import {
  type CanActivate,
  type ExecutionContext,
  ForbiddenException,
  Injectable,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { QueryBus } from '@nestjs/cqrs';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { type QuotaCheckResult } from '../../application/queries/check-quota/check-quota.handler';
import { CheckQuotaQuery } from '../../application/queries/check-quota/check-quota.query';
import { QuotaExceededEvent } from '../../domain/events/quota-exceeded.event';
import { QUOTA_METRIC_KEY } from '../decorators/require-quota.decorator';

@Injectable()
export class QuotaGuard implements CanActivate {
  constructor(
    private readonly reflector: Reflector,
    private readonly queryBus: QueryBus,
    private readonly eventEmitter: EventEmitter2,
  ) {}

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

    if (!metric) {
      return true;
    }

    const request = context.switchToHttp().getRequest();
    const user = request.user;

    if (!user?.sub) {
      return true; // Let auth guards handle unauthenticated requests
    }

    const result: QuotaCheckResult = await this.queryBus.execute(
      new CheckQuotaQuery(user.sub, metric),
    );

    if (!result.allowed) {
      const event = new QuotaExceededEvent(
        user.sub,
        result.metric,
        result.limit!,
        result.used,
      );
      this.eventEmitter.emit(event.eventName, event);

      throw new ForbiddenException({
        code: 'QUOTA_EXCEEDED',
        message: `Bạn đã đạt giới hạn ${metric}. Vui lòng nâng cấp gói để tiếp tục.`,
        quota: {
          metric: result.metric,
          limit: result.limit,
          used: result.used,
        },
      });
    }

    return true;
  }
}
