import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import type { Request } from 'express';
import { envs } from 'src/config/envs';
import { SesionService } from './sesion.service';
import { Sesion } from './sesion.types';

const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;

export type RequestConSesion = Request & { sesion?: Sesion };

/**
 * Verifica el access token del ERP con el mismo JWT_SECRET (HS256) y relee la
 * sesión en la base. Los refresh tokens usan otro secreto y no pasan.
 */
@Injectable()
export class ErpJwtGuard implements CanActivate {
  constructor(
    private readonly jwt: JwtService,
    private readonly sesiones: SesionService,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const req = context.switchToHttp().getRequest<RequestConSesion>();
    const [tipo, token] = (req.headers.authorization ?? '').split(' ');
    if (tipo !== 'Bearer' || !token) throw new UnauthorizedException('Falta el token');

    let sub: unknown;
    try {
      const payload = await this.jwt.verifyAsync<{ sub?: unknown }>(token, {
        secret: envs.jwtSecret,
        algorithms: ['HS256'],
      });
      sub = payload.sub;
    } catch {
      throw new UnauthorizedException('Token inválido');
    }
    if (typeof sub !== 'string' || !UUID.test(sub)) throw new UnauthorizedException('Token inválido');

    const sesion = await this.sesiones.resolver(sub);
    if (!sesion) throw new UnauthorizedException('Token inválido');

    req.sesion = sesion;
    return true;
  }
}
