import {
  Controller,
  Get,
  Post,
  Query,
  Param,
  Body,
  Res,
  NotFoundException,
  BadRequestException,
  ParseUUIDPipe,
} from '@nestjs/common';
import type { Response } from 'express';
import { AuditService } from './audit.service';
import { ComplianceReportService } from './services/compliance-report.service';
import { AuditAlertService } from './services/alert.service';
import {
  QueryAuditLogDto,
  EntityAuditQueryDto,
  UserAuditQueryDto,
  FinancialAuditQueryDto,
  SensitiveAuditQueryDto,
  AuditStatisticsDto,
  VerifyIntegrityDto,
  IntegrityCheckDto,
  AuditExportDto,
  DetectFailuresDto,
  DetectAnomalyDto,
  BatchCheckAlertsDto,
  DateRangeReportDto,
} from './dto/query-audit-log.dto';
import { RequirePermissions } from '@common/decorators/permissions.decorator';
import { CurrentUser } from '@common/decorators/current-user.decorator';

/**
 * 审计系统控制器
 * 基础路径: /api/v1/audit
 *
 * 提供 12 个 API 端点:
 * - GET /logs - 查询审计日志
 * - GET /logs/:id - 获取审计日志详情
 * - GET /entity/:type/:id - 获取实体审计历史
 * - GET /user/:userId - 获取用户操作历史
 * - GET /financial - 获取财务操作日志
 * - GET /sensitive - 获取敏感操作日志
 * - GET /trace/:traceId - 按追踪 ID 获取请求链路
 * - POST /statistics - 获取统计分析
 * - POST /verify-integrity - 即时验证完整性
 * - POST /integrity-check - 触发后台完整性检查任务
 * - GET /integrity-check/:jobId - 查询检查任务状态
 * - POST /export - 导出审计日志
 */
@Controller('audit')
export class AuditController {
  constructor(
    private readonly auditService: AuditService,
    private readonly complianceReportService: ComplianceReportService,
    private readonly alertService: AuditAlertService,
  ) {}

  /**
   * 查询审计日志
   * GET /api/v1/audit/logs
   */
  @Get('logs')
  @RequirePermissions('audit:read')
  async queryLogs(@Query() query: QueryAuditLogDto, @CurrentUser() user: any) {
    const filters: any = {
      region: user.region || 'cn',
      tenantId: user.tenantId || 'default',
      ...query,
    };

    if (query.startDate) {
      filters.startDate = new Date(query.startDate);
    }
    if (query.endDate) {
      filters.endDate = new Date(query.endDate);
    }

    return this.auditService.query(filters);
  }

  /**
   * 获取审计日志详情
   * GET /api/v1/audit/logs/:id
   */
  @Get('logs/:id')
  @RequirePermissions('audit:read')
  async getLogDetail(@Param('id') id: string, @CurrentUser() user: any) {
    const region = user.region || 'cn';
    const tenantId = user.tenantId || 'default';

    const log = await this.auditService.getById(id, region, tenantId);

    if (!log) {
      throw new NotFoundException({
        code: 'AUDIT_LOG_NOT_FOUND',
        message: '审计日志不存在',
        details: `审计日志 ID '${id}' 不存在`,
      });
    }

    return log;
  }

  /**
   * 单条审计日志完整性校验
   * GET /api/v1/audit/logs/:id/verify
   */
  @Get('logs/:id/verify')
  @RequirePermissions('audit:verify')
  async verifySingleLog(@Param('id') id: string, @CurrentUser() user: any) {
    const region = user.region || 'cn';
    const tenantId = user.tenantId || 'default';

    const result = await this.auditService.verifySingleLog(id, region, tenantId);

    if (!result) {
      throw new NotFoundException({
        code: 'AUDIT_LOG_NOT_FOUND',
        message: '审计日志不存在',
        details: `审计日志 ID '${id}' 不存在`,
      });
    }

    return result;
  }

  /**
   * 获取实体的审计历史
   * GET /api/v1/audit/entity/:type/:id
   */
  @Get('entity/:type/:id')
  @RequirePermissions('audit:read')
  async getEntityHistory(
    @Param('type') entityType: string,
    @Param('id', ParseUUIDPipe) entityId: string,
    @Query() query: EntityAuditQueryDto,
    @CurrentUser() user: any,
  ) {
    const region = user.region || 'cn';
    const tenantId = user.tenantId || 'default';

    return this.auditService.getEntityHistory(
      entityType,
      entityId,
      region,
      tenantId,
      {
        page: query.page,
        limit: query.limit,
        includeDiff: query.includeDiff,
      },
    );
  }

  /**
   * 获取用户的操作历史
   * GET /api/v1/audit/user/:userId
   */
  @Get('user/:userId')
  @RequirePermissions('audit:read')
  async getUserHistory(
    @Param('userId', ParseUUIDPipe) userId: string,
    @Query() query: UserAuditQueryDto,
    @CurrentUser() user: any,
  ) {
    const region = user.region || 'cn';
    const tenantId = user.tenantId || 'default';

    return this.auditService.getUserHistory(userId, region, tenantId, {
      startDate: query.startDate ? new Date(query.startDate) : undefined,
      endDate: query.endDate ? new Date(query.endDate) : undefined,
      module: query.module,
      action: query.action,
      isSensitive: query.isSensitive,
      isFinancial: query.isFinancial,
      riskLevel: query.riskLevel,
      page: query.page,
      limit: query.limit,
    });
  }

  /**
   * 获取财务相关操作日志
   * GET /api/v1/audit/financial
   */
  @Get('financial')
  @RequirePermissions('audit:read:financial')
  async getFinancialLogs(
    @Query() query: FinancialAuditQueryDto,
    @CurrentUser() user: any,
  ) {
    const region = user.region || 'cn';
    const tenantId = user.tenantId || 'default';

    return this.auditService.getFinancialLogs(region, tenantId, {
      startDate: new Date(query.startDate),
      endDate: new Date(query.endDate),
      userId: query.userId,
      action: query.action,
      module: query.module,
      sortBy: query.sortBy,
      sortOrder: query.sortOrder,
      page: query.page,
      limit: query.limit,
    });
  }

  /**
   * 获取敏感操作日志
   * GET /api/v1/audit/sensitive
   */
  @Get('sensitive')
  @RequirePermissions('audit:read:sensitive')
  async getSensitiveLogs(
    @Query() query: SensitiveAuditQueryDto,
    @CurrentUser() user: any,
  ) {
    const region = user.region || 'cn';
    const tenantId = user.tenantId || 'default';

    return this.auditService.getSensitiveLogs(region, tenantId, {
      startDate: query.startDate ? new Date(query.startDate) : undefined,
      endDate: query.endDate ? new Date(query.endDate) : undefined,
      userId: query.userId,
      action: query.action,
      riskLevel: query.riskLevel,
      page: query.page,
      limit: query.limit,
    });
  }

  /**
   * 按追踪ID获取完整请求链路
   * GET /api/v1/audit/trace/:traceId
   */
  @Get('trace/:traceId')
  @RequirePermissions('audit:trace')
  async getByTraceId(
    @Param('traceId', ParseUUIDPipe) traceId: string,
    @CurrentUser() user: any,
  ) {
    const region = user.region || 'cn';
    const tenantId = user.tenantId || 'default';

    return this.auditService.getByTraceId(traceId, region, tenantId);
  }

  /**
   * 获取统计分析
   * POST /api/v1/audit/statistics
   */
  @Post('statistics')
  @RequirePermissions('audit:statistics')
  async getStatistics(
    @Body() dto: AuditStatisticsDto,
    @CurrentUser() user: any,
  ) {
    const region = user.region || 'cn';
    const tenantId = user.tenantId || 'default';

    return this.auditService.getStatistics(
      region,
      tenantId,
      new Date(dto.startDate),
      new Date(dto.endDate),
      {
        module: dto.module,
        userId: dto.userId,
      },
    );
  }

  /**
   * 即时验证完整性（同步）
   * POST /api/v1/audit/verify-integrity
   */
  @Post('verify-integrity')
  @RequirePermissions('audit:verify')
  async verifyIntegrity(
    @Body() dto: VerifyIntegrityDto,
    @CurrentUser() user: any,
  ) {
    const region = user.region || 'cn';
    const tenantId = user.tenantId || 'default';

    return this.auditService.verifyIntegrity(
      region,
      tenantId,
      dto.startDate ? new Date(dto.startDate) : undefined,
      dto.endDate ? new Date(dto.endDate) : undefined,
    );
  }

  /**
   * 触发后台完整性检查任务（异步）
   * POST /api/v1/audit/integrity-check
   */
  @Post('integrity-check')
  @RequirePermissions('audit:admin')
  async triggerIntegrityCheck(
    @Body() dto: IntegrityCheckDto,
    @CurrentUser() user: any,
  ) {
    const region = user.region || 'cn';
    const tenantId = user.tenantId || 'default';

    const jobId = await this.auditService.triggerAsyncIntegrityCheck(
      region,
      tenantId,
      {
        startDate: dto.startDate ? new Date(dto.startDate) : undefined,
        endDate: dto.endDate ? new Date(dto.endDate) : undefined,
        scope: dto.scope,
      },
    );

    return {
      jobId,
      status: 'QUEUED',
      createdAt: new Date().toISOString(),
      message: '完整性检查任务已排队',
    };
  }

  /**
   * 查询完整性检查任务状态
   * GET /api/v1/audit/integrity-check/:jobId
   */
  @Get('integrity-check/:jobId')
  @RequirePermissions('audit:admin')
  async getIntegrityCheckStatus(
    @Param('jobId') jobId: string,
    @CurrentUser() user: any,
  ) {
    const region = user.region || 'cn';
    const tenantId = user.tenantId || 'default';

    const job = await this.auditService.getIntegrityJobStatus(
      jobId,
      region,
      tenantId,
    );

    if (!job) {
      throw new NotFoundException({
        code: 'AUDIT_INTEGRITY_CHECK_NOT_FOUND',
        message: '完整性检查任务不存在',
      });
    }

    return job;
  }

  /**
   * 导出审计日志
   * POST /api/v1/audit/export
   */
  @Post('export')
  @RequirePermissions('audit:export')
  async exportLogs(
    @Body() dto: AuditExportDto,
    @CurrentUser() user: any,
    @Res() res: Response,
  ) {
    const region = user.region || 'cn';
    const tenantId = user.tenantId || 'default';

    const startDate = new Date(dto.startDate);
    const endDate = new Date(dto.endDate);

    // 获取数据
    const logs = await this.auditService.exportLogs(
      region,
      tenantId,
      startDate,
      endDate,
      dto.filters,
      dto.fields,
    );

    const filename = `audit-logs-${new Date().toISOString().split('T')[0]}`;

    switch (dto.format) {
      case 'json':
        res.setHeader('Content-Type', 'application/json');
        res.setHeader(
          'Content-Disposition',
          `attachment; filename="${filename}.json"`,
        );
        return res.send(JSON.stringify(logs, null, 2));

      case 'csv':
        const csv = this.convertToCSV(logs);
        res.setHeader('Content-Type', 'text/csv; charset=utf-8');
        res.setHeader(
          'Content-Disposition',
          `attachment; filename="${filename}.csv"`,
        );
        // 添加 BOM 以支持 Excel 正确识别 UTF-8
        return res.send('\uFEFF' + csv);

      case 'excel':
        // 简化实现：返回 CSV 格式（实际项目中应使用 exceljs 等库）
        const excelCsv = this.convertToCSV(logs);
        res.setHeader('Content-Type', 'text/csv; charset=utf-8');
        res.setHeader(
          'Content-Disposition',
          `attachment; filename="${filename}.csv"`,
        );
        return res.send('\uFEFF' + excelCsv);

      default:
        throw new BadRequestException({
          code: 'AUDIT_EXPORT_INVALID_FORMAT',
          message: '不支持的导出格式',
        });
    }
  }

  /**
   * 将数据转换为 CSV 格式
   */
  private convertToCSV(data: any[]): string {
    if (!data || data.length === 0) {
      return '';
    }

    // 获取所有列名
    const headers = Object.keys(data[0]);

    // 转义 CSV 值
    const escapeCSV = (value: any): string => {
      if (value === null || value === undefined) {
        return '';
      }
      const str =
        typeof value === 'object' ? JSON.stringify(value) : String(value);
      // 如果包含逗号、引号或换行，需要用引号包裹并转义内部引号
      if (str.includes(',') || str.includes('"') || str.includes('\n')) {
        return `"${str.replace(/"/g, '""')}"`;
      }
      return str;
    };

    // 生成 CSV
    const rows = [
      headers.join(','),
      ...data.map((row) => headers.map((h) => escapeCSV(row[h])).join(',')),
    ];

    return rows.join('\n');
  }

  /**
   * 生成 SOX 合规报表
   * POST /api/v1/audit/reports/sox
   */
  @Post('reports/sox')
  @RequirePermissions('audit:report:sox')
  async generateSoxReport(
    @Body() dto: DateRangeReportDto,
    @CurrentUser() user: any,
  ) {
    const region = user.region || 'cn';
    const tenantId = user.tenantId || 'default';

    return this.complianceReportService.generateSoxReport(
      region,
      tenantId,
      new Date(dto.startDate),
      new Date(dto.endDate),
    );
  }

  /**
   * 生成 GDPR 数据访问报告
   * GET /api/v1/audit/reports/gdpr/:userId
   */
  @Get('reports/gdpr/:userId')
  @RequirePermissions('audit:report:gdpr')
  async generateGdprReport(
    @Param('userId', ParseUUIDPipe) userId: string,
    @CurrentUser() user: any,
  ) {
    const region = user.region || 'cn';
    const tenantId = user.tenantId || 'default';

    return this.complianceReportService.generateGdprDataAccessReport(
      userId,
      region,
      tenantId,
    );
  }

  /**
   * 生成异常操作报告
   * POST /api/v1/audit/reports/anomaly
   */
  @Post('reports/anomaly')
  @RequirePermissions('audit:report:anomaly')
  async generateAnomalyReport(
    @Body() dto: DateRangeReportDto,
    @CurrentUser() user: any,
  ) {
    const region = user.region || 'cn';
    const tenantId = user.tenantId || 'default';

    return this.complianceReportService.generateAnomalyReport(
      region,
      tenantId,
      new Date(dto.startDate),
      new Date(dto.endDate),
    );
  }

  /**
   * 导出 SOX 报表为 CSV
   * POST /api/v1/audit/reports/sox/export
   */
  @Post('reports/sox/export')
  @RequirePermissions('audit:report:sox')
  async exportSoxReport(
    @Body() dto: DateRangeReportDto,
    @CurrentUser() user: any,
    @Res() res: Response,
  ) {
    const region = user.region || 'cn';
    const tenantId = user.tenantId || 'default';

    const report = await this.complianceReportService.generateSoxReport(
      region,
      tenantId,
      new Date(dto.startDate),
      new Date(dto.endDate),
    );

    const csv = await this.complianceReportService.exportReportToCsv(report);

    const filename = `sox-compliance-report-${new Date().toISOString().split('T')[0]}.csv`;

    res.setHeader('Content-Type', 'text/csv; charset=utf-8');
    res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
    return res.send('\uFEFF' + csv);
  }

  /**
   * 批量检查告警
   * POST /api/v1/audit/alerts/batch-check
   */
  @Post('alerts/batch-check')
  @RequirePermissions('audit:admin')
  async batchCheckAlerts(
    @Body() dto: BatchCheckAlertsDto,
    @CurrentUser() user: any,
  ) {
    const region = user.region || 'cn';
    const tenantId = user.tenantId || 'default';
    const since = dto.since ? new Date(dto.since) : undefined;

    return this.alertService.batchCheckAlerts(region, tenantId, since);
  }

  /**
   * 检查用户告警状态
   * GET /api/v1/audit/alerts/user/:userId
   */
  @Get('alerts/user/:userId')
  @RequirePermissions('audit:admin')
  async getUserAlertStatus(
    @Param('userId', ParseUUIDPipe) userId: string,
    @CurrentUser() user: any,
  ) {
    const region = user.region || 'cn';
    const tenantId = user.tenantId || 'default';

    return this.alertService.checkUserAlertStatus(userId, region, tenantId);
  }

  /**
   * 检测连续失败模式
   * POST /api/v1/audit/alerts/detect-failures
   */
  @Post('alerts/detect-failures')
  @RequirePermissions('audit:admin')
  async detectContinuousFailures(
    @Body() dto: DetectFailuresDto,
    @CurrentUser() user: any,
  ) {
    const region = user.region || 'cn';
    const tenantId = user.tenantId || 'default';

    return this.alertService.detectContinuousFailures(
      dto.userId,
      dto.action as any,
      region,
      tenantId,
      dto.timeWindow,
    );
  }

  /**
   * 检测异常操作模式
   * POST /api/v1/audit/alerts/detect-anomaly
   */
  @Post('alerts/detect-anomaly')
  @RequirePermissions('audit:admin')
  async detectAnomalousPattern(
    @Body() dto: DetectAnomalyDto,
    @CurrentUser() user: any,
  ) {
    const region = user.region || 'cn';
    const tenantId = user.tenantId || 'default';

    return this.alertService.detectAnomalousPattern(
      dto.userId,
      region,
      tenantId,
      dto.days,
    );
  }
}
