import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Inject, Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import axios from 'axios';
import type { Cache } from 'cache-manager';
import type { Request } from 'express';
import { passportJwtSecret } from 'jwks-rsa';
import { ExtractJwt, type StrategyOptionsWithRequest } from 'passport-jwt';
import type { IAuthenticationStrategy } from '../../../domain/ports';

@Injectable()
export class AuroraHubConsumerAdapter implements IAuthenticationStrategy {
  private readonly hubApiUrl: string;

  constructor(
    configService: ConfigService,
    @Inject(CACHE_MANAGER) private readonly cacheManager: Cache,
  ) {
    this.hubApiUrl = configService.get<string>('OAUTH_HUB_SERVER_URL', 'http://localhost:8080');
  }

  getPassportOptions(): StrategyOptionsWithRequest {
    return {
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      passReqToCallback: true,
      secretOrKeyProvider: passportJwtSecret({
        jwksUri: `${this.hubApiUrl}/.well-known/jwks.json`,
        cache: true,
        cacheMaxAge: 600_000, // 10 min
        rateLimit: true,
        jwksRequestsPerMinute: 5,
      }),
      algorithms: ['RS256'],
      issuer: 'Aurora OAuth',
    };
  }

  async validate(req: Request, payload: Record<string, unknown>): Promise<object> {
    const accountId = payload.aci as string;
    const cacheKey = `jwt-account:${accountId}`;

    const cached = await this.cacheManager.get<object>(cacheKey);
    if (cached) return cached;

    const authorization = req.headers.authorization;
    const response = await axios.post(
      `${this.hubApiUrl}/graphql`,
      {
        query: `query iamMeAccount {
          iamMeAccount {
            id
            clientId
            email
            username
            isActive
            scopes
            dApplicationCodes
            dPermissions
            dTenants
            meta
            roles {
              id
              name
              defaultRedirection
              hasHiddenVerticalNavigation
            }
            tenants {
              id
              name
            }
            user {
              id
              name
              surname
              langId
              meta
            }
            createdAt
            updatedAt
            deletedAt
          }
        }`,
      },
      {
        headers: {
          'Content-Type': 'application/json',
          Authorization: authorization,
        },
      },
    );

    if (response.data.errors) {
      throw new Error(response.data.errors[0]?.message || 'Failed to fetch user data.');
    }

    const account = response.data.data.iamMeAccount;

    await this.cacheManager.set(cacheKey, account, 300_000);

    return account;
  }
}
