import {
  Controller,
  Get,
  Post,
  Body,
  Req,
  HttpException,
  HttpStatus,
  UseInterceptors,
  UploadedFile,
  Logger,
} from '@nestjs/common';
import {
  ApiTags,
  ApiOperation,
  ApiBearerAuth,
  ApiBody,
  ApiConsumes,
} from '@nestjs/swagger';
import { FileInterceptor } from '@nestjs/platform-express';
import * as XLSX from 'xlsx';
import { BatchMiningService, BatchMiningItem } from '../../application/services/batch-mining.service';
import { getClientIp } from '../../shared/utils/get-client-ip';

@ApiTags('Batch Mining')
@ApiBearerAuth()
@Controller('batch-mining')
export class BatchMiningController {
  private readonly logger = new Logger(BatchMiningController.name);

  constructor(private readonly batchMiningService: BatchMiningService) {}

  @Get('status')
  @ApiOperation({ summary: '获取批量补发状态（是否已执行）' })
  async getStatus() {
    this.logger.log(`[GET /batch-mining/status] 请求获取批量补发状态`);
    try {
      const result = await this.batchMiningService.getStatus();
      this.logger.log(`[GET /batch-mining/status] 返回: ${JSON.stringify(result)}`);
      return result;
    } catch (error) {
      this.logger.error(`[GET /batch-mining/status] 错误:`, error);
      throw error;
    }
  }

  @Post('upload-preview')
  @ApiOperation({ summary: '上传 Excel 文件并预览（不执行）' })
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        file: {
          type: 'string',
          format: 'binary',
          description: 'Excel 文件 (.xlsx)',
        },
      },
    },
  })
  @UseInterceptors(FileInterceptor('file'))
  async uploadAndPreview(@UploadedFile() file: Express.Multer.File) {
    this.logger.log(`[POST /batch-mining/upload-preview] 开始处理上传预览请求`);

    if (!file) {
      this.logger.error(`[POST /batch-mining/upload-preview] 未收到文件`);
      throw new HttpException('请上传文件', HttpStatus.BAD_REQUEST);
    }

    this.logger.log(`[POST /batch-mining/upload-preview] 收到文件: ${file.originalname}, 大小: ${file.size}, 类型: ${file.mimetype}`);

    // 检查文件类型
    const validTypes = [
      'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
      'application/vnd.ms-excel',
    ];
    if (!validTypes.includes(file.mimetype) && !file.originalname.endsWith('.xlsx')) {
      this.logger.error(`[POST /batch-mining/upload-preview] 文件类型不正确: ${file.mimetype}`);
      throw new HttpException('请上传 Excel 文件 (.xlsx)', HttpStatus.BAD_REQUEST);
    }

    try {
      // 解析 Excel
      this.logger.log(`[POST /batch-mining/upload-preview] 开始解析 Excel...`);
      const workbook = XLSX.read(file.buffer, { type: 'buffer' });
      this.logger.log(`[POST /batch-mining/upload-preview] Excel Sheet 列表: ${workbook.SheetNames.join(', ')}`);

      const sheetName = workbook.SheetNames[0];
      const worksheet = workbook.Sheets[sheetName];

      // 尝试读取 Sheet2（如果存在）
      const actualSheetName = workbook.SheetNames.includes('Sheet2') ? 'Sheet2' : sheetName;
      const actualSheet = workbook.Sheets[actualSheetName];
      this.logger.log(`[POST /batch-mining/upload-preview] 使用 Sheet: ${actualSheetName}`);

      // 转换为数组
      const rows: any[][] = XLSX.utils.sheet_to_json(actualSheet, { header: 1 });
      this.logger.log(`[POST /batch-mining/upload-preview] Excel 总行数: ${rows.length}`);

      // 解析数据
      const items = this.batchMiningService.parseExcelData(rows);
      this.logger.log(`[POST /batch-mining/upload-preview] 解析后有效数据: ${items.length} 条`);

      if (items.length === 0) {
        this.logger.error(`[POST /batch-mining/upload-preview] Excel 文件中没有有效数据`);
        throw new HttpException('Excel 文件中没有有效数据', HttpStatus.BAD_REQUEST);
      }

      // 调用预览 API
      this.logger.log(`[POST /batch-mining/upload-preview] 调用 mining-service 预览 API...`);
      const preview = await this.batchMiningService.preview(items);
      this.logger.log(`[POST /batch-mining/upload-preview] 预览成功, 总金额: ${preview.grandTotalAmount}`);

      return {
        ...preview,
        parsedItems: items,
        originalFileName: file.originalname,
      };
    } catch (error) {
      if (error instanceof HttpException) {
        throw error;
      }
      this.logger.error(`[POST /batch-mining/upload-preview] 解析 Excel 文件失败:`, error);
      throw new HttpException(
        `解析 Excel 文件失败: ${error instanceof Error ? error.message : error}`,
        HttpStatus.BAD_REQUEST,
      );
    }
  }

  @Post('preview')
  @ApiOperation({ summary: '预览批量补发（传入解析后的数据）' })
  @ApiBody({
    schema: {
      type: 'object',
      required: ['items'],
      properties: {
        items: {
          type: 'array',
          items: {
            type: 'object',
            properties: {
              accountSequence: { type: 'string' },
              treeCount: { type: 'number' },
              miningStartDate: { type: 'string' },
              batch: { type: 'number' },
              preMineDays: { type: 'number' },
              remark: { type: 'string' },
            },
          },
        },
      },
    },
  })
  async preview(@Body() body: { items: BatchMiningItem[] }) {
    this.logger.log(`[POST /batch-mining/preview] 请求预览, 数据条数: ${body.items?.length || 0}`);

    if (!body.items || body.items.length === 0) {
      this.logger.error(`[POST /batch-mining/preview] 数据为空`);
      throw new HttpException('数据不能为空', HttpStatus.BAD_REQUEST);
    }

    try {
      const result = await this.batchMiningService.preview(body.items);
      this.logger.log(`[POST /batch-mining/preview] 预览成功`);
      return result;
    } catch (error) {
      this.logger.error(`[POST /batch-mining/preview] 错误:`, error);
      throw error;
    }
  }

  @Post('upload-execute')
  @ApiOperation({ summary: '上传 Excel 文件并执行批量补发（只能执行一次）' })
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    schema: {
      type: 'object',
      required: ['file', 'reason'],
      properties: {
        file: {
          type: 'string',
          format: 'binary',
          description: 'Excel 文件 (.xlsx)',
        },
        reason: {
          type: 'string',
          description: '补发原因（必填）',
        },
      },
    },
  })
  @UseInterceptors(FileInterceptor('file'))
  async uploadAndExecute(
    @UploadedFile() file: Express.Multer.File,
    @Body() body: { reason: string },
    @Req() req: any,
  ) {
    this.logger.log(`[POST /batch-mining/upload-execute] 开始处理上传执行请求`);

    if (!file) {
      this.logger.error(`[POST /batch-mining/upload-execute] 未收到文件`);
      throw new HttpException('请上传文件', HttpStatus.BAD_REQUEST);
    }

    this.logger.log(`[POST /batch-mining/upload-execute] 收到文件: ${file.originalname}, 原因: ${body.reason}`);

    if (!body.reason || body.reason.trim().length === 0) {
      this.logger.error(`[POST /batch-mining/upload-execute] 补发原因为空`);
      throw new HttpException('补发原因不能为空', HttpStatus.BAD_REQUEST);
    }

    // 检查文件类型
    const validTypes = [
      'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
      'application/vnd.ms-excel',
    ];
    if (!validTypes.includes(file.mimetype) && !file.originalname.endsWith('.xlsx')) {
      this.logger.error(`[POST /batch-mining/upload-execute] 文件类型不正确: ${file.mimetype}`);
      throw new HttpException('请上传 Excel 文件 (.xlsx)', HttpStatus.BAD_REQUEST);
    }

    try {
      // 解析 Excel
      this.logger.log(`[POST /batch-mining/upload-execute] 开始解析 Excel...`);
      const workbook = XLSX.read(file.buffer, { type: 'buffer' });
      this.logger.log(`[POST /batch-mining/upload-execute] Excel Sheet 列表: ${workbook.SheetNames.join(', ')}`);

      // 尝试读取 Sheet2（如果存在）
      const actualSheetName = workbook.SheetNames.includes('Sheet2') ? 'Sheet2' : workbook.SheetNames[0];
      const actualSheet = workbook.Sheets[actualSheetName];
      this.logger.log(`[POST /batch-mining/upload-execute] 使用 Sheet: ${actualSheetName}`);

      // 转换为数组
      const rows: any[][] = XLSX.utils.sheet_to_json(actualSheet, { header: 1 });
      this.logger.log(`[POST /batch-mining/upload-execute] Excel 总行数: ${rows.length}`);

      // 解析数据
      const items = this.batchMiningService.parseExcelData(rows);
      this.logger.log(`[POST /batch-mining/upload-execute] 解析后有效数据: ${items.length} 条`);

      if (items.length === 0) {
        this.logger.error(`[POST /batch-mining/upload-execute] Excel 文件中没有有效数据`);
        throw new HttpException('Excel 文件中没有有效数据', HttpStatus.BAD_REQUEST);
      }

      const admin = req.admin;
      this.logger.log(`[POST /batch-mining/upload-execute] 操作管理员: ${admin?.username} (${admin?.id})`);

      // 调用执行 API
      this.logger.log(`[POST /batch-mining/upload-execute] 调用 mining-service 执行 API...`);
      const result = await this.batchMiningService.execute(
        {
          items,
          operatorId: admin.id,
          operatorName: admin.username,
          reason: body.reason,
        },
        admin.id,
        getClientIp(req),
        req.headers['user-agent'],
      );

      this.logger.log(`[POST /batch-mining/upload-execute] 执行成功: successCount=${result.successCount}, totalAmount=${result.totalAmount}`);

      return {
        ...result,
        originalFileName: file.originalname,
      };
    } catch (error) {
      if (error instanceof HttpException) {
        throw error;
      }
      this.logger.error(`[POST /batch-mining/upload-execute] 执行失败:`, error);
      throw new HttpException(
        `执行失败: ${error instanceof Error ? error.message : error}`,
        HttpStatus.BAD_REQUEST,
      );
    }
  }

  @Post('execute')
  @ApiOperation({ summary: '执行批量补发（传入解析后的数据，只能执行一次）' })
  @ApiBody({
    schema: {
      type: 'object',
      required: ['items', 'reason'],
      properties: {
        items: {
          type: 'array',
          items: {
            type: 'object',
            properties: {
              accountSequence: { type: 'string' },
              treeCount: { type: 'number' },
              miningStartDate: { type: 'string' },
              batch: { type: 'number' },
              preMineDays: { type: 'number' },
              remark: { type: 'string' },
            },
          },
        },
        reason: { type: 'string', description: '补发原因（必填）' },
      },
    },
  })
  async execute(
    @Body() body: { items: BatchMiningItem[]; reason: string },
    @Req() req: any,
  ) {
    this.logger.log(`[POST /batch-mining/execute] 请求执行批量补发`);
    this.logger.log(`[POST /batch-mining/execute] 数据条数: ${body.items?.length || 0}, 原因: ${body.reason}`);

    if (!body.items || body.items.length === 0) {
      this.logger.error(`[POST /batch-mining/execute] 数据为空`);
      throw new HttpException('数据不能为空', HttpStatus.BAD_REQUEST);
    }

    if (!body.reason || body.reason.trim().length === 0) {
      this.logger.error(`[POST /batch-mining/execute] 补发原因为空`);
      throw new HttpException('补发原因不能为空', HttpStatus.BAD_REQUEST);
    }

    const admin = req.admin;
    this.logger.log(`[POST /batch-mining/execute] 操作管理员: ${admin?.username} (${admin?.id})`);

    try {
      const result = await this.batchMiningService.execute(
        {
          items: body.items,
          operatorId: admin.id,
          operatorName: admin.username,
          reason: body.reason,
        },
        admin.id,
        getClientIp(req),
        req.headers['user-agent'],
      );
      this.logger.log(`[POST /batch-mining/execute] 执行成功`);
      return result;
    } catch (error) {
      this.logger.error(`[POST /batch-mining/execute] 错误:`, error);
      throw error;
    }
  }

  @Get('execution')
  @ApiOperation({ summary: '获取批量补发执行记录（含明细）' })
  async getExecution() {
    this.logger.log(`[GET /batch-mining/execution] 请求获取执行记录`);

    try {
      const execution = await this.batchMiningService.getExecution();
      if (!execution) {
        this.logger.log(`[GET /batch-mining/execution] 尚未执行过批量补发`);
        throw new HttpException('尚未执行过批量补发', HttpStatus.NOT_FOUND);
      }
      this.logger.log(`[GET /batch-mining/execution] 返回执行记录: id=${execution.id}`);
      return execution;
    } catch (error) {
      if (error instanceof HttpException) {
        throw error;
      }
      this.logger.error(`[GET /batch-mining/execution] 错误:`, error);
      throw error;
    }
  }
}
