import { Injectable, CanActivate, ExecutionContext, UnauthorizedException, ForbiddenException } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';
import { IS_PUBLIC_KEY, PERMISSIONS_KEY } from '../../shared/common/decorators';

@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
  constructor(private reflector: Reflector) {
    super();
  }

  canActivate(context: ExecutionContext) {
    const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);
    if (isPublic) return true;
    return super.canActivate(context);
  }

  handleRequest<TUser = unknown>(err: Error | null, user: TUser): TUser {
    if (err || !user) throw err || new UnauthorizedException();
    return user;
  }
}

@Injectable()
export class PermissionsGuard implements CanActivate {
  constructor(private reflector: Reflector) {}

  canActivate(context: ExecutionContext): boolean {
    const required = this.reflector.getAllAndOverride<string[]>(PERMISSIONS_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);

    const { user } = context.switchToHttp().getRequest();
    if (!user || user.userType !== 'ADMIN') {
      throw new ForbiddenException('Admin access required');
    }
    if (user.role === 'SUPER_ADMIN') return true;

    if (!required?.length) {
      throw new ForbiddenException('Insufficient permissions');
    }

    const userPerms: string[] = user.permissions ?? [];
    const hasAccess = required.some((p) => userPerms.includes(p));
    if (!hasAccess) throw new ForbiddenException('Insufficient permissions');
    return true;
  }
}

export function UserTypeGuard(...types: string[]) {
  @Injectable()
  class MixedUserTypeGuard implements CanActivate {
    canActivate(context: ExecutionContext): boolean {
      const { user } = context.switchToHttp().getRequest();
      if (!types.includes(user?.userType)) {
        throw new ForbiddenException('Access denied for this portal');
      }
      return true;
    }
  }
  return MixedUserTypeGuard;
}

@Injectable()
export class PlayerGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    const { user } = context.switchToHttp().getRequest();
    if (user?.userType !== 'PLAYER') throw new ForbiddenException('Player access only');
    return true;
  }
}

@Injectable()
export class AdminGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    const { user } = context.switchToHttp().getRequest();
    if (user?.userType !== 'ADMIN') throw new ForbiddenException('Admin access only');
    return true;
  }
}

@Injectable()
export class AgentGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    const { user } = context.switchToHttp().getRequest();
    if (user?.userType !== 'AGENT') throw new ForbiddenException('Agent access only');
    return true;
  }
}
