import {
  CanActivate,
  ExecutionContext,
  Injectable,
  UnauthorizedException,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import type { FastifyRequest } from 'fastify';

import {
  IS_PUBLIC_KEY,
  type RequestWithSession,
} from '../decorators/current-user.decorator';
import { SessionService } from '../session.service';

@Injectable()
export class SessionGuard implements CanActivate {
  constructor(
    private readonly sessionService: SessionService,
    private readonly reflector: Reflector,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);

    if (isPublic) {
      return true;
    }

    const request = context.switchToHttp().getRequest<RequestWithSession>();
    const token = this.sessionService.readSessionToken(
      request as FastifyRequest,
    );

    if (!token) {
      throw new UnauthorizedException('Authentication required');
    }

    const session = await this.sessionService.validateSessionToken(token);
    request.session = session;
    request.user = session.user;

    return true;
  }
}
