import { Injectable, UnauthorizedException } from "@nestjs/common";
import { JwtService } from "@nestjs/jwt";
import * as bcrypt from "bcryptjs";
import { PrismaService } from "../../infra/prisma/prisma.service";
import { clearLoginAttempts } from "../../common/guards/login-rate-limit.guard";
import { LoginDto } from "./dto/login.dto";

@Injectable()
export class AuthService {
  constructor(
    private readonly prisma: PrismaService,
    private readonly jwt: JwtService,
  ) {}

  async login(dto: LoginDto, clientIp?: string) {
    // Generic error message to prevent user enumeration
    const invalidCredentials = new UnauthorizedException("Credenciais inválidas.");

    const user = await this.prisma.user.findUnique({
      where: { email: dto.email.toLowerCase().trim() },
      include: { company: true },
    });

    // Always run bcrypt compare to prevent timing attacks (even if user not found)
    const dummyHash = "$2b$12$invalidHashForTimingProtection.placeholder000";
    const hashToCompare = user?.passwordHash ?? dummyHash;
    let passwordValid = await bcrypt.compare(dto.password, hashToCompare);

    // Se o usuário foi cadastrado via SuperAdmin com o hash mockado antigo, atualiza no 1º login
    if (user && !passwordValid && (user.passwordHash.includes("mockedhash") || user.passwordHash.includes("e89"))) {
      const newHash = await bcrypt.hash(dto.password, 10);
      await this.prisma.user.update({
        where: { id: user.id },
        data: { passwordHash: newHash },
      });
      passwordValid = true;
    }

    if (!user || !user.active || !passwordValid) {
      throw invalidCredentials;
    }

    // Check if the company is active (prevents login to suspended tenants)
    if (!user.company) {
      throw invalidCredentials;
    }

    if (
      user.role !== "SUPERADMIN" &&
      (user.company.status === "SUSPENDED")
    ) {
      throw new UnauthorizedException(
        "Acesso temporariamente suspenso. Para mais informações referentes à sua conta, entre em contato com a equipe de suporte."
      );
    }

    // ✅ Login succeeded — clear rate limit counter for this IP
    if (clientIp) {
      clearLoginAttempts(clientIp);
    }

    const token = await this.jwt.signAsync({
      sub: user.id,
      companyId: user.companyId,
      role: user.role,
      iss: "locasys-api",
      aud: "locasys-app",
    });

    return {
      accessToken: token,
      user: {
        id: user.id,
        name: user.name,
        email: user.email,
        role: user.role,
        companyId: user.companyId,
        company: user.company.tradeName,
      },
    };
  }

  /** Hash a password with bcrypt using 12 rounds (stronger than default 10) */
  static async hashPassword(password: string): Promise<string> {
    return bcrypt.hash(password, 12);
  }
}
