import {
  CanActivate,
  ExecutionContext,
  Injectable,
  UnauthorizedException,
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Request } from 'express';
import { PayloadAcesso, SessionService } from './session.service';

/** Request com a conta já resolvida, para os controllers não usarem `any`. */
export interface RequestAutenticado extends Request {
  conta: { id: string; sessionId: string };
}

@Injectable()
export class JwtAuthGuard implements CanActivate {
  constructor(
    private readonly jwt: JwtService,
    private readonly sessions: SessionService,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const req = context.switchToHttp().getRequest<RequestAutenticado>();
    const header = req.headers.authorization;

    if (!header?.startsWith('Bearer ')) {
      throw new UnauthorizedException('token ausente');
    }

    let payload: PayloadAcesso;
    try {
      payload = await this.jwt.verifyAsync<PayloadAcesso>(header.slice(7));
    } catch {
      throw new UnauthorizedException('token inválido ou expirado');
    }

    // Access token válido não basta: a sessão pode ter sido revogada no logout.
    // Sem esta checagem o logout de AC-3 não teria efeito nos 15 min seguintes.
    if (!(await this.sessions.sessaoAtiva(payload.sid))) {
      throw new UnauthorizedException('sessão encerrada');
    }

    req.conta = { id: payload.sub, sessionId: payload.sid };
    return true;
  }
}
