import ExcelJS from 'exceljs';

import type {
  ExportFieldMeta,
  ExportGranularity,
} from '#/views/business/order/product-order/config/exportFields';
import { granularityLabel } from '#/views/business/order/product-order/config/exportFields';

export interface OrderExportFilterInfo {
  search_time: [string, string];
  order_no?: string;
  store_name?: string;
  status_text?: string;
  delivery_method_text?: string;
  prescription_type_text?: string;
  export_fields_text?: string;
  row_count?: number;
}

export interface ExportProductOrderExcelOptions {
  rows: Record<string, unknown>[];
  selectedFields: string[];
  fieldMeta: ExportFieldMeta[];
  filters: OrderExportFilterInfo;
  granularity: ExportGranularity;
  exportedAt?: Date;
}

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 TEXT_KEYS = new Set(['order_no', 'express_mobile', 'epl_order_no']);

function alignOf(meta: ExportFieldMeta): Partial<ExcelJS.Alignment> {
  const horizontal =
    meta.align === 'right'
      ? 'right'
      : meta.align === 'left'
        ? 'left'
        : 'center';
  return { horizontal, vertical: 'middle', wrapText: meta.format === 'text' };
}

function cellValue(row: Record<string, unknown>, key: string, format: ExportFieldMeta['format']) {
  const raw = row[key];
  if (raw === null || raw === undefined || raw === '') {
    return '';
  }
  if (format === 'currency' || format === 'integer') {
    const num = Number(raw);
    return Number.isFinite(num) ? num : raw;
  }
  return String(raw);
}

function applyCellFormat(cell: ExcelJS.Cell, meta: ExportFieldMeta) {
  cell.alignment = alignOf(meta);
  cell.border = THIN_BORDER;
  if (TEXT_KEYS.has(meta.key)) {
    cell.numFmt = '@';
  } else if (meta.format === 'currency') {
    cell.numFmt = '#,##0.00';
  } else if (meta.format === 'datetime') {
    cell.numFmt = 'yyyy-mm-dd hh:mm:ss';
  } else if (meta.format === 'integer') {
    cell.numFmt = '0';
  }
}

function filterRows(filters: OrderExportFilterInfo): {
  pairs: [[string, string], [string, string]][];
  exportFields: [string, string];
  rowCount: [string, string];
} {
  const [start, end] = filters.search_time;
  return {
    pairs: [
      [
        ['时间范围', `${start} ~ ${end}`],
        ['订单号', filters.order_no?.trim() || '全部'],
      ],
      [
        ['门店', filters.store_name?.trim() || '全部'],
        ['订单状态', filters.status_text?.trim() || '全部'],
      ],
      [
        ['发货方式', filters.delivery_method_text?.trim() || '全部'],
        ['订单类型', filters.prescription_type_text?.trim() || '全部'],
      ],
    ],
    exportFields: ['导出字段', filters.export_fields_text || '—'],
    rowCount: [
      '数据条数',
      filters.row_count != null ? `共 ${filters.row_count} 条` : '—',
    ],
  };
}

function styleFilterLabel(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 styleFilterValue(cell: ExcelJS.Cell, value: string, wrapText = false) {
  cell.value = value;
  cell.font = { size: 10 };
  cell.alignment = { horizontal: 'left', vertical: 'middle', wrapText };
  cell.border = THIN_BORDER;
}

/** 一行两个条件：左/右各一组 label|value；right 省略时右侧合并留空 */
function renderFilterPairRow(
  sheet: ExcelJS.Worksheet,
  row: number,
  layoutCols: number,
  left: [string, string],
  right?: [string, string],
) {
  const mid = Math.floor(layoutCols / 2);
  const leftValueEnd = mid;
  const rightLabelCol = mid + 1;
  const rightValueStart = mid + 2;

  styleFilterLabel(sheet.getCell(row, 1), left[0]);
  if (leftValueEnd >= 2) {
    sheet.mergeCells(row, 2, row, leftValueEnd);
  }
  styleFilterValue(sheet.getCell(row, 2), left[1]);

  if (right?.[0]) {
    styleFilterLabel(sheet.getCell(row, rightLabelCol), right[0]);
    if (rightValueStart <= layoutCols) {
      if (rightValueStart < layoutCols) {
        sheet.mergeCells(row, rightValueStart, row, layoutCols);
      }
      styleFilterValue(sheet.getCell(row, rightValueStart), right[1] ?? '');
    }
  } else if (rightLabelCol <= layoutCols) {
    sheet.mergeCells(row, rightLabelCol, row, layoutCols);
    const emptyCell = sheet.getCell(row, rightLabelCol);
    emptyCell.border = THIN_BORDER;
  }
  sheet.getRow(row).height = 20;
}

/** 单行条件：标签 + 值占满剩余列 */
function renderFilterFullRow(
  sheet: ExcelJS.Worksheet,
  row: number,
  layoutCols: number,
  label: string,
  value: string,
  rowHeight = 20,
) {
  styleFilterLabel(sheet.getCell(row, 1), label);
  if (layoutCols >= 2) {
    sheet.mergeCells(row, 2, row, layoutCols);
  }
  styleFilterValue(sheet.getCell(row, 2), value, true);
  sheet.getRow(row).height = rowHeight;
}

function renderFilterBlock(
  sheet: ExcelJS.Worksheet,
  filters: OrderExportFilterInfo,
  startRow: number,
  layoutCols: number,
): number {
  const { pairs, exportFields, rowCount } = filterRows(filters);
  let r = startRow;

  pairs.forEach(([left, right]) => {
    renderFilterPairRow(sheet, r, layoutCols, left, right);
    r += 1;
  });

  renderFilterFullRow(sheet, r, layoutCols, exportFields[0], exportFields[1], 28);
  r += 1;

  renderFilterPairRow(sheet, r, layoutCols, rowCount);
  r += 1;

  return r;
}

function autoFitColumns(
  sheet: ExcelJS.Worksheet,
  colCount: number,
  fieldMeta: ExportFieldMeta[],
  dataStartRow: number,
  dataEndRow: number,
) {
  for (let c = 1; c <= colCount; c++) {
    const meta = fieldMeta[c - 1];
    let maxLen = meta?.label.length ?? 8;
    for (let r = dataStartRow; r <= dataEndRow; r++) {
      const cell = sheet.getCell(r, c);
      const v = cell.value?.toString() ?? '';
      maxLen = Math.max(maxLen, v.length);
    }
    const width = Math.min(Math.max(maxLen * 1.15 + 2, meta?.width ?? 10), 55);
    sheet.getColumn(c).width = width;
  }
}

export async function exportProductOrderExcel(
  options: ExportProductOrderExcelOptions,
): Promise<ArrayBuffer> {
  const {
    rows,
    selectedFields,
    fieldMeta,
    filters,
    granularity,
    exportedAt = new Date(),
  } = options;

  const columns = selectedFields
    .map((key) => fieldMeta.find((f) => f.key === key))
    .filter((f): f is ExportFieldMeta => !!f);

  if (columns.length === 0) {
    throw new Error('请至少选择一个导出字段');
  }

  const workbook = new ExcelJS.Workbook();
  workbook.creator = '萧康云医';
  const sheetName = granularity === 'item' ? '商品明细' : '商品订单';
  const sheet = workbook.addWorksheet(sheetName, {
    views: [{ showGridLines: true }],
  });

  const colCount = columns.length;
  const layoutCols = Math.max(colCount, 4);

  // Row 1: title
  sheet.mergeCells(1, 1, 1, layoutCols);
  const titleCell = sheet.getCell(1, 1);
  titleCell.value = `萧康云医 · 商品订单导出报表（${granularityLabel(granularity)}）`;
  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;

  // Row 2: meta
  const metaSplit = Math.max(1, Math.floor(layoutCols / 2));
  sheet.mergeCells(2, 1, 2, metaSplit);
  sheet.mergeCells(2, metaSplit + 1, 2, layoutCols);
  const leftMeta = sheet.getCell(2, 1);
  leftMeta.value = `导出时间：${formatDateTime(exportedAt)}`;
  leftMeta.font = { size: 10 };
  leftMeta.alignment = { horizontal: 'left', vertical: 'middle' };
  const rightMeta = sheet.getCell(2, metaSplit + 1);
  rightMeta.value = `导出粒度：${granularityLabel(granularity)}`;
  rightMeta.font = { size: 10 };
  rightMeta.alignment = { horizontal: 'right', vertical: 'middle' };
  sheet.getRow(2).height = 22;

  // Filter block: 2 conditions per row (4-col layout minimum)
  const filterStartRow = 3;
  const afterFilterRow = renderFilterBlock(sheet, filters, filterStartRow, layoutCols);

  const headerRowNum = afterFilterRow + 1;
  sheet.getRow(afterFilterRow).height = 8;

  // Header row
  columns.forEach((meta, i) => {
    const cell = sheet.getCell(headerRowNum, i + 1);
    cell.value = meta.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(headerRowNum).height = 30;

  const dataStartRow = headerRowNum + 1;
  rows.forEach((row, rowIdx) => {
    const excelRow = sheet.getRow(dataStartRow + rowIdx);
    columns.forEach((meta, colIdx) => {
      const cell = excelRow.getCell(colIdx + 1);
      cell.value = cellValue(row, meta.key, meta.format) as ExcelJS.CellValue;
      applyCellFormat(cell, meta);
      if (rowIdx % 2 === 1) {
        cell.fill = {
          type: 'pattern',
          pattern: 'solid',
          fgColor: { argb: 'FFF2F2F2' },
        };
      }
    });
    excelRow.height = 22;
  });

  const dataEndRow = dataStartRow + Math.max(rows.length, 1) - 1;

  // Summary row (order granularity)
  let summaryRowNum = dataEndRow + 1;
  if (granularity === 'order' && rows.length > 0) {
    const summaryFields = columns.filter((c) => c.summary);
    if (summaryFields.length > 0) {
      summaryRowNum = dataEndRow + 2;
      sheet.mergeCells(summaryRowNum, 1, summaryRowNum, Math.min(2, colCount));
      const summaryTitle = sheet.getCell(summaryRowNum, 1);
      summaryTitle.value = '汇总';
      summaryTitle.font = { bold: true, size: 11 };
      summaryTitle.fill = {
        type: 'pattern',
        pattern: 'solid',
        fgColor: { argb: 'FFFFF9E6' },
      };
      summaryTitle.border = {
        ...THIN_BORDER,
        top: { style: 'double', color: { argb: 'FF000000' } },
      };

      columns.forEach((meta, colIdx) => {
        const cell = sheet.getCell(summaryRowNum, colIdx + 1);
        cell.border = {
          ...THIN_BORDER,
          top: { style: 'double', color: { argb: 'FF000000' } },
        };
        cell.fill = {
          type: 'pattern',
          pattern: 'solid',
          fgColor: { argb: 'FFFFF9E6' },
        };
        cell.font = { bold: true };

        if (colIdx === 0) {
          cell.value = '汇总';
        } else if (meta.summary) {
          const sum = rows.reduce((acc, row) => {
            const n = Number(row[meta.key]);
            return acc + (Number.isFinite(n) ? n : 0);
          }, 0);
          cell.value = sum;
          applyCellFormat(cell, meta);
        }
      });
      sheet.getRow(summaryRowNum).height = 24;
    }
  }

  autoFitColumns(sheet, colCount, columns, headerRowNum, dataEndRow);

  sheet.autoFilter = {
    from: { row: headerRowNum, column: 1 },
    to: { row: dataEndRow, column: colCount },
  };

  sheet.views = [
    {
      state: 'frozen',
      xSplit: 0,
      ySplit: headerRowNum,
      topLeftCell: `A${headerRowNum + 1}`,
      activeCell: `A${headerRowNum + 1}`,
    },
  ];

  sheet.pageSetup = {
    orientation: 'landscape',
    fitToPage: true,
    fitToWidth: 1,
    fitToHeight: 0,
  };

  return workbook.xlsx.writeBuffer();
}

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())}`;
}

export function exportFilename(
  granularity: ExportGranularity,
  searchTime: [string, string],
): string {
  const g = granularity === 'item' ? '明细' : '订单';
  return `萧康云医-商品订单_${g}_${searchTime[0]}_${searchTime[1]}.xlsx`;
}
