import { Injectable, Logger } from '@nestjs/common';
import * as fs from 'fs';
import * as path from 'path';
import { PDFDocument, PDFFont /* , rgb */ } from 'pdf-lib';

// eslint-disable-next-line @typescript-eslint/no-var-requires
const fontkit = require('@pdf-lib/fontkit');

/**
 * 表单字段名称常量
 * 在 PDF 模板中创建这些命名的文本字段
 */
const FORM_FIELDS = {
  CONTRACT_NO: 'contractNo',
  USER_NAME: 'userName',
  USER_ID_CARD: 'userIdCard',
  USER_PHONE: 'userPhone',
  TREE_COUNT: 'treeCount',
  TOTAL_AMOUNT: 'RmbAmount',                        // 认种金额（数字）
  TOTAL_AMOUNT_CHINESE: 'SpellChineseFormatNumber', // 认种金额（大写）
  GREEN_POINTS_AMOUNT: 'GreenAmount',               // 绿积分金额
  SIGN_YEAR: 'signYear',
  SIGN_MONTH: 'signMonth',
  SIGN_DAY: 'signDay',
  SIGNATURE: 'signature', // 签名图片按钮字段
} as const;

/**
 * 数字转中文大写金额
 * @param num 数字金额
 * @returns 中文大写金额字符串
 */
function numberToChineseAmount(num: number): string {
  if (num === 0) return '零元整';

  const digits = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
  const units = ['', '拾', '佰', '仟'];
  const bigUnits = ['', '万', '亿', '兆'];

  // 分离整数和小数部分
  const [integerPart, decimalPart] = num.toFixed(2).split('.');
  const intNum = parseInt(integerPart, 10);
  const jiao = parseInt(decimalPart[0], 10); // 角
  const fen = parseInt(decimalPart[1], 10);  // 分

  let result = '';

  // 处理整数部分
  if (intNum > 0) {
    const intStr = intNum.toString();
    const len = intStr.length;
    let zeroFlag = false; // 是否需要补零

    for (let i = 0; i < len; i++) {
      const digit = parseInt(intStr[i], 10);
      const unitIndex = (len - i - 1) % 4;
      const bigUnitIndex = Math.floor((len - i - 1) / 4);

      if (digit === 0) {
        zeroFlag = true;
        // 在万、亿位置需要加单位
        if (unitIndex === 0 && bigUnitIndex > 0) {
          // 检查这个大单位区间是否全为零
          const start = Math.max(0, i - 3);
          let allZero = true;
          for (let j = start; j <= i; j++) {
            if (parseInt(intStr[j], 10) !== 0) {
              allZero = false;
              break;
            }
          }
          if (!allZero) {
            result += bigUnits[bigUnitIndex];
          }
        }
      } else {
        if (zeroFlag) {
          result += digits[0]; // 补零
          zeroFlag = false;
        }
        result += digits[digit] + units[unitIndex];
        if (unitIndex === 0) {
          result += bigUnits[bigUnitIndex];
        }
      }
    }
    result += '元';
  }

  // 处理小数部分
  if (jiao === 0 && fen === 0) {
    result += '整';
  } else {
    if (jiao > 0) {
      result += digits[jiao] + '角';
    } else if (intNum > 0) {
      result += '零';
    }
    if (fen > 0) {
      result += digits[fen] + '分';
    }
  }

  return result || '零元整';
}

/**
 * 单棵榴莲树含税价格（人民币）
 */
export const PRICE_PER_TREE_CNY = 17414.1;

/**
 * 单棵榴莲树绿积分价格
 */
export const PRICE_PER_TREE_GREEN_POINTS = 15831;

/**
 * 合同 PDF 生成数据
 */
export interface ContractPdfData {
  contractNo: string; // 合同编号: accountSequence-yyyyMMddHHmm
  userRealName: string;
  userIdCard: string;
  userPhone: string;
  treeCount: number;
  totalAmount?: number;        // 认种金额（人民币），可选，默认根据 treeCount 计算
  greenPointsAmount?: number;  // 绿积分金额，可选
  signingDate: string; // YYYY-MM-DD 格式
}

/**
 * 签名嵌入数据
 */
export interface SignatureData {
  signatureImagePng: Buffer; // PNG 格式的签名图片
}

/**
 * PDF 生成服务
 *
 * 使用 pdf-lib 操作 PDF：
 * 1. 优先使用 AcroForm 表单字段填充（更可靠）
 * 2. 如果模板没有表单字段，回退到坐标定位方式
 * 3. 嵌入用户签名图片
 * 4. 输出最终 PDF
 */
@Injectable()
export class PdfGeneratorService {
  private readonly logger = new Logger(PdfGeneratorService.name);
  private readonly templatePath: string;
  private readonly fontPath: string;

  constructor() {
    this.templatePath = path.join(
      __dirname,
      '../../../templates/contract-template.pdf',
    );
    this.fontPath = path.join(
      __dirname,
      '../../../templates/fonts/STKAITI.ttf',
    );
  }

  /**
   * 检查 PDF 是否包含表单字段
   */
  private hasFormFields(pdfDoc: PDFDocument): boolean {
    try {
      const form = pdfDoc.getForm();
      const fields = form.getFields();
      return fields.length > 0;
    } catch {
      return false;
    }
  }

  /**
   * 生成合同 PDF（填充用户信息，不含签名）
   * @param data 合同数据
   * @returns PDF Buffer
   */
  async generateContractPdf(data: ContractPdfData): Promise<Buffer> {
    this.logger.log(`Generating PDF for contract: ${data.contractNo}`);

    try {
      // 1. 加载 PDF 模板
      const templateBytes = fs.readFileSync(this.templatePath);
      const pdfDoc = await PDFDocument.load(templateBytes);

      // 2. 注册 fontkit 以支持自定义字体
      pdfDoc.registerFontkit(fontkit);

      // 3. 加载中文字体
      const fontBytes = fs.readFileSync(this.fontPath);
      const customFont = await pdfDoc.embedFont(fontBytes);

      // 4. 使用表单字段填充
      if (!this.hasFormFields(pdfDoc)) {
        throw new Error('PDF模板缺少表单字段，请使用带表单字段的模板');
      }
      this.logger.log('Using form fields mode');
      await this.fillFormFields(pdfDoc, data, customFont);
      // 预览PDF时扁平化所有字段（包括签名字段）
      const form = pdfDoc.getForm();
      form.flatten();

      // 5. 保存 PDF
      const pdfBytes = await pdfDoc.save();

      this.logger.log(`PDF generated successfully for contract: ${data.contractNo}`);
      return Buffer.from(pdfBytes);
    } catch (error) {
      this.logger.error(
        `Failed to generate PDF for contract ${data.contractNo}:`,
        error,
      );
      throw new Error(`PDF generation failed: ${error.message}`);
    }
  }

  /**
   * 使用表单字段填充 PDF（推荐方式，更可靠）
   * 需要 PDF 模板中预先创建命名的文本字段
   */
  private async fillFormFields(
    pdfDoc: PDFDocument,
    data: ContractPdfData,
    font: PDFFont,
  ): Promise<void> {
    const form = pdfDoc.getForm();
    const [year, month, day] = data.signingDate.split('-');

    // 计算金额：优先使用传入的金额，否则根据棵数计算
    const totalAmount = data.totalAmount ?? data.treeCount * PRICE_PER_TREE_CNY;
    const totalAmountChinese = numberToChineseAmount(totalAmount);
    // 绿积分金额：优先使用传入的金额，否则根据棵数计算（使用绿积分单价）
    const greenPointsAmount = data.greenPointsAmount ?? data.treeCount * PRICE_PER_TREE_GREEN_POINTS;

    // 填充各个字段
    const fieldMappings: Array<{ name: string; value: string }> = [
      { name: FORM_FIELDS.CONTRACT_NO, value: data.contractNo },
      { name: FORM_FIELDS.USER_NAME, value: data.userRealName || '未认证' },
      { name: FORM_FIELDS.USER_ID_CARD, value: data.userIdCard || '未认证' },
      { name: FORM_FIELDS.USER_PHONE, value: data.userPhone || '未认证' },
      { name: FORM_FIELDS.TREE_COUNT, value: data.treeCount.toString() },
      { name: FORM_FIELDS.TOTAL_AMOUNT, value: totalAmount.toFixed(2) },
      { name: FORM_FIELDS.TOTAL_AMOUNT_CHINESE, value: totalAmountChinese },
      { name: FORM_FIELDS.GREEN_POINTS_AMOUNT, value: greenPointsAmount.toFixed(2) },
      { name: FORM_FIELDS.SIGN_YEAR, value: year },
      { name: FORM_FIELDS.SIGN_MONTH, value: month },
      { name: FORM_FIELDS.SIGN_DAY, value: day },
    ];

    for (const { name, value } of fieldMappings) {
      try {
        const field = form.getTextField(name);
        field.setText(value);
        field.updateAppearances(font);
      } catch (error) {
        // 所有字段都是必须的，缺少任何字段都应该报错
        throw new Error(`PDF模板缺少必需的表单字段: ${name}`);
      }
    }

    // 注意：不在这里调用 form.flatten()
    // 签名字段需要保留，待签名嵌入后再统一扁平化
  }

  /**
   * 在已生成的 PDF 上嵌入签名
   * @param pdfBuffer 原始 PDF Buffer
   * @param signature 签名数据
   * @returns 带签名的 PDF Buffer
   */
  async embedSignature(
    pdfBuffer: Buffer,
    signature: SignatureData,
  ): Promise<Buffer> {
    this.logger.log('Embedding signature into PDF');

    try {
      const pdfDoc = await PDFDocument.load(pdfBuffer);

      // 嵌入签名图片
      const signatureImage = await pdfDoc.embedPng(signature.signatureImagePng);

      // 尝试使用表单字段放置签名
      if (await this.tryEmbedSignatureByFormField(pdfDoc, signatureImage)) {
        this.logger.log('Signature embedded using form field');
      } else {
        // 回退到坐标方式
        this.logger.log('Signature embedded using coordinates (no form field found)');
        this.embedSignatureByCoordinates(pdfDoc, signatureImage);
      }

      const pdfBytes = await pdfDoc.save();
      this.logger.log('Signature embedded successfully');
      return Buffer.from(pdfBytes);
    } catch (error) {
      this.logger.error('Failed to embed signature:', error);
      throw new Error(`Signature embedding failed: ${error.message}`);
    }
  }

  /**
   * 使用表单字段放置签名图片
   * @returns 是否成功使用表单字段
   */
  private async tryEmbedSignatureByFormField(
    pdfDoc: PDFDocument,
    signatureImage: Awaited<ReturnType<PDFDocument['embedPng']>>,
  ): Promise<boolean> {
    try {
      const form = pdfDoc.getForm();
      const signatureButton = form.getButton(FORM_FIELDS.SIGNATURE);
      signatureButton.setImage(signatureImage);
      form.flatten();
      return true;
    } catch {
      return false;
    }
  }

  /**
   * 使用坐标方式放置签名图片
   */
  private embedSignatureByCoordinates(
    pdfDoc: PDFDocument,
    signatureImage: Awaited<ReturnType<PDFDocument['embedPng']>>,
  ): void {
    const pages = pdfDoc.getPages();
    // 使用最后一页（签名区域通常在最后一页）
    const lastPage = pages[pages.length - 1];

    // 计算签名图片的尺寸（保持宽高比，最大宽度150，最大高度60）
    const maxWidth = 150;
    const maxHeight = 60;
    const { width, height } = signatureImage.scale(1);
    let scaledWidth = width;
    let scaledHeight = height;

    if (width > maxWidth) {
      scaledWidth = maxWidth;
      scaledHeight = (height * maxWidth) / width;
    }
    if (scaledHeight > maxHeight) {
      scaledHeight = maxHeight;
      scaledWidth = (width * maxHeight) / height;
    }

    // 在"乙方（签字/盖章）："后方绘制签名（坐标根据模板调整）
    lastPage.drawImage(signatureImage, {
      x: 350,
      y: 180,
      width: scaledWidth,
      height: scaledHeight,
    });
  }

  /**
   * 生成带签名的完整合同 PDF
   * 在同一个 PDFDocument 实例上完成填充和签名，最后统一扁平化
   * @param data 合同数据
   * @param signature 签名数据（可选，如果没有签名则只生成填充数据的 PDF）
   * @returns PDF Buffer
   */
  async generateSignedContractPdf(
    data: ContractPdfData,
    signature?: SignatureData,
  ): Promise<Buffer> {
    this.logger.log(`Generating signed PDF for contract: ${data.contractNo}`);

    try {
      // 1. 加载 PDF 模板
      const templateBytes = fs.readFileSync(this.templatePath);
      const pdfDoc = await PDFDocument.load(templateBytes);

      // 2. 注册 fontkit 以支持自定义字体
      pdfDoc.registerFontkit(fontkit);

      // 3. 加载中文字体
      const fontBytes = fs.readFileSync(this.fontPath);
      const customFont = await pdfDoc.embedFont(fontBytes);

      // 4. 填充表单字段（不扁平化）
      if (!this.hasFormFields(pdfDoc)) {
        throw new Error('PDF模板缺少表单字段，请使用带表单字段的模板');
      }
      this.logger.log('Using form fields mode');
      await this.fillFormFields(pdfDoc, data, customFont);

      // 5. 如果有签名，嵌入签名图片
      // 直接使用坐标方式在页面上绘制签名，不受表单字段尺寸限制
      if (signature) {
        const signatureImage = await pdfDoc.embedPng(signature.signatureImagePng);

        // 获取签名字段位置作为参考
        let fieldX = 380; // 默认 x 坐标
        let fieldY = 100; // 默认 y 坐标
        let fieldWidth = 92;
        let fieldHeight = 51;

        try {
          const form = pdfDoc.getForm();
          const signatureButton = form.getButton(FORM_FIELDS.SIGNATURE);
          const widgets = signatureButton.acroField.getWidgets();
          if (widgets.length > 0) {
            const rect = widgets[0].getRectangle();
            fieldX = rect.x;
            fieldY = rect.y;
            fieldWidth = rect.width;
            fieldHeight = rect.height;
            this.logger.log(`Signature field position: x=${rect.x}, y=${rect.y}, field size: ${rect.width}x${rect.height}`);
          }
        } catch {
          this.logger.log('No signature button field found, using default coordinates');
        }

        // 直接在页面上绘制签名图片
        const pages = pdfDoc.getPages();
        const lastPage = pages[pages.length - 1];

        // 计算签名图片的尺寸（保持宽高比，目标尺寸更大）
        const maxWidth = 150;
        const maxHeight = 80;
        const { width, height } = signatureImage.scale(1);
        let scaledWidth = width;
        let scaledHeight = height;

        if (width > maxWidth) {
          scaledWidth = maxWidth;
          scaledHeight = (height * maxWidth) / width;
        }
        if (scaledHeight > maxHeight) {
          scaledHeight = maxHeight;
          scaledWidth = (width * maxHeight) / height;
        }

        // 计算签名位置：以签名字段中心为基准，将签名图片居中放置
        const fieldCenterX = fieldX + fieldWidth / 2;
        const fieldCenterY = fieldY + fieldHeight / 2;
        const signatureX = fieldCenterX - scaledWidth / 2;
        const signatureY = fieldCenterY - scaledHeight / 2;

        // 在签名位置绘制图片
        lastPage.drawImage(signatureImage, {
          x: signatureX,
          y: signatureY,
          width: scaledWidth,
          height: scaledHeight,
        });

        this.logger.log(`Signature drawn at (${signatureX}, ${signatureY}), size: ${scaledWidth}x${scaledHeight}`);

        // 移除签名按钮字段，避免扁平化时产生灰色背景
        try {
          const form = pdfDoc.getForm();
          const signatureButton = form.getButton(FORM_FIELDS.SIGNATURE);
          form.removeField(signatureButton);
          this.logger.log('Signature button field removed');
        } catch {
          // 忽略移除失败
        }
      }

      // 6. 最后统一扁平化所有表单字段
      if (this.hasFormFields(pdfDoc)) {
        const form = pdfDoc.getForm();
        form.flatten();
        this.logger.log('Form fields flattened');
      }

      // 7. 保存 PDF
      const pdfBytes = await pdfDoc.save();
      this.logger.log(`Signed PDF generated successfully for contract: ${data.contractNo}`);
      return Buffer.from(pdfBytes);
    } catch (error) {
      this.logger.error(
        `Failed to generate signed PDF for contract ${data.contractNo}:`,
        error,
      );
      throw new Error(`Signed PDF generation failed: ${error.message}`);
    }
  }

}
