/**
 * @name 租赁业务台账
 * 设计规范：ledger-shared/DESIGN.md · vm-page + ldb-page
 */
import '../vehicle-management/style.css';
import './styles/index.css';
import React, { useCallback, useMemo, useState } from 'react';
import { Archive, Download, FileUp, Save } from 'lucide-react';
import {
  type AnnotationDirectoryRouteNode,
  type AnnotationSourceDocument,
  type AnnotationViewerOptions
} from '@axhub/annotation';
import { PrototypeAnnotationHost } from '../../common/prototype-annotation-host';
import seedRows from './data/rows.json';
import seedReceipts from './data/receipts.json';
import seedReturnSettlementFees from './data/return-settlement-fees.json';
import seedMaintenanceLedger from './data/maintenance-ledger-records.json';
import seedBiMileage from './data/bi-mileage.json';
import seedHydrogenFees from './data/hydrogen-fees.json';
import { FilterPanel } from './components/FilterPanel';
import { LedgerKpiRow } from './components/LedgerKpiRow';
import { LeaseLedgerTable } from './components/LeaseLedgerTable';
import { ReceiptLinkModal } from './components/ReceiptLinkModal';
import { TablePagination, DEFAULT_PAGE_SIZE } from '../../common/TablePagination';
import {
  EMPTY_LEASE_FILTERS,
  type BiMileageRecord,
  type HydrogenFeeRecord,
  type LeaseLedgerFilters,
  type LeaseLedgerRow,
  type ListViewMode,
  type MaintenanceLedgerRecord,
  type ReceiptRecord,
  type ReturnSettlementFeeRecord,
} from './types';
import {
  applyLeaseFilters,
  applyListViewFilter,
  canStaffEditRow,
  enrichLeaseRow,
  filterRecordsByRole,
  latestReceiptPaymentDate,
  CURRENT_STAFF_USER,
  sumLeaseKpi,
} from './utils/ledger';
import { LeaseLedgerImportModal } from './components/LeaseLedgerImportModal';
import {
  applyLedgerImportToRow,
  createDraftLedgerRowFromImport,
  downloadLedgerBatchImportTemplate,
  matchLedgerImportRow,
  parseLedgerBatchImportFile,
} from './utils/ledger-batch-import';
import annotationSourceDocument from './annotation-source.json';

const RETURN_SETTLEMENT_FEES = seedReturnSettlementFees as ReturnSettlementFeeRecord[];
const MAINTENANCE_LEDGER_RECORDS = seedMaintenanceLedger as MaintenanceLedgerRecord[];
const BI_MILEAGE = seedBiMileage as BiMileageRecord[];
const HYDROGEN_FEES = seedHydrogenFees as HydrogenFeeRecord[];

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

function mapRows(rows: LeaseLedgerRow[], receipts: ReceiptRecord[]): LeaseLedgerRow[] {
  return rows.map((row) => enrichLeaseRow(row, {
    returnSettlementFees: RETURN_SETTLEMENT_FEES,
    maintenanceLedgerRecords: MAINTENANCE_LEDGER_RECORDS,
    biMileage: BI_MILEAGE,
    hydrogenFees: HYDROGEN_FEES,
    receipts,
  }));
}

export default function LeaseBusinessLedgerApp() {
  const [records, setRecords] = useState<LeaseLedgerRow[]>(() => mapRows(seedRows as LeaseLedgerRow[], seedReceipts as ReceiptRecord[]));
  const [receipts] = useState<ReceiptRecord[]>(seedReceipts as ReceiptRecord[]);
  const [pendingFilters, setPendingFilters] = useState<LeaseLedgerFilters>(EMPTY_LEASE_FILTERS);
  const [appliedFilters, setAppliedFilters] = useState<LeaseLedgerFilters>(EMPTY_LEASE_FILTERS);
  const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
  const [toast, setToast] = useState('');
  const [receiptRow, setReceiptRow] = useState<LeaseLedgerRow | null>(null);
  const [showUnpaidOnly, setShowUnpaidOnly] = useState(false);
  const [listViewMode, setListViewMode] = useState<ListViewMode>('all');
  const [page, setPage] = useState(1);
  const [pageSize, setPageSize] = useState(DEFAULT_PAGE_SIZE);
  const [tableLoading, setTableLoading] = useState(false);
  const [editingRowId, setEditingRowId] = useState<string | null>(null);
  const [importOpen, setImportOpen] = useState(false);

  const showToast = useCallback((msg: string) => {
    setToast(msg);
    window.setTimeout(() => setToast(''), 3000);
  }, []);

  const roleScopedRecords = useMemo(() => filterRecordsByRole(records), [records]);
  const filtered = useMemo(
    () => applyLeaseFilters(records, appliedFilters),
    [records, appliedFilters],
  );
  const listFiltered = useMemo(
    () => applyListViewFilter(filtered, { showUnpaidOnly, listViewMode }),
    [filtered, showUnpaidOnly, listViewMode],
  );
  const kpi = useMemo(() => sumLeaseKpi(applyLeaseFilters(roleScopedRecords, appliedFilters)), [roleScopedRecords, appliedFilters]);
  const totalPages = Math.max(1, Math.ceil(listFiltered.length / pageSize));
  const pagedRecords = useMemo(() => {
    const start = (page - 1) * pageSize;
    return listFiltered.slice(start, start + pageSize);
  }, [listFiltered, page, pageSize]);

  const handleSearch = () => {
    setTableLoading(true);
    window.setTimeout(() => {
      setAppliedFilters(pendingFilters);
      setPage(1);
      setSelectedIds(new Set());
      setTableLoading(false);
    }, 320);
  };

  const handleReset = () => {
    setPendingFilters(EMPTY_LEASE_FILTERS);
    setAppliedFilters(EMPTY_LEASE_FILTERS);
    setPage(1);
    setSelectedIds(new Set());
    setShowUnpaidOnly(false);
    setListViewMode('all');
  };

  const handleSetArchived = () => {
    if (selectedIds.size === 0) {
      showToast('请先勾选需要归档的记录');
      return;
    }
    const ids = new Set(selectedIds);
    const now = formatMaintainerTime();
    setRecords((prev) => mapRows(
      prev.map((row) => {
        if (!ids.has(row.id)) return row;
        return {
          ...row,
          archiveStatus: '已归档' as const,
          maintainerName: CURRENT_STAFF_USER,
          maintainerTime: now,
          operationHistory: [
            ...(row.operationHistory ?? []),
            {
              operatedAt: now,
              operatorName: CURRENT_STAFF_USER,
              field: '账单状态',
              before: row.archiveStatus,
              after: '已归档',
            },
          ],
        };
      }),
      receipts,
    ));
    setEditingRowId(null);
    setSelectedIds(new Set());
    showToast(`已将 ${ids.size} 条记录设置为已归档`);
  };

  const handleSaveUnarchived = () => {
    if (selectedIds.size === 0) {
      showToast('请先勾选需要保存的记录');
      return;
    }
    const ids = new Set(selectedIds);
    const now = formatMaintainerTime();
    setRecords((prev) => mapRows(
      prev.map((row) => {
        if (!ids.has(row.id)) return row;
        return {
          ...row,
          archiveStatus: '未归档' as const,
          maintainerName: CURRENT_STAFF_USER,
          maintainerTime: now,
          operationHistory: [
            ...(row.operationHistory ?? []),
            {
              operatedAt: now,
              operatorName: CURRENT_STAFF_USER,
              field: '账单状态',
              before: row.archiveStatus,
              after: '未归档',
            },
          ],
        };
      }),
      receipts,
    ));
    setEditingRowId(null);
    setSelectedIds(new Set());
    showToast(`已将 ${ids.size} 条记录保存为未归档`);
  };

  const handleReceiptConfirm = (
    recordId: string,
    selectedReceiptIds: string[],
    linkedAmount: number,
    _allocations: Record<string, number>,
  ) => {
    const arrivalTimes = selectedReceiptIds
      .map((id) => receipts.find((r) => r.id === id)?.arrivalTime)
      .filter((v): v is string => Boolean(v));
    const paymentDate = latestReceiptPaymentDate(arrivalTimes);
    const billAmount = Math.min(linkedAmount, records.find((r) => r.id === recordId)?.receivableTotal ?? linkedAmount);

    setRecords((prev) => mapRows(
      prev.map((row) => {
        if (row.id !== recordId) return row;
        const receivedAmount = Math.round((row.receivedAmount + billAmount) * 100) / 100;
        return {
          ...row,
          receivedAmount,
          linkedReceiptIds: [...new Set([...(row.linkedReceiptIds ?? []), ...selectedReceiptIds])],
          actualPaymentDate: paymentDate,
        };
      }),
      receipts,
    ));
    setReceiptRow(null);
    showToast(linkedAmount > billAmount ? '收款关联成功，多出部分请在单据下自行分配' : '收款记录关联成功');
  };

  const handleOtherIncomeItemsChange = (recordId: string, items: LeaseLedgerRow['otherIncomeItems']) => {
    setRecords((prev) => mapRows(
      prev.map((row) => (row.id === recordId ? { ...row, otherIncomeItems: items ?? [] } : row)),
      receipts,
    ));
  };

  const handleOtherDeductionItemsChange = (recordId: string, items: LeaseLedgerRow['otherDeductionItems']) => {
    setRecords((prev) => mapRows(
      prev.map((row) => (row.id === recordId ? { ...row, otherDeductionItems: items ?? [] } : row)),
      receipts,
    ));
  };

  const handleOtherCostChange = (recordId: string, value: number) => {
    setRecords((prev) => mapRows(
      prev.map((row) => (row.id === recordId ? { ...row, otherCost: value } : row)),
      receipts,
    ));
  };

  const handleBrokerageFeeChange = (recordId: string, value: number) => {
    setRecords((prev) => mapRows(
      prev.map((row) => (row.id === recordId ? { ...row, brokerageFee: value } : row)),
      receipts,
    ));
  };

  const handleRemarkChange = (recordId: string, value: string) => {
    setRecords((prev) => mapRows(
      prev.map((row) => (row.id === recordId ? { ...row, remark: value } : row)),
      receipts,
    ));
  };

  const handleDeductionDetailChange = (recordId: string, value: string) => {
    setRecords((prev) => mapRows(
      prev.map((row) => (row.id === recordId ? { ...row, otherDeductionDetail: value } : row)),
      receipts,
    ));
  };

  const handleExemptionPolicyChange = (recordId: string, value: string) => {
    setRecords((prev) => mapRows(
      prev.map((row) => (row.id === recordId ? { ...row, exemptionPolicy: value } : row)),
      receipts,
    ));
  };

  const handleBatchImport = async (file: File) => {
    const text = await file.text();
    const importRows = parseLedgerBatchImportFile(text);
    if (importRows.length === 0) {
      showToast('未识别到有效数据，请使用模板填写必填项及需导入的字段');
      return;
    }

    let updated = 0;
    let created = 0;
    setRecords((prev) => {
      const next = [...prev];
      importRows.forEach((importRow, index) => {
        const hitIndex = next.findIndex((row) => matchLedgerImportRow(row, importRow));
        if (hitIndex >= 0) {
          next[hitIndex] = applyLedgerImportToRow(next[hitIndex], importRow);
          updated += 1;
          return;
        }
        next.push(createDraftLedgerRowFromImport(importRow, index));
        created += 1;
      });
      return mapRows(next, receipts);
    });
    setImportOpen(false);
    const parts: string[] = [];
    if (updated > 0) parts.push(`更新 ${updated} 条`);
    if (created > 0) parts.push(`新增 ${created} 条`);
    showToast(`导入完成：${parts.join('，')}；自动计算字段已重新汇总`);
  };

  const handleListViewChange = (mode: ListViewMode) => {
    setListViewMode(mode);
    setPage(1);
    if (mode === 'unpaid') setShowUnpaidOnly(true);
    if (mode === 'all') setShowUnpaidOnly(false);
  };

  const annotationOptions = useMemo<AnnotationViewerOptions>(
    () => ({
      showToolbar: true,
      showThemeToggle: true,
      showColorFilter: true,
      emptyWhenNoData: false,
      toolbarEdge: 'right',
      currentPageId: 'list',
      onDirectoryRoute: (_node: AnnotationDirectoryRouteNode) => {},
    }),
    [],
  );

  return (
    <>
      <div className="vm-page ldb-page">
        <FilterPanel
          records={records}
          filters={pendingFilters}
          onChange={(patch) => setPendingFilters((prev) => ({ ...prev, ...patch }))}
          onReset={handleReset}
          onSearch={handleSearch}
        />

        <LedgerKpiRow
          summary={kpi}
          listViewMode={listViewMode}
          onListViewChange={handleListViewChange}
        />

        <section className="vm-table-section">
          <div className="vm-table-toolbar ldb-table-toolbar" data-annotation-id="lbl-toolbar">
            <div className="ldb-toolbar-unpaid-group">
              <label
                className={`ldb-toolbar-unpaid-filter${showUnpaidOnly ? ' is-active' : ''}`}
                aria-label="仅显示未收款数据"
              >
                <input
                  type="checkbox"
                  className="vm-checkbox"
                  checked={showUnpaidOnly}
                  onChange={(e) => {
                    setShowUnpaidOnly(e.target.checked);
                    setListViewMode(e.target.checked ? 'unpaid' : 'all');
                    setPage(1);
                  }}
                />
                <span>仅显示未收款数据</span>
              </label>
            </div>
            <div className="vm-table-actions">
              <button type="button" className="vm-btn vm-btn-secondary ldb-toolbar-btn" data-vm-icon="import" onClick={() => setImportOpen(true)}>
                批量导入
              </button>
              <button type="button" className="vm-btn vm-btn-ghost ldb-toolbar-btn" data-vm-icon="download" onClick={() => showToast(`导出 ${listFiltered.length} 条（原型演示）`)}>
                导出
              </button>
              <button
                type="button"
                className="vm-btn vm-btn-ghost ldb-toolbar-btn"
                data-annotation-id="lbl-btn-save-unarchived"
                onClick={handleSaveUnarchived}
               data-vm-icon="save">保存
              </button>
              <button
                type="button"
                className="vm-btn vm-btn-ghost ldb-toolbar-btn"
                data-annotation-id="lbl-btn-set-archived"
                data-vm-icon="save"
                onClick={handleSetArchived}
              >
                设置为归档
              </button>
            </div>
          </div>

          <div className="vm-table-card">
            <LeaseLedgerTable
              records={pagedRecords}
              loading={tableLoading}
              returnSettlementFees={RETURN_SETTLEMENT_FEES}
              maintenanceLedgerRecords={MAINTENANCE_LEDGER_RECORDS}
              receipts={receipts}
              hydrogenFees={HYDROGEN_FEES}
              selectedIds={selectedIds}
              editingRowId={editingRowId}
              onToggleRow={(id, checked) => {
                setSelectedIds((prev) => {
                  const next = new Set(prev);
                  if (checked) next.add(id);
                  else next.delete(id);
                  return next;
                });
              }}
              onToggleAll={(checked) => {
                setSelectedIds(checked ? new Set(listFiltered.map((r) => r.id)) : new Set());
              }}
              onEdit={(row) => {
                if (!canStaffEditRow(row)) {
                  showToast('仅草稿状态的数据可以编辑');
                  return;
                }
                setEditingRowId(row.id);
                showToast(`正在编辑 ${row.plateNo}，完成后请点击保存`);
              }}
              onSave={(row) => {
                const now = formatMaintainerTime();
                setRecords((prev) => mapRows(
                  prev.map((item) => {
                    if (item.id !== row.id) return item;
                    return {
                      ...item,
                      archiveStatus: '未归档' as const,
                      maintainerName: CURRENT_STAFF_USER,
                      maintainerTime: now,
                      operationHistory: [
                        ...(item.operationHistory ?? []),
                        {
                          operatedAt: now,
                          operatorName: CURRENT_STAFF_USER,
                          field: '账单状态',
                          before: item.archiveStatus,
                          after: '未归档',
                        },
                      ],
                    };
                  }),
                  receipts,
                ));
                setEditingRowId(null);
                showToast(`已保存 ${row.plateNo}，账单状态已设为未归档`);
              }}
              onLinkReceipt={(row) => setReceiptRow(row)}
              onOtherIncomeItemsChange={handleOtherIncomeItemsChange}
              onOtherDeductionItemsChange={handleOtherDeductionItemsChange}
              onOtherCostChange={handleOtherCostChange}
              onBrokerageFeeChange={handleBrokerageFeeChange}
              onRemarkChange={handleRemarkChange}
              onDeductionDetailChange={handleDeductionDetailChange}
              onExemptionPolicyChange={handleExemptionPolicyChange}
            />
            <div className="vm-table-footer ldb-table-footer">
              <TablePagination
                page={Math.min(page, totalPages)}
                pageSize={pageSize}
                total={listFiltered.length}
                onPageChange={setPage}
                onPageSizeChange={(size) => {
                  setPageSize(size);
                  setPage(1);
                }}
              />
            </div>
          </div>
        </section>

        {toast && <div className="vm-toast" role="status">{toast}</div>}
      </div>

      <ReceiptLinkModal
        key={receiptRow?.id ?? 'closed'}
        open={Boolean(receiptRow)}
        record={receiptRow}
        receipts={receipts}
        onClose={() => setReceiptRow(null)}
        onConfirm={handleReceiptConfirm}
      />
      <LeaseLedgerImportModal
        open={importOpen}
        onClose={() => setImportOpen(false)}
        onDownloadTemplate={downloadLedgerBatchImportTemplate}
        onImport={handleBatchImport}
      />
      <PrototypeAnnotationHost source={annotationSourceDocument as AnnotationSourceDocument} options={annotationOptions} />
    </>
  );
}
