import {
  Controller,
  Get,
  Post,
  Param,
  Body,
  UseGuards,
  Request,
  HttpCode,
  HttpStatus,
  Logger,
  Res,
  StreamableFile,
} from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { Response } from 'express';
import { JwtAuthGuard } from '../guards/jwt-auth.guard';
import { ContractSigningService } from '../../application/services/contract-signing.service';
import { PdfGeneratorService } from '../../infrastructure/pdf/pdf-generator.service';
import { MinioStorageService } from '../../infrastructure/storage/minio-storage.service';
import * as crypto from 'crypto';

/**
 * 获取北京时间的日期字符串 (YYYY-MM-DD)
 * 用于合同签署日期显示
 */
function getBeijingDateString(): string {
  const now = new Date();
  // 北京时间 = UTC + 8小时
  const beijingTime = new Date(now.getTime() + 8 * 60 * 60 * 1000);
  return beijingTime.toISOString().split('T')[0];
}

/**
 * 签名轨迹点
 */
interface SignatureTracePoint {
  x: number;
  y: number;
  t: number; // 毫秒时间戳
}

/**
 * 签名笔画
 */
interface SignatureTraceStroke {
  points: SignatureTracePoint[];
  startTime: number;
  endTime: number;
}

/**
 * 签名轨迹数据（用于法律凭证）
 */
interface SignatureTraceData {
  strokes: SignatureTraceStroke[];
  totalDuration: number; // 总签名时长（毫秒）
  strokeCount: number;   // 笔画数量
}

/**
 * 签署合同请求DTO
 */
interface SignContractDto {
  signatureBase64: string;  // Base64编码的签名图片
  signatureHash: string;    // SHA256哈希
  deviceInfo: {
    deviceId?: string;
    deviceModel?: string;
    osVersion?: string;
    appVersion?: string;
  };
  location?: {
    latitude?: number;
    longitude?: number;
  };
  signatureTrace?: SignatureTraceData; // 签名轨迹数据（可选）
}

/**
 * 合同签署配置控制器（公开接口，不需要认证）
 */
@Controller('planting/contract-signing')
export class ContractSigningConfigController {
  private readonly contractSigningEnabled: boolean;

  constructor(private readonly configService: ConfigService) {
    // 默认启用合同签署功能
    this.contractSigningEnabled =
      this.configService.get<string>('CONTRACT_SIGNING_ENABLED', 'true') === 'true';
  }

  /**
   * 获取合同签署配置（公开接口）
   * 用于前端判断是否需要在认种前检查实名认证
   */
  @Get('config')
  getConfig() {
    return {
      success: true,
      data: {
        contractSigningEnabled: this.contractSigningEnabled,
      },
    };
  }
}

/**
 * 合同签署控制器
 *
 * 独立模块，提供合同签署相关的API
 */
@Controller('planting/contract-signing')
@UseGuards(JwtAuthGuard)
export class ContractSigningController {
  private readonly logger = new Logger(ContractSigningController.name);

  constructor(
    private readonly contractSigningService: ContractSigningService,
    private readonly pdfGeneratorService: PdfGeneratorService,
    private readonly minioStorageService: MinioStorageService,
  ) {}

  /**
   * 获取用户待签署的合同任务列表
   */
  @Get('pending')
  async getPendingTasks(@Request() req: { user: { id: string } }) {
    const userId = BigInt(req.user.id);
    const tasks = await this.contractSigningService.getPendingTasks(userId);
    return {
      success: true,
      data: tasks,
    };
  }

  /**
   * 获取用户所有未签署的合同任务（包括超时的）
   * 用于App启动时检查
   */
  @Get('unsigned')
  async getUnsignedTasks(@Request() req: { user: { id: string } }) {
    const userId = BigInt(req.user.id);
    const tasks = await this.contractSigningService.getUnsignedTasks(userId);
    return {
      success: true,
      data: tasks,
    };
  }

  /**
   * 检查用户是否需要先完成 KYC
   *
   * 如果用户有已付款的认种订单但未完成 KYC，返回需要强制完成 KYC 的信息
   */
  @Get('kyc-requirement')
  async checkKycRequirement(
    @Request() req: { user: { id: string; accountSequence?: string } },
  ) {
    const userId = BigInt(req.user.id);
    // accountSequence 可能在 token 中，也可能需要从 userId 派生
    const accountSequence = req.user.accountSequence || req.user.id;

    const result = await this.contractSigningService.checkKycRequirement(
      userId,
      accountSequence,
    );

    return {
      success: true,
      data: result,
    };
  }

  /**
   * 获取签署任务详情
   */
  @Get('tasks/:orderNo')
  async getTask(
    @Param('orderNo') orderNo: string,
    @Request() req: { user: { id: string } },
  ) {
    const userId = BigInt(req.user.id);
    const task = await this.contractSigningService.getTask(orderNo, userId);

    if (!task) {
      return {
        success: false,
        message: '签署任务不存在',
      };
    }

    return {
      success: true,
      data: task,
    };
  }

  /**
   * 记录用户已滚动到底部
   */
  @Post('tasks/:orderNo/scroll-complete')
  @HttpCode(HttpStatus.OK)
  async markScrollComplete(
    @Param('orderNo') orderNo: string,
    @Request() req: { user: { id: string } },
  ) {
    const userId = BigInt(req.user.id);

    try {
      await this.contractSigningService.markScrollComplete(orderNo, userId);
      return {
        success: true,
        message: '已记录滚动到底部',
      };
    } catch (error) {
      this.logger.error(`Failed to mark scroll complete: ${error.message}`);
      return {
        success: false,
        message: error.message,
      };
    }
  }

  /**
   * 记录用户确认法律效力
   */
  @Post('tasks/:orderNo/acknowledge')
  @HttpCode(HttpStatus.OK)
  async acknowledgeContract(
    @Param('orderNo') orderNo: string,
    @Request() req: { user: { id: string } },
  ) {
    const userId = BigInt(req.user.id);

    try {
      await this.contractSigningService.acknowledgeContract(orderNo, userId);
      return {
        success: true,
        message: '已确认法律效力',
      };
    } catch (error) {
      this.logger.error(`Failed to acknowledge contract: ${error.message}`);
      return {
        success: false,
        message: error.message,
      };
    }
  }

  /**
   * 上传签名并完成签署
   */
  @Post('tasks/:orderNo/sign')
  @HttpCode(HttpStatus.OK)
  async signContract(
    @Param('orderNo') orderNo: string,
    @Body() dto: SignContractDto,
    @Request() req: { user: { id: string }; ip: string; headers: { 'user-agent'?: string } },
  ) {
    const userId = BigInt(req.user.id);
    const ipAddress = req.ip || 'unknown';
    const userAgent = req.headers['user-agent'] || 'unknown';

    try {
      // 1. 获取任务详情
      const task = await this.contractSigningService.getTask(orderNo, userId);
      if (!task) {
        throw new Error('签署任务不存在');
      }

      // 2. 解码签名图片
      const signatureBuffer = Buffer.from(dto.signatureBase64, 'base64');
      this.logger.log(`Signature size: ${signatureBuffer.length} bytes for order ${orderNo}`);

      // 3. 计算签名哈希（如果前端没有提供）
      const signatureHash = dto.signatureHash || crypto.createHash('sha256').update(signatureBuffer).digest('hex');

      // 4. 上传签名图片到 MinIO
      let signatureCloudUrl: string;
      try {
        signatureCloudUrl = await this.minioStorageService.uploadSignature(orderNo, signatureBuffer);
        this.logger.log(`Signature uploaded to: ${signatureCloudUrl}`);
      } catch (uploadError) {
        this.logger.warn(`Failed to upload signature, using placeholder: ${uploadError.message}`);
        // 如果上传失败，使用占位 URL（允许服务继续工作）
        signatureCloudUrl = `data:image/png;base64,${dto.signatureBase64.slice(0, 100)}...`;
      }

      // 5. 生成带签名的 PDF（在同一个实例上完成填充和签名）
      const signingDate = getBeijingDateString();
      const pdfBuffer = await this.pdfGeneratorService.generateSignedContractPdf(
        {
          contractNo: task.contractNo,
          userRealName: task.userRealName || '未认证',
          userIdCard: task.userIdCardNumber || '',
          userPhone: task.userPhoneNumber || '',
          treeCount: task.treeCount,
          signingDate,
        },
        { signatureImagePng: signatureBuffer },
      );
      this.logger.log(`Signed PDF generated: ${pdfBuffer.length} bytes`);

      // 7. 上传签署后的 PDF 到 MinIO
      let signedPdfUrl: string;
      try {
        signedPdfUrl = await this.minioStorageService.uploadSignedPdf(orderNo, pdfBuffer);
        this.logger.log(`Signed PDF uploaded to: ${signedPdfUrl}`);
      } catch (uploadError) {
        this.logger.warn(`Failed to upload signed PDF: ${uploadError.message}`);
        // 如果上传失败，使用空 URL（数据库允许 null）
        signedPdfUrl = '';
      }

      // 8. 记录签名轨迹数据（如果有）
      if (dto.signatureTrace) {
        this.logger.log(`Signature trace: ${dto.signatureTrace.strokeCount} strokes, ${dto.signatureTrace.totalDuration}ms`);
      }

      // 9. 完成签署
      await this.contractSigningService.signContract(orderNo, userId, {
        signatureCloudUrl,
        signatureHash,
        signedPdfUrl,
        ipAddress,
        deviceInfo: dto.deviceInfo,
        userAgent,
        location: dto.location,
        signatureTrace: dto.signatureTrace ? JSON.stringify(dto.signatureTrace) : undefined,
      });

      return {
        success: true,
        message: '合同签署成功',
      };
    } catch (error) {
      this.logger.error(`Failed to sign contract: ${error.message}`);
      return {
        success: false,
        message: error.message,
      };
    }
  }

  /**
   * 补签合同（超时后用户仍可补签）
   */
  @Post('tasks/:orderNo/late-sign')
  @HttpCode(HttpStatus.OK)
  async lateSignContract(
    @Param('orderNo') orderNo: string,
    @Body() dto: SignContractDto,
    @Request() req: { user: { id: string }; ip: string; headers: { 'user-agent'?: string } },
  ) {
    const userId = BigInt(req.user.id);
    const ipAddress = req.ip || 'unknown';
    const userAgent = req.headers['user-agent'] || 'unknown';

    try {
      // 1. 获取任务详情
      const task = await this.contractSigningService.getTask(orderNo, userId);
      if (!task) {
        throw new Error('签署任务不存在');
      }

      // 2. 解码签名图片
      const signatureBuffer = Buffer.from(dto.signatureBase64, 'base64');
      this.logger.log(`Signature size: ${signatureBuffer.length} bytes for late-sign order ${orderNo}`);

      // 3. 计算签名哈希（如果前端没有提供）
      const signatureHash = dto.signatureHash || crypto.createHash('sha256').update(signatureBuffer).digest('hex');

      // 4. 上传签名图片到 MinIO
      let signatureCloudUrl: string;
      try {
        signatureCloudUrl = await this.minioStorageService.uploadSignature(orderNo, signatureBuffer);
        this.logger.log(`Signature uploaded to: ${signatureCloudUrl}`);
      } catch (uploadError) {
        this.logger.warn(`Failed to upload signature, using placeholder: ${uploadError.message}`);
        signatureCloudUrl = `data:image/png;base64,${dto.signatureBase64.slice(0, 100)}...`;
      }

      // 5. 生成带签名的 PDF（在同一个实例上完成填充和签名）
      const signingDate = getBeijingDateString();
      const pdfBuffer = await this.pdfGeneratorService.generateSignedContractPdf(
        {
          contractNo: task.contractNo,
          userRealName: task.userRealName || '未认证',
          userIdCard: task.userIdCardNumber || '',
          userPhone: task.userPhoneNumber || '',
          treeCount: task.treeCount,
          signingDate,
        },
        { signatureImagePng: signatureBuffer },
      );
      this.logger.log(`Signed PDF generated: ${pdfBuffer.length} bytes`);

      // 7. 上传签署后的 PDF 到 MinIO
      let signedPdfUrl: string;
      try {
        signedPdfUrl = await this.minioStorageService.uploadSignedPdf(orderNo, pdfBuffer);
        this.logger.log(`Signed PDF uploaded to: ${signedPdfUrl}`);
      } catch (uploadError) {
        this.logger.warn(`Failed to upload signed PDF: ${uploadError.message}`);
        signedPdfUrl = '';
      }

      // 8. 记录签名轨迹数据（如果有）
      if (dto.signatureTrace) {
        this.logger.log(`Signature trace: ${dto.signatureTrace.strokeCount} strokes, ${dto.signatureTrace.totalDuration}ms`);
      }

      // 9. 完成补签
      await this.contractSigningService.lateSignContract(orderNo, userId, {
        signatureCloudUrl,
        signatureHash,
        signedPdfUrl,
        ipAddress,
        deviceInfo: dto.deviceInfo,
        userAgent,
        location: dto.location,
        signatureTrace: dto.signatureTrace ? JSON.stringify(dto.signatureTrace) : undefined,
      });

      return {
        success: true,
        message: '合同补签成功',
      };
    } catch (error) {
      this.logger.error(`Failed to late-sign contract: ${error.message}`);
      return {
        success: false,
        message: error.message,
      };
    }
  }

  /**
   * 获取当前有效的合同模板（供前端预览）
   */
  @Get('template')
  async getActiveTemplate() {
    const template = await this.contractSigningService.getActiveTemplate();

    if (!template) {
      return {
        success: false,
        message: '没有可用的合同模板',
      };
    }

    return {
      success: true,
      data: {
        version: template.version,
        title: template.title,
        content: template.content,
      },
    };
  }

  /**
   * 获取合同 PDF 文件
   * 用于前端展示和签署
   */
  @Get('tasks/:orderNo/pdf')
  async getContractPdf(
    @Param('orderNo') orderNo: string,
    @Request() req: { user: { id: string } },
    @Res({ passthrough: true }) res: Response,
  ): Promise<StreamableFile> {
    const userId = BigInt(req.user.id);

    try {
      const task = await this.contractSigningService.getTask(orderNo, userId);

      if (!task) {
        throw new Error('签署任务不存在');
      }

      let pdfBuffer: Buffer;

      // 如果已签名且有签名PDF URL，从MinIO下载已签名的PDF
      if (task.status === 'SIGNED' && task.signedPdfUrl) {
        this.logger.log(`Downloading signed PDF from MinIO for order ${orderNo}`);
        try {
          pdfBuffer = await this.minioStorageService.downloadSignedPdf(task.signedPdfUrl);
          this.logger.log(`Signed PDF downloaded: ${pdfBuffer.length} bytes`);
        } catch (downloadError) {
          this.logger.warn(`Failed to download signed PDF, regenerating: ${downloadError.message}`);
          // 下载失败时回退到重新生成
          pdfBuffer = await this.regeneratePreviewPdf(task);
        }
      } else {
        // 未签名，生成预览PDF
        pdfBuffer = await this.regeneratePreviewPdf(task);
      }

      // 设置响应头
      res.set({
        'Content-Type': 'application/pdf',
        'Content-Disposition': `inline; filename="contract-${orderNo}.pdf"`,
        'Content-Length': pdfBuffer.length,
      });

      return new StreamableFile(pdfBuffer);
    } catch (error) {
      this.logger.error(`Failed to get PDF for order ${orderNo}:`, error);
      throw error;
    }
  }

  /**
   * 生成预览PDF（不含签名）
   */
  private async regeneratePreviewPdf(task: {
    contractNo: string;
    userRealName?: string;
    userIdCardNumber?: string;
    userPhoneNumber?: string;
    treeCount: number;
  }): Promise<Buffer> {
    const signingDate = getBeijingDateString();
    return this.pdfGeneratorService.generateContractPdf({
      contractNo: task.contractNo,
      userRealName: task.userRealName || '未认证',
      userIdCard: task.userIdCardNumber || '',
      userPhone: task.userPhoneNumber || '',
      treeCount: task.treeCount,
      signingDate,
    });
  }
}
