import { CanActivate, ExecutionContext, Injectable, UnauthorizedException, Inject, Logger } from '@nestjs/common';
import { Request } from 'express';
import { JwtService } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';
import { ITokenPayload } from '../interfaces/IToken-payload';

export interface UserAuthRequest extends Request {
  userId: string;
  restId: string;
}

@Injectable()
export class AuthGuard implements CanActivate {
  private readonly logger = new Logger(AuthGuard.name);

  constructor(
    @Inject(JwtService)
    private readonly jwtService: JwtService,
    @Inject(ConfigService)
    private readonly configService: ConfigService,
  ) {}

  async canActivate(context: ExecutionContext) {
    const request = context.switchToHttp().getRequest<UserAuthRequest>();

    try {
      const secret = this.configService.getOrThrow<string>('JWT_SECRET');
      const token = this.extractTokenFromHeader(request);
      const slug = this.extractSlugFromHeader(request);
      if (!slug) {
        throw new UnauthorizedException('Slug is required');
      }
      if (!token) {
        throw new UnauthorizedException();
      }

      try {
        const payload = await this.jwtService.verifyAsync<ITokenPayload>(token, {
          secret,
        });
        if (!payload.userId || !payload.restId) {
          this.logger.error('Invalid token payload structure', payload);
          throw new UnauthorizedException('Invalid token payload');
        }
        if (payload.slug !== slug) {
          throw new UnauthorizedException('Invalid slug');
        }
        request['userId'] = payload.userId;
        request['restId'] = payload.restId;
      } catch {
        throw new UnauthorizedException();
      }

      return true;
    } catch (err) {
      if (err instanceof UnauthorizedException) {
        throw err;
      }
      this.logger.error('error in AuthGuard', err);
      throw new UnauthorizedException('Invalid or expired token');
    }
  }
  private extractTokenFromHeader(request: Request): string | undefined {
    const [type, token] = request.headers.authorization?.split(' ') ?? [];
    return type === 'Bearer' ? token : undefined;
  }
  private extractSlugFromHeader(request: Request): string | undefined {
    // Fastify normalizes headers to lowercase, so check both cases
    const slug = (request.headers['x-slug'] || request.headers['X-Slug']) as string;
    return slug;
  }
}
