import { Injectable, CanActivate, ExecutionContext, ForbiddenException, HttpStatus, Logger } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { PERMISSIONS_KEY } from '../../../../common/decorators/permissions.decorator';
import { BusinessException } from '@common/exceptions/business.exception';
import { IamAuditService } from '@common/services/iam-audit.service';
import { EmergencyBypassService } from '@common/services/emergency-bypass.service';
import { isAdministrator } from '@common/utils/role-check.util';

@Injectable()
export class PermissionsGuard implements CanActivate {
  private readonly logger = new Logger(PermissionsGuard.name);

  constructor(
    private reflector: Reflector,
    private iamAudit: IamAuditService,
    private emergencyBypass: EmergencyBypassService,
  ) {}

  /** 异步审计：失败仅记录日志，不阻塞主请求 */
  private auditFireAndForget(payload: Parameters<IamAuditService['record']>[0]) {
    this.iamAudit.record(payload).catch((err: unknown) => {
      const msg = err instanceof Error ? err.message : String(err);
      this.logger.warn(`审计写入失败: ${msg}`);
    });
  }

  /** Administrator 跳过权限校验时的审计，同样 fire-and-forget */
  private adminBypassFireAndForget(
    actor: string,
    endpoint: string,
    requiredPermissions: string[],
  ) {
    this.iamAudit
      .recordAdminBypass(actor, endpoint, requiredPermissions)
      .catch((err: unknown) => {
        const msg = err instanceof Error ? err.message : String(err);
        this.logger.warn(`Admin bypass 审计失败: ${msg}`);
      });
  }

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

    if (!requiredPermissions || requiredPermissions.length === 0) {
      return true;
    }

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

    if (!user) {
      return false;
    }

    // 紧急豁免：Redis 白名单命中 → 放行 + 强制审计（规则 §5.6 P2）
    const endpoint = `${request.method} ${request.url}`;
    const bypassInfo = await this.emergencyBypass.getBypassInfo(endpoint);
    if (bypassInfo) {
      this.auditFireAndForget({
        actor: user.userId,
        action: 'ADMIN_BYPASS',
        resource: 'EmergencyBypass',
        after: { endpoint, reason: bypassInfo.reason, expiresAt: bypassInfo.expiresAt },
      });
      return true;
    }

    if (isAdministrator(user)) {
      // 规则 §4.5 + §8 禁止事项 #13：Administrator 权限跳过必记审计
      this.adminBypassFireAndForget(user.userId, endpoint, requiredPermissions);
      return true;
    }

    const userPermissions: string[] = user.permissions || [];

    const hasRequiredPermissions = requiredPermissions.every((required) =>
      this.hasPermission(userPermissions, required),
    );

    if (!hasRequiredPermissions) {
      const performanceError = this.resolvePerformancePermissionError(
        requiredPermissions,
        request,
      );
      if (performanceError) {
        throw new BusinessException(
          performanceError.message,
          performanceError.code,
          HttpStatus.FORBIDDEN,
        );
      }
      // 结构化 403（规则 §8 禁止事项配套 / ForbiddenException 带结构化字段）
      const missing = requiredPermissions.filter(
        (req) => !this.hasPermission(userPermissions, req),
      );
      throw new ForbiddenException({
        message: `Missing required permissions: ${missing.join(', ')}`,
        code: 'PERMISSION_DENIED',
        userId: user.userId,
        endpoint: `${request.method} ${request.url}`,
        requiredPermissions,
        missingPermissions: missing,
      });
    }

    return true;
  }

  private hasPermission(userPermissions: string[], required: string): boolean {
    if (userPermissions.includes(required)) {
      return true;
    }

    const [resource, action] = required.split(':');

    if (userPermissions.includes(`${resource}:*`)) {
      return true;
    }

    const wildcardPermission = `${resource}:*:${action}`;
    if (userPermissions.includes(wildcardPermission)) {
      return true;
    }

    if (userPermissions.includes('*:*')) {
      return true;
    }

    return false;
  }

  private resolvePerformancePermissionError(
    requiredPermissions: string[] | undefined,
    request: any,
  ): { code: string; message: string } | null {
    if (!request?.url?.startsWith('/api/v1/performance')) {
      return null;
    }

    const permission = (requiredPermissions || []).find(Boolean) || '';
    const code = this.mapPerformancePermissionCode(permission);
    return { code, message: this.mapPerformancePermissionMessage(code) };
  }

  private static readonly PERF_EXACT_MAP: Map<string, string> = new Map([
    ['performance:360:create', 'PERF_E360_012'],
    ['performance:360:view:results', 'PERF_E360_011'],
    ['performance:feedback:delete', 'PERF_FEEDBACK_002'],
    ['performance:result:view:all', 'PERF_REPORT_002'],
    ['performance:kpi:manage', 'PERF_KPI_011'],
    ['performance:kpi:manager-evaluate', 'PERF_KPI_010'],
  ]);

  private static readonly PERF_PREFIX_MAP: ReadonlyArray<[string, string]> = [
    ['performance:calibration', 'PERF_CAL_005'],
    ['performance:interview', 'PERF_INTERVIEW_004'],
    ['performance:cycle', 'PERF_CYCLE_008'],
  ];

  private mapPerformancePermissionCode(permission: string): string {
    const exact = PermissionsGuard.PERF_EXACT_MAP.get(permission);
    if (exact) return exact;
    for (const [prefix, code] of PermissionsGuard.PERF_PREFIX_MAP) {
      if (permission.startsWith(prefix)) return code;
    }
    return 'PERF_COMMON_002';
  }

  private mapPerformancePermissionMessage(code: string): string {
    switch (code) {
      case 'PERF_E360_011': return '无权查看该评估';
      case 'PERF_E360_012': return '无权发起 360 评估';
      case 'PERF_CAL_005': return '无权校准';
      case 'PERF_INTERVIEW_004': return '无权管理面谈';
      case 'PERF_FEEDBACK_002': return '无权删除反馈';
      case 'PERF_REPORT_002': return '无权查看报表';
      case 'PERF_CYCLE_008': return '无权限管理周期';
      case 'PERF_KPI_010': return '只能评估直属下属';
      case 'PERF_KPI_011': return '无权管理 KPI 指标库';
      default: return '无权限访问资源';
    }
  }
}
