import {
  CanActivate,
  ExecutionContext,
  Injectable,
  UnauthorizedException,
  Logger,
} from "@nestjs/common";
import { JwtService } from "@nestjs/jwt";
import { PrismaService } from "../../infra/prisma/prisma.service";

@Injectable()
export class JwtAuthGuard implements CanActivate {
  private readonly logger = new Logger("JwtAuthGuard");

  constructor(
    private readonly jwtService: JwtService,
    private readonly prisma: PrismaService,
  ) {}

  async canActivate(context: ExecutionContext) {
    const request = context.switchToHttp().getRequest<{
      tenantId?: string;
      ip: string;
      url: string;
      method: string;
      headers: Record<string, string>;
    }>();

    const tenantHeader = request.headers["x-tenant-id"];
    const authHeader = request.headers["authorization"];

    // ─── Mock JWT (Development fallback) ────────────────────────────────────
    if (authHeader && authHeader.startsWith("Bearer mock-jwt-")) {
      if (tenantHeader && tenantHeader !== "default") {
        request.tenantId = tenantHeader;
        return true;
      }
      try {
        const company = await this.prisma.company.findFirst({ select: { id: true } });
        request.tenantId = company?.id ?? tenantHeader ?? "default";
      } catch {
        request.tenantId = tenantHeader ?? "default";
      }
      return true;
    }

    // ─── No auth header but x-tenant-id present (dev mode only) ─────────────
    if (!authHeader || !authHeader.startsWith("Bearer ")) {
      if (tenantHeader && process.env.NODE_ENV !== "production") {
        if (tenantHeader !== "default") {
          request.tenantId = tenantHeader;
        } else {
          try {
            const company = await this.prisma.company.findFirst({ select: { id: true } });
            request.tenantId = company?.id ?? "default";
          } catch {
            request.tenantId = "default";
          }
        }
        return true;
      }
      throw new UnauthorizedException("Token de acesso não fornecido.");
    }

    const token = authHeader.split(" ")[1];

    // ─── Verify JWT signature ────────────────────────────────────────────────
    let payload: { sub: string; companyId: string; role: string } & Record<string, unknown>;
    try {
      payload = await this.jwtService.verifyAsync(token);
    } catch {
      const ip = request.headers["x-forwarded-for"]?.split(",")[0]?.trim() || request.ip;
      this.logger.warn(
        `[INVALID_TOKEN] ${request.method} ${request.url} | IP: ${ip}`,
      );
      throw new UnauthorizedException("Token de acesso inválido ou expirado.");
    }

    // ─── Validate companyId exists and is active ─────────────────────────────
    if (!payload.companyId) {
      throw new UnauthorizedException("Token inválido: empresa não identificada.");
    }

    request.tenantId = payload.companyId;
    return true;
  }
}
