import { Injectable, CanActivate, ExecutionContext, UnauthorizedException, BadRequestException } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { UserService } from '../user/user.service';
import { Request } from 'express';
import { IS_PUBLIC_KEY } from './public.decorator';

@Injectable()
export class ApiKeyGuard implements CanActivate {
    constructor(
        private reflector: Reflector,
        private userService: UserService,
    ) { }

    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<Request & { user?: any, tenantId?: string }>();
        const apiKey = this.extractApiKeyFromHeader(request);

        if (apiKey) {
            const user = await this.userService.findByApiKey(apiKey);
            if (user) {
                // Get tenantId from header or query parameter
                const requestedTenantId = request.headers['x-tenant-id'] as string || 
                                         request.query.tenantId as string;
                
                // If tenantId is provided, verify user belongs to that tenant
                if (requestedTenantId) {
                    // Check if user belongs to the requested tenant
                    const userTenants = await this.userService.getUserTenants(user.id);
                    const belongsToTenant = userTenants.some(t => t.id === requestedTenantId);
                    
                    if (!belongsToTenant) {
                        throw new BadRequestException(`User does not belong to tenant "${requestedTenantId}"`);
                    }
                    
                    request.user = { ...user, tenantId: requestedTenantId };
                    request.tenantId = requestedTenantId;
                } else {
                    // Use user's default tenantId
                    request.user = user;
                    request.tenantId = user.tenantId;
                }
                
                return true;
            }
            throw new UnauthorizedException('Invalid API key');
        }

        throw new UnauthorizedException('Missing API key');
    }

    private extractApiKeyFromHeader(request: Request): string | undefined {
        const authHeader = request.headers.authorization;
        if (authHeader && authHeader.startsWith('Bearer kb_')) {
            return authHeader.substring(7, authHeader.length);
        }
        const headerKey = request.headers['x-api-key'] as string;
        if (headerKey) return headerKey;

        return undefined;
    }
}
