import { Injectable, Inject, UnauthorizedException, BadRequestException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { VerificationCodeEntity } from '../../domain/entities/verification-code.entity';
import {
  IVerificationCodeRepository,
  VERIFICATION_CODE_REPOSITORY,
} from '../../domain/repositories/verification-code.repository.interface';
import { UserService } from './user.service';

@Injectable()
export class AuthService {
  constructor(
    @Inject(VERIFICATION_CODE_REPOSITORY)
    private readonly verificationCodeRepo: IVerificationCodeRepository,
    private readonly userService: UserService,
    private readonly jwtService: JwtService,
  ) {}

  async createAnonymousSession(fingerprint: string) {
    if (!fingerprint) {
      throw new BadRequestException('Fingerprint is required');
    }

    const user = await this.userService.createAnonymousUser(fingerprint);

    const token = this.jwtService.sign({
      sub: user.id,
      type: user.type,
    });

    return {
      userId: user.id,
      token,
      expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
    };
  }

  async sendVerificationCode(phone: string) {
    if (!this.isValidPhone(phone)) {
      throw new BadRequestException('Invalid phone number');
    }

    const recentCodes = await this.verificationCodeRepo.countRecentByPhone(phone, 1);

    if (recentCodes >= 5) {
      throw new BadRequestException('Too many verification codes requested');
    }

    const verificationCode = VerificationCodeEntity.create(phone);
    await this.verificationCodeRepo.save(verificationCode);

    console.log(`[DEV] Verification code for ${phone}: ${verificationCode.code}`);

    return {
      sent: true,
      expiresIn: 300,
    };
  }

  async verifyAndLogin(phone: string, code: string, userId?: string) {
    const verificationCode = await this.verificationCodeRepo.findValidCode(phone, code);

    if (!verificationCode) {
      throw new UnauthorizedException('Invalid or expired verification code');
    }

    await this.verificationCodeRepo.markAsUsed(verificationCode.id);

    let user;
    if (userId) {
      user = await this.userService.upgradeToRegistered(userId, phone);
    } else {
      user = await this.userService.findByPhone(phone);
      if (!user) {
        throw new BadRequestException('User not found. Please provide userId to upgrade.');
      }
    }

    const token = this.jwtService.sign({
      sub: user.id,
      type: user.type,
    });

    return {
      userId: user.id,
      token,
      user: {
        id: user.id,
        type: user.type,
        phone: user.phone,
        nickname: user.nickname,
      },
    };
  }

  async refreshToken(oldToken: string) {
    try {
      const payload = this.jwtService.verify(oldToken, {
        ignoreExpiration: true,
      });

      const user = await this.userService.findById(payload.sub);

      const newToken = this.jwtService.sign({
        sub: user.id,
        type: user.type,
      });

      return {
        token: newToken,
        expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
      };
    } catch (error) {
      throw new UnauthorizedException('Invalid token');
    }
  }

  private isValidPhone(phone: string): boolean {
    const cleanPhone = phone.replace(/[\s-]/g, '');
    return /^1[3-9]\d{9}$/.test(cleanPhone) || /^[2-9]\d{7}$/.test(cleanPhone);
  }
}
