import {
  Injectable,
  CanActivate,
  ExecutionContext,
  ForbiddenException,
  Logger,
  OnModuleInit,
  OnModuleDestroy,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { ConfigService } from '@nestjs/config';
import { CAPABILITY_KEY } from '../decorators/require-capability.decorator';
import Redis from 'ioredis';

const CAPABILITY_LABELS: Record<string, string> = {
  LOGIN: '登录',
  TRADING: '交易',
  C2C: 'C2C交易',
  TRANSFER_IN: '划入',
  TRANSFER_OUT: '划出',
  P2P_SEND: 'P2P转出',
  P2P_RECEIVE: 'P2P收款',
  MINING_CLAIM: '挖矿领取',
  KYC: '实名认证',
  PROFILE_EDIT: '编辑资料',
  VIEW_ASSET: '查看资产',
  VIEW_TEAM: '查看团队',
  VIEW_RECORDS: '查看记录',
};

/**
 * CapabilityGuard - 从 Redis DB 14 (auth-service) 读取用户能力并校验
 * 必须在 JwtAuthGuard 之后注册，依赖 request.user.accountSequence
 */
@Injectable()
export class CapabilityGuard implements CanActivate, OnModuleInit, OnModuleDestroy {
  private readonly logger = new Logger(CapabilityGuard.name);
  private capRedis: Redis | null = null;

  constructor(
    private readonly reflector: Reflector,
    private readonly configService: ConfigService,
  ) {}

  onModuleInit() {
    this.capRedis = new Redis({
      host: this.configService.get<string>('REDIS_HOST', 'localhost'),
      port: this.configService.get<number>('REDIS_PORT', 6379),
      password: this.configService.get<string>('REDIS_PASSWORD'),
      db: 14, // auth-service 的 Redis DB
      lazyConnect: true,
      maxRetriesPerRequest: 1,
      retryStrategy: (times) => Math.min(times * 100, 3000),
    });
    this.capRedis.connect().catch((err) => {
      this.logger.warn('Capability Redis 连接失败 (fail-open)', err.message);
    });
  }

  async onModuleDestroy() {
    await this.capRedis?.quit();
  }

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

    // 无能力要求 → 放行
    if (!requiredCapability) return true;

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

    // 未认证（公开端点或认证前） → 放行
    if (!accountSequence) return true;

    try {
      const raw = await this.capRedis?.get(`cap:${accountSequence}`);

      // 无缓存 = 默认全部开启 (fail-open)
      if (!raw) return true;

      const capabilities = JSON.parse(raw);
      const isEnabled = capabilities[requiredCapability];

      // 能力键不存在 = 默认开启
      if (isEnabled === undefined) return true;

      if (!isEnabled) {
        const label = CAPABILITY_LABELS[requiredCapability] || requiredCapability;
        throw new ForbiddenException({
          code: 'CAPABILITY_DISABLED',
          capability: requiredCapability,
          message: `您的${label}功能已被限制`,
        });
      }

      return true;
    } catch (error) {
      if (error instanceof ForbiddenException) throw error;
      // Redis 错误 → fail-open
      this.logger.warn(`能力检查失败 (fail-open): ${accountSequence}`, error?.message);
      return true;
    }
  }
}
