/**
 * 部门财务报表 ExcelJS 导出
 * 面向 C 端用户：标题区 / 信息区 / 表头 / 斑马纹 / 合计行 / 冻结窗格
 */
import ExcelJS from 'exceljs';

import { downloadByData } from '#/util/tool';
import {
  getDepartmentFinanceReportDetailApi,
  getDepartmentFinanceStoreDrugDetailApi,
} from '#/views/finance/department-finance/api';
import {
  MEDICINE_SCOPE_NOTE,
  STORE_HEADERS,
  STORE_MONEY_KEYS,
  SUMMARY_METRICS,
} from '#/views/finance/department-finance/config/metrics';

const XLSX_MIME =
  'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';

const THIN_BORDER: Partial<ExcelJS.Borders> = {
  top: { style: 'thin', color: { argb: 'FF000000' } },
  left: { style: 'thin', color: { argb: 'FF000000' } },
  bottom: { style: 'thin', color: { argb: 'FF000000' } },
  right: { style: 'thin', color: { argb: 'FF000000' } },
};

const DOUBLE_TOP_BORDER: Partial<ExcelJS.Borders> = {
  ...THIN_BORDER,
  top: { style: 'double', color: { argb: 'FF000000' } },
};

const DRUG_HEADERS = [
  '诊所名称',
  '药品编码',
  '药品名称',
  '药品类型',
  '数量',
  '供货单价',
  '供货总额',
];

export interface DepartmentFinanceDrugRow {
  store_name: string;
  drug_number?: string;
  drug_name?: string;
  type_txt?: string;
  number?: number | string;
  market_price?: number | string;
  total_supply_price?: number | string;
}

function formatDateTime(d: Date): string {
  const pad = (n: number) => String(n).padStart(2, '0');
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
}

/** 金额转数值，无效则返回 0 */
function toMoney(raw: unknown): number {
  const n = Number(raw);
  return Number.isFinite(n) ? n : 0;
}

function applyMoneyCell(cell: ExcelJS.Cell, value: unknown) {
  cell.value = toMoney(value);
  cell.numFmt = '#,##0.00';
  cell.alignment = { horizontal: 'right', vertical: 'middle' };
  cell.border = THIN_BORDER;
}

function applyTextCell(cell: ExcelJS.Cell, value: unknown, align: 'left' | 'center' = 'left') {
  cell.value = value == null || value === '' ? '' : String(value);
  cell.alignment = { horizontal: align, vertical: 'middle', wrapText: true };
  cell.border = THIN_BORDER;
}

function applyIntCell(cell: ExcelJS.Cell, value: unknown) {
  const n = Number(value);
  cell.value = Number.isFinite(n) ? n : value == null ? '' : String(value);
  cell.numFmt = '0';
  cell.alignment = { horizontal: 'right', vertical: 'middle' };
  cell.border = THIN_BORDER;
}

function styleInfoLabel(cell: ExcelJS.Cell, label: string) {
  cell.value = label;
  cell.font = { bold: true, size: 10 };
  cell.fill = {
    type: 'pattern',
    pattern: 'solid',
    fgColor: { argb: 'FFE8F0FE' },
  };
  cell.alignment = { horizontal: 'right', vertical: 'middle' };
  cell.border = THIN_BORDER;
}

function styleInfoValue(cell: ExcelJS.Cell, value: string) {
  cell.value = value;
  cell.font = { size: 10 };
  cell.alignment = { horizontal: 'left', vertical: 'middle' };
  cell.border = THIN_BORDER;
}

/**
 * 写入标题行（合并 layoutCols 列）
 * 为什么：C 端打开文件时先看到品牌标题，降低「裸表」感
 */
function writeTitleRow(
  sheet: ExcelJS.Worksheet,
  layoutCols: number,
  title: string,
) {
  sheet.mergeCells(1, 1, 1, layoutCols);
  const titleCell = sheet.getCell(1, 1);
  titleCell.value = title;
  titleCell.font = { bold: true, size: 16, color: { argb: 'FF1F4E79' } };
  titleCell.fill = {
    type: 'pattern',
    pattern: 'solid',
    fgColor: { argb: 'FFF5F7FA' },
  };
  titleCell.alignment = { horizontal: 'center', vertical: 'middle' };
  titleCell.border = THIN_BORDER;
  sheet.getRow(1).height = 36;
}

/**
 * 写入报表信息区（2 列一组：标签|值），返回下一可用行号
 */
function writeReportInfoBlock(
  sheet: ExcelJS.Worksheet,
  detail: Record<string, any>,
  layoutCols: number,
  exportedAt: Date,
): number {
  const pairs: [string, string][] = [
    ['报表编号', String(detail.report_no ?? '')],
    ['统计区间', `${detail.period_start ?? ''} ~ ${detail.period_end ?? ''}`],
    ['生成时间', String(detail.generated_at ?? '')],
    ['导出时间', formatDateTime(exportedAt)],
  ];
  let row = 2;
  for (const [label, value] of pairs) {
    styleInfoLabel(sheet.getCell(row, 1), label);
    if (layoutCols >= 2) {
      sheet.mergeCells(row, 2, row, layoutCols);
    }
    styleInfoValue(sheet.getCell(row, 2), value);
    sheet.getRow(row).height = 22;
    row += 1;
  }
  // 空一行分隔信息区与表头
  sheet.getRow(row).height = 8;
  return row + 1;
}

/** 表头行样式 */
function writeHeaderRow(
  sheet: ExcelJS.Worksheet,
  rowNum: number,
  headers: string[],
) {
  headers.forEach((label, i) => {
    const cell = sheet.getCell(rowNum, i + 1);
    cell.value = label;
    cell.font = { bold: true, color: { argb: 'FF000000' } };
    cell.fill = {
      type: 'pattern',
      pattern: 'solid',
      fgColor: { argb: 'FFFFFF00' },
    };
    cell.alignment = { horizontal: 'center', vertical: 'middle' };
    cell.border = THIN_BORDER;
  });
  sheet.getRow(rowNum).height = 30;
}

/** 按内容估算列宽 */
function autoFitColumns(
  sheet: ExcelJS.Worksheet,
  colCount: number,
  startRow: number,
  endRow: number,
  minWidth = 10,
  maxWidth = 40,
) {
  for (let c = 1; c <= colCount; c++) {
    let maxLen = minWidth;
    for (let r = startRow; r <= endRow; r++) {
      const v = sheet.getCell(r, c).value;
      const s =
        v == null
          ? ''
          : typeof v === 'object' && 'richText' in (v as object)
            ? ''
            : String(v);
      maxLen = Math.max(maxLen, s.length);
    }
    sheet.getColumn(c).width = Math.min(Math.max(maxLen * 1.2 + 2, minWidth), maxWidth);
  }
}

function freezeAt(sheet: ExcelJS.Worksheet, headerRow: number) {
  sheet.views = [
    {
      state: 'frozen',
      xSplit: 0,
      ySplit: headerRow,
      topLeftCell: `A${headerRow + 1}`,
      activeCell: `A${headerRow + 1}`,
    },
  ];
}

/**
 * Sheet1：报表汇总 —— 键值表，开票合计高亮
 */
function buildSummarySheet(
  workbook: ExcelJS.Workbook,
  detail: Record<string, any>,
  exportedAt: Date,
) {
  const sheet = workbook.addWorksheet('报表汇总', {
    views: [{ showGridLines: true }],
  });
  const layoutCols = 2;
  writeTitleRow(sheet, layoutCols, '萧康云医 · 部门财务报表');
  const headerRow = writeReportInfoBlock(sheet, detail, layoutCols, exportedAt);

  // 键值表表头
  writeHeaderRow(sheet, headerRow, ['指标', '金额（元）']);

  const summary = detail.summary ?? detail;
  let dataRow = headerRow + 1;
  SUMMARY_METRICS.forEach((metric, idx) => {
    const labelCell = sheet.getCell(dataRow, 1);
    const moneyCell = sheet.getCell(dataRow, 2);
    applyTextCell(labelCell, metric.label);
    applyMoneyCell(moneyCell, summary[metric.key]);
    moneyCell.font = { bold: true, size: metric.highlight ? 12 : 11 };
    if (metric.highlight) {
      labelCell.font = { bold: true, color: { argb: 'FF1F4E79' } };
      moneyCell.font = { bold: true, size: 13, color: { argb: 'FF1F4E79' } };
      const fill = {
        type: 'pattern' as const,
        pattern: 'solid' as const,
        fgColor: { argb: 'FFE8F0FE' },
      };
      labelCell.fill = fill;
      moneyCell.fill = fill;
    } else if (idx % 2 === 1) {
      const zebra = {
        type: 'pattern' as const,
        pattern: 'solid' as const,
        fgColor: { argb: 'FFF2F2F2' },
      };
      labelCell.fill = zebra;
      moneyCell.fill = zebra;
    }
    sheet.getRow(dataRow).height = 24;
    dataRow += 1;
  });

  // 口径说明行
  sheet.mergeCells(dataRow, 1, dataRow, 2);
  const noteCell = sheet.getCell(dataRow, 1);
  noteCell.value = MEDICINE_SCOPE_NOTE;
  noteCell.font = { size: 10, color: { argb: 'FF64748B' } };
  noteCell.alignment = { wrapText: true, vertical: 'middle' };
  sheet.getRow(dataRow).height = 36;
  dataRow += 1;

  autoFitColumns(sheet, layoutCols, 1, dataRow - 1, 14, 28);
  freezeAt(sheet, headerRow);
}

/**
 * Sheet2：诊所明细 + 底部合计行
 */
function buildStoreSheet(
  workbook: ExcelJS.Workbook,
  detail: Record<string, any>,
  exportedAt: Date,
) {
  const sheet = workbook.addWorksheet('诊所明细', {
    views: [{ showGridLines: true }],
  });
  const colCount = STORE_HEADERS.length;
  writeTitleRow(sheet, colCount, '萧康云医 · 部门财务 · 诊所明细');
  const headerRow = writeReportInfoBlock(sheet, detail, colCount, exportedAt);
  writeHeaderRow(sheet, headerRow, STORE_HEADERS);

  const stores: Record<string, any>[] = detail.stores ?? [];
  const dataStart = headerRow + 1;
  stores.forEach((store, rowIdx) => {
    const r = dataStart + rowIdx;
    applyTextCell(sheet.getCell(r, 1), store.store_name);
    STORE_MONEY_KEYS.forEach((key, i) => {
      applyMoneyCell(sheet.getCell(r, i + 2), store[key]);
    });
    if (rowIdx % 2 === 1) {
      for (let c = 1; c <= colCount; c++) {
        sheet.getCell(r, c).fill = {
          type: 'pattern',
          pattern: 'solid',
          fgColor: { argb: 'FFF2F2F2' },
        };
      }
    }
    sheet.getRow(r).height = 22;
  });

  const dataEnd = dataStart + Math.max(stores.length, 1) - 1;
  const summaryRow = (stores.length > 0 ? dataEnd : headerRow) + 2;

  // 合计行
  const sumFill = {
    type: 'pattern' as const,
    pattern: 'solid' as const,
    fgColor: { argb: 'FFFFF9E6' },
  };
  const titleCell = sheet.getCell(summaryRow, 1);
  titleCell.value = '合计';
  titleCell.font = { bold: true, size: 11 };
  titleCell.fill = sumFill;
  titleCell.border = DOUBLE_TOP_BORDER;
  titleCell.alignment = { horizontal: 'center', vertical: 'middle' };

  STORE_MONEY_KEYS.forEach((key, i) => {
    const cell = sheet.getCell(summaryRow, i + 2);
    const sum = stores.reduce((acc, s) => acc + toMoney(s[key]), 0);
    cell.value = sum;
    cell.numFmt = '#,##0.00';
    cell.font = { bold: true };
    cell.fill = sumFill;
    cell.border = DOUBLE_TOP_BORDER;
    cell.alignment = { horizontal: 'right', vertical: 'middle' };
  });
  sheet.getRow(summaryRow).height = 24;

  autoFitColumns(sheet, colCount, headerRow, summaryRow, 10, 22);
  freezeAt(sheet, headerRow);
}

/**
 * Sheet3：药品供货明细，按诊所分组标题行
 */
function buildDrugSheet(
  workbook: ExcelJS.Workbook,
  detail: Record<string, any>,
  drugRows: DepartmentFinanceDrugRow[],
  exportedAt: Date,
) {
  const sheet = workbook.addWorksheet('药品供货明细', {
    views: [{ showGridLines: true }],
  });
  const colCount = DRUG_HEADERS.length;
  writeTitleRow(sheet, colCount, '萧康云医 · 部门财务 · 药品供货明细');
  const headerRow = writeReportInfoBlock(sheet, detail, colCount, exportedAt);
  writeHeaderRow(sheet, headerRow, DRUG_HEADERS);

  // 按诊所分组，保持接口返回顺序
  const groups = new Map<string, DepartmentFinanceDrugRow[]>();
  for (const row of drugRows) {
    const name = row.store_name || '未知诊所';
    if (!groups.has(name)) groups.set(name, []);
    groups.get(name)!.push(row);
  }

  let r = headerRow + 1;
  let zebra = 0;
  for (const [storeName, rows] of groups) {
    // 分组标题行
    sheet.mergeCells(r, 1, r, colCount);
    const groupCell = sheet.getCell(r, 1);
    groupCell.value = `诊所：${storeName}（${rows.length} 条）`;
    groupCell.font = { bold: true, size: 11, color: { argb: 'FF1F4E79' } };
    groupCell.fill = {
      type: 'pattern',
      pattern: 'solid',
      fgColor: { argb: 'FFE8F0FE' },
    };
    groupCell.alignment = { horizontal: 'left', vertical: 'middle' };
    groupCell.border = THIN_BORDER;
    for (let c = 2; c <= colCount; c++) {
      sheet.getCell(r, c).border = THIN_BORDER;
      sheet.getCell(r, c).fill = {
        type: 'pattern',
        pattern: 'solid',
        fgColor: { argb: 'FFE8F0FE' },
      };
    }
    sheet.getRow(r).height = 24;
    r += 1;

    for (const drug of rows) {
      applyTextCell(sheet.getCell(r, 1), drug.store_name);
      applyTextCell(sheet.getCell(r, 2), drug.drug_number);
      applyTextCell(sheet.getCell(r, 3), drug.drug_name);
      applyTextCell(sheet.getCell(r, 4), drug.type_txt, 'center');
      applyIntCell(sheet.getCell(r, 5), drug.number);
      applyMoneyCell(sheet.getCell(r, 6), drug.market_price);
      applyMoneyCell(sheet.getCell(r, 7), drug.total_supply_price);
      if (zebra % 2 === 1) {
        for (let c = 1; c <= colCount; c++) {
          sheet.getCell(r, c).fill = {
            type: 'pattern',
            pattern: 'solid',
            fgColor: { argb: 'FFF2F2F2' },
          };
        }
      }
      sheet.getRow(r).height = 22;
      r += 1;
      zebra += 1;
    }
  }

  if (drugRows.length === 0) {
    sheet.mergeCells(r, 1, r, colCount);
    applyTextCell(sheet.getCell(r, 1), '暂无药品供货明细', 'center');
    r += 1;
  }

  autoFitColumns(sheet, colCount, headerRow, Math.max(r - 1, headerRow), 10, 36);
  freezeAt(sheet, headerRow);
}

/**
 * 根据详情 + 药品行生成美化后的 xlsx buffer
 */
export async function exportDepartmentFinanceExcel(
  detail: Record<string, any>,
  drugRows: DepartmentFinanceDrugRow[],
  exportedAt = new Date(),
): Promise<ArrayBuffer> {
  const workbook = new ExcelJS.Workbook();
  workbook.creator = '萧康云医';
  workbook.created = exportedAt;

  buildSummarySheet(workbook, detail, exportedAt);
  buildStoreSheet(workbook, detail, exportedAt);
  buildDrugSheet(workbook, detail, drugRows, exportedAt);

  return workbook.xlsx.writeBuffer() as Promise<ArrayBuffer>;
}

/** 安全文件名 */
export function exportDepartmentFinanceFilename(reportNo: string): string {
  const safe = String(reportNo || 'report').replace(/[\\/:*?"<>|]+/g, '_');
  return `部门财务报表_${safe}.xlsx`;
}

/**
 * 拉取详情与各诊所药品明细，生成并下载 Excel
 * 为什么串行拉药品：与后台导出口径一致，避免并发打爆接口
 */
export async function buildAndDownloadDepartmentFinanceExcel(
  reportId: number,
): Promise<void> {
  const detail = await getDepartmentFinanceReportDetailApi(reportId);
  if (!detail) {
    throw new Error('报表不存在');
  }
  const drugRows: DepartmentFinanceDrugRow[] = [];
  const stores: Record<string, any>[] = detail.stores ?? [];
  for (const store of stores) {
    const res = await getDepartmentFinanceStoreDrugDetailApi({
      store_id: store.store_id,
      report_id: reportId,
    });
    for (const drug of res?.items ?? []) {
      drugRows.push({
        store_name: store.store_name,
        drug_number: drug.drug_number,
        drug_name: drug.drug_name,
        type_txt: drug.type_txt,
        number: drug.number,
        market_price: drug.market_price,
        total_supply_price: drug.total_supply_price,
      });
    }
  }
  const buffer = await exportDepartmentFinanceExcel(detail, drugRows);
  downloadByData(
    buffer,
    exportDepartmentFinanceFilename(detail.report_no),
    XLSX_MIME,
  );
}
