/**
 * 合同管理控制器
 * [2026-02-05] 新增：提供合同查询、下载、批量下载功能
 * 回滚方式：删除此文件并从 app.module.ts 中移除引用
 */

import {
  Controller,
  Get,
  Post,
  Param,
  Query,
  Body,
  Res,
  Req,
  NotFoundException,
  BadRequestException,
  Logger,
  StreamableFile,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiQuery, ApiResponse, ApiParam, ApiBody } from '@nestjs/swagger';
import { Request, Response } from 'express';
import { PrismaService } from '../../infrastructure/persistence/prisma/prisma.service';
import { ContractService, ContractQueryParams } from '../../application/services/contract.service';

/**
 * 批量下载请求 DTO
 */
interface BatchDownloadRequestDto {
  filters?: {
    signedAfter?: string;
    signedBefore?: string;
    provinceCode?: string;
    cityCode?: string;
  };
  orderNos?: string[];
}

/**
 * 合同管理控制器
 * 为管理后台提供合同查询和下载功能
 */
@ApiTags('Admin - Contracts')
@Controller('admin/contracts')
export class ContractController {
  private readonly logger = new Logger(ContractController.name);

  constructor(
    private readonly prisma: PrismaService,
    private readonly contractService: ContractService,
  ) {}

  /**
   * 获取合同列表
   */
  @Get()
  @ApiOperation({ summary: '获取合同列表' })
  @ApiQuery({ name: 'signedAfter', required: false, description: '签署时间起始（ISO格式）' })
  @ApiQuery({ name: 'signedBefore', required: false, description: '签署时间结束（ISO格式）' })
  @ApiQuery({ name: 'provinceCode', required: false, description: '省份代码' })
  @ApiQuery({ name: 'cityCode', required: false, description: '城市代码' })
  @ApiQuery({ name: 'status', required: false, description: '合同状态' })
  @ApiQuery({ name: 'page', required: false, description: '页码，默认1' })
  @ApiQuery({ name: 'pageSize', required: false, description: '每页条数，默认50' })
  @ApiQuery({ name: 'orderBy', required: false, description: '排序字段：signedAt/createdAt' })
  @ApiQuery({ name: 'orderDir', required: false, description: '排序方向：asc/desc' })
  @ApiResponse({ status: 200, description: '合同列表' })
  async getContracts(
    @Query('signedAfter') signedAfter?: string,
    @Query('signedBefore') signedBefore?: string,
    @Query('provinceCode') provinceCode?: string,
    @Query('cityCode') cityCode?: string,
    @Query('status') status?: string,
    @Query('page') page?: string,
    @Query('pageSize') pageSize?: string,
    @Query('orderBy') orderBy?: string,
    @Query('orderDir') orderDir?: string,
  ) {
    this.logger.log(`========== GET /v1/admin/contracts 请求 ==========`);

    const params: ContractQueryParams = {
      signedAfter,
      signedBefore,
      provinceCode,
      cityCode,
      status,
      page: page ? parseInt(page, 10) : undefined,
      pageSize: pageSize ? parseInt(pageSize, 10) : undefined,
      orderBy: orderBy as 'signedAt' | 'createdAt',
      orderDir: orderDir as 'asc' | 'desc',
    };

    return this.contractService.getContracts(params);
  }

  /**
   * 获取合同统计信息
   */
  @Get('statistics')
  @ApiOperation({ summary: '获取合同统计信息' })
  @ApiQuery({ name: 'provinceCode', required: false, description: '省份代码' })
  @ApiQuery({ name: 'cityCode', required: false, description: '城市代码' })
  @ApiResponse({ status: 200, description: '合同统计' })
  async getStatistics(
    @Query('provinceCode') provinceCode?: string,
    @Query('cityCode') cityCode?: string,
  ) {
    this.logger.log(`========== GET /v1/admin/contracts/statistics 请求 ==========`);
    return this.contractService.getStatistics({ provinceCode, cityCode });
  }

  /**
   * 创建批量下载任务
   */
  @Post('batch-download')
  @ApiOperation({ summary: '创建合同批量下载任务' })
  @ApiBody({ description: '筛选条件' })
  @ApiResponse({ status: 201, description: '任务创建成功' })
  async createBatchDownload(
    @Body() body: BatchDownloadRequestDto,
    @Req() req: Request,
  ) {
    this.logger.log(`========== POST /v1/admin/contracts/batch-download 请求 ==========`);
    this.logger.log(`筛选条件: ${JSON.stringify(body.filters)}`);

    // 生成任务号
    const taskNo = `BD${Date.now()}`;

    // 获取操作者 ID（从请求头或默认值）
    const operatorId = (req.headers['x-operator-id'] as string) || 'system';

    // 创建任务记录
    const task = await this.prisma.contractBatchDownloadTask.create({
      data: {
        taskNo,
        operatorId,
        filters: body.filters ? JSON.parse(JSON.stringify(body.filters)) : null,
        status: 'PENDING',
        expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7天后过期
      },
    });

    // TODO: 触发异步任务处理（后续实现）
    // 可以使用 Bull Queue 或 Kafka 消息

    this.logger.log(`批量下载任务创建成功: ${taskNo}`);

    return {
      success: true,
      taskId: task.id.toString(),
      taskNo: task.taskNo,
      status: task.status,
      createdAt: task.createdAt.toISOString(),
    };
  }

  /**
   * 查询批量下载任务状态
   */
  @Get('batch-download/:taskNo')
  @ApiOperation({ summary: '查询批量下载任务状态' })
  @ApiParam({ name: 'taskNo', description: '任务号' })
  @ApiResponse({ status: 200, description: '任务状态' })
  @ApiResponse({ status: 404, description: '任务不存在' })
  async getBatchDownloadStatus(@Param('taskNo') taskNo: string) {
    this.logger.log(`========== GET /v1/admin/contracts/batch-download/${taskNo} 请求 ==========`);

    const task = await this.prisma.contractBatchDownloadTask.findUnique({
      where: { taskNo },
    });

    if (!task) {
      throw new NotFoundException(`任务不存在: ${taskNo}`);
    }

    return {
      taskId: task.id.toString(),
      taskNo: task.taskNo,
      status: task.status,
      totalContracts: task.totalContracts,
      downloadedCount: task.downloadedCount,
      failedCount: task.failedCount,
      progress: task.progress,
      resultFileUrl: task.resultFileUrl,
      resultFileSize: task.resultFileSize?.toString(),
      errors: task.errors,
      createdAt: task.createdAt.toISOString(),
      startedAt: task.startedAt?.toISOString(),
      completedAt: task.completedAt?.toISOString(),
      expiresAt: task.expiresAt?.toISOString(),
    };
  }

  /**
   * 获取用户的合同列表
   */
  @Get('users/:accountSequence')
  @ApiOperation({ summary: '获取用户的合同列表' })
  @ApiParam({ name: 'accountSequence', description: '用户账户序列号' })
  @ApiQuery({ name: 'page', required: false, description: '页码' })
  @ApiQuery({ name: 'pageSize', required: false, description: '每页条数' })
  @ApiResponse({ status: 200, description: '合同列表' })
  async getUserContracts(
    @Param('accountSequence') accountSequence: string,
    @Query('page') page?: string,
    @Query('pageSize') pageSize?: string,
  ) {
    this.logger.log(`========== GET /v1/admin/contracts/users/${accountSequence} 请求 ==========`);

    return this.contractService.getUserContracts(accountSequence, {
      page: page ? parseInt(page, 10) : undefined,
      pageSize: pageSize ? parseInt(pageSize, 10) : undefined,
    });
  }

  /**
   * 获取单个合同详情
   */
  @Get(':orderNo')
  @ApiOperation({ summary: '获取合同详情' })
  @ApiParam({ name: 'orderNo', description: '订单号' })
  @ApiResponse({ status: 200, description: '合同详情' })
  @ApiResponse({ status: 404, description: '合同不存在' })
  async getContract(@Param('orderNo') orderNo: string) {
    this.logger.log(`========== GET /v1/admin/contracts/${orderNo} 请求 ==========`);

    const contract = await this.contractService.getContract(orderNo);
    if (!contract) {
      throw new NotFoundException(`合同不存在: ${orderNo}`);
    }

    return contract;
  }

  /**
   * 下载合同 PDF（支持断点续传）
   */
  @Get(':orderNo/download')
  @ApiOperation({ summary: '下载合同 PDF（支持断点续传）' })
  @ApiParam({ name: 'orderNo', description: '订单号' })
  @ApiResponse({ status: 200, description: 'PDF 文件' })
  @ApiResponse({ status: 206, description: '部分内容（断点续传）' })
  @ApiResponse({ status: 404, description: '合同不存在' })
  async downloadContract(
    @Param('orderNo') orderNo: string,
    @Req() req: Request,
    @Res() res: Response,
  ): Promise<void> {
    this.logger.log(`========== GET /v1/admin/contracts/${orderNo}/download 请求 ==========`);

    // 获取合同详情
    const contract = await this.contractService.getContract(orderNo);
    if (!contract) {
      throw new NotFoundException(`合同不存在: ${orderNo}`);
    }

    if (!contract.signedPdfUrl) {
      throw new NotFoundException(`合同PDF不存在: ${orderNo}，状态: ${contract.status}`);
    }

    // 下载 PDF
    const pdfBuffer = await this.contractService.downloadContractPdf(orderNo);
    const fileSize = pdfBuffer.length;

    // 生成文件名
    const safeRealName = contract.userRealName?.replace(/[\/\\:*?"<>|]/g, '_') || '未知';
    const fileName = `${contract.contractNo}_${safeRealName}_${contract.treeCount}棵_${contract.provinceName}${contract.cityName}.pdf`;
    const encodedFileName = encodeURIComponent(fileName);

    // 检查 Range 请求头
    const range = req.headers.range;

    // 设置通用响应头
    res.setHeader('Accept-Ranges', 'bytes');
    res.setHeader('Content-Type', 'application/pdf');
    res.setHeader('Content-Disposition', `attachment; filename*=UTF-8''${encodedFileName}`);
    res.setHeader('Cache-Control', 'public, max-age=86400');

    if (range) {
      // 断点续传
      const parts = range.replace(/bytes=/, '').split('-');
      const start = parseInt(parts[0], 10);
      const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1;

      if (start >= fileSize || end >= fileSize || start > end) {
        res.status(416);
        res.setHeader('Content-Range', `bytes */${fileSize}`);
        res.end();
        return;
      }

      const chunkSize = end - start + 1;
      const chunk = pdfBuffer.slice(start, end + 1);

      this.logger.log(`Range 请求: ${fileName}, bytes ${start}-${end}/${fileSize}`);

      res.status(206);
      res.setHeader('Content-Range', `bytes ${start}-${end}/${fileSize}`);
      res.setHeader('Content-Length', chunkSize);
      res.end(chunk);
    } else {
      // 完整文件
      this.logger.log(`完整下载: ${fileName}, size=${fileSize}`);

      res.setHeader('Content-Length', fileSize);
      res.end(pdfBuffer);
    }
  }
}
