import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { ArrowDown, ArrowUp, ArrowUpDown, AlertTriangle, CircleHelp } from 'lucide-react';
import type { AccidentRecord, LeaseLedgerRow, MaintenanceOrder } from '../types';
import {
  calcMonthlyIncome,
  calcUnreceived,
  canStaffDeleteRow,
  canStaffEditRow,
  displayMoney,
  displayText,
  formatMoney,
  isBlankDisplayValue,
  needsAccidentLinkWarning,
  needsMaintenanceLinkWarning,
} from '../utils/ledger';
import { LEASE_TABLE_COLUMNS, STATUS_CLASS, type LeaseTableColumn } from './tableColumns';

interface LeaseLedgerTableProps {
  records: LeaseLedgerRow[];
  selectedIds: Set<string>;
  loading?: boolean;
  maintenanceOrders: MaintenanceOrder[];
  accidentRecords: AccidentRecord[];
  onToggleRow: (id: string, checked: boolean) => void;
  onToggleAll: (checked: boolean) => void;
  onEdit: (record: LeaseLedgerRow) => void;
  onDelete: (record: LeaseLedgerRow) => void;
  onLinkReceipt: (record: LeaseLedgerRow) => void;
  onLinkMaintenance: (record: LeaseLedgerRow) => void;
  onLinkAccident: (record: LeaseLedgerRow) => void;
  onOtherIncomeChange: (recordId: string, value: number) => void;
  onOtherCostChange: (recordId: string, value: number) => void;
  onBrokerageFeeChange: (recordId: string, value: number) => void;
  onRemarkChange: (recordId: string, value: string) => void;
  onDeductionDetailChange: (recordId: string, value: string) => void;
}

type SortDir = 'asc' | 'desc';

const CHECK_COL_WIDTH = 48;
const ACTION_COL_WIDTH = 168;

const DEFAULT_COLUMN_WIDTHS: Record<string, number> = {
  _index: 56,
  status: 88,
  maintainerName: 88,
  year: 72,
  month: 64,
  dept: 120,
  paymentDate: 108,
  plateNo: 120,
  customerName: 160,
  valueAddedService: 96,
  exemptionPolicy: 96,
  pickupDate: 108,
  contractStartDate: 116,
  contractEndDate: 116,
  periodStartDate: 108,
  returnDate: 108,
  avgDays: 88,
  deposit: 88,
  contractRent: 112,
  receivableTotal: 112,
  receivableRent: 112,
  monthlyIncome: 112,
  monthlyRent: 112,
  maintenanceIncome: 112,
  insuranceSurcharge: 112,
  opsFeeIncome: 100,
  otherIncome: 100,
  mileageDeduction: 112,
  otherDeduction: 112,
  receivedAmount: 112,
  unreceived: 112,
  invoiceDate: 108,
  actualPaymentDate: 116,
  paymentMethod: 96,
  vehicleStandardCost: 112,
  vehicleActualCost: 112,
  insuranceFee: 96,
  hydrogenFee: 96,
  opsFeeCost: 100,
  brokerageFee: 96,
  otherCost: 96,
  totalCost: 112,
  profitLoss: 112,
  gpsMileage: 96,
  otherDeductionDetail: 160,
  assetOwner: 140,
  signingCompany: 160,
  remark: 140,
};

function IncomeWarning({ title, onClick }: { title: string; onClick: () => void }) {
  return (
    <button type="button" className="ldb-income-warn" title={title} aria-label={title} onClick={onClick}>
      <AlertTriangle size={14} aria-hidden />
    </button>
  );
}

function HeaderWithTip({
  title,
  tip,
  sortable,
  sortActive,
  sortDir,
  onSort,
}: {
  title: string;
  tip?: string;
  sortable?: boolean;
  sortActive?: boolean;
  sortDir?: SortDir;
  onSort?: () => void;
}) {
  const label = (
    <span className="ldb-th-label">
      {title}
      {tip && (
        <span className="ldb-th-tip" tabIndex={0} aria-label={`${title}说明`} onClick={(e) => e.stopPropagation()}>
          <CircleHelp size={14} aria-hidden />
          <span className="ldb-kpi-tooltip" role="tooltip">{tip}</span>
        </span>
      )}
    </span>
  );

  if (!sortable) {
    return tip ? <span className="ldb-th-with-tip">{label}</span> : <>{title}</>;
  }

  return (
    <button type="button" className={`ldb-th-sort ${sortActive ? 'is-active' : ''}`} onClick={onSort}>
      {label}
      <span className="ldb-th-sort-icon" aria-hidden>
        {sortActive
          ? (sortDir === 'asc' ? <ArrowUp size={14} /> : <ArrowDown size={14} />)
          : <ArrowUpDown size={14} />}
      </span>
    </button>
  );
}

function MoneyInput({
  value,
  placeholder,
  required,
  ariaLabel,
  onChange,
}: {
  value: number;
  placeholder?: string;
  required?: boolean;
  ariaLabel: string;
  onChange: (v: number) => void;
}) {
  return (
    <input
      type="number"
      className={`vm-input ldb-income-input tabular-nums ${required && !value ? 'ldb-input-required' : ''}`}
      value={value || ''}
      min={0}
      step={0.01}
      placeholder={placeholder}
      aria-label={ariaLabel}
      aria-required={required}
      onChange={(e) => onChange(Number(e.target.value) || 0)}
    />
  );
}

function TextInput({
  value,
  placeholder,
  ariaLabel,
  onChange,
}: {
  value: string;
  placeholder?: string;
  ariaLabel: string;
  onChange: (v: string) => void;
}) {
  return (
    <input
      type="text"
      className="vm-input ldb-text-input"
      value={value}
      placeholder={placeholder}
      aria-label={ariaLabel}
      onChange={(e) => onChange(e.target.value)}
    />
  );
}

function getSortValue(row: LeaseLedgerRow, col: LeaseTableColumn): string | number {
  switch (col.render) {
    case 'monthly-income':
      return calcMonthlyIncome(row);
    case 'stack-dept':
      return row.dept;
    case 'stack-plate':
      return row.plateNo;
    case 'stack-customer':
      return row.customerName;
    case 'status':
      return row.status;
    default:
      break;
  }
  if (col.key === 'unreceived') return calcUnreceived(row);
  if (col.key === 'profitLoss') return row.profitLoss;
  const raw = row[col.key as keyof LeaseLedgerRow];
  if (typeof raw === 'number') return raw;
  if (typeof raw === 'string') return raw;
  return '';
}

function renderCell(
  row: LeaseLedgerRow,
  col: LeaseTableColumn,
  index: number,
  ctx: {
    maintenanceOrders: MaintenanceOrder[];
    accidentRecords: AccidentRecord[];
    canEdit: boolean;
    onLinkMaintenance: (record: LeaseLedgerRow) => void;
    onLinkAccident: (record: LeaseLedgerRow) => void;
    onOtherIncomeChange: (recordId: string, value: number) => void;
    onOtherCostChange: (recordId: string, value: number) => void;
    onBrokerageFeeChange: (recordId: string, value: number) => void;
    onRemarkChange: (recordId: string, value: string) => void;
    onDeductionDetailChange: (recordId: string, value: string) => void;
  },
) {
  switch (col.render) {
    case 'status':
      return <span className={`ldb-status-tag ${STATUS_CLASS[row.status]}`}>{row.status}</span>;
    case 'stack-dept':
      return (
        <div className="ldb-cell-stack">
          <span className="ldb-cell-primary">{displayText(row.dept)}</span>
          <span className="ldb-cell-secondary">{displayText(row.salesman)}</span>
        </div>
      );
    case 'stack-plate': {
      const vehicleLine = row.vehicleType || [row.vehicleBrand, row.vehicleModel].filter(Boolean).join('');
      return (
        <div className="ldb-cell-stack">
          <span className="ldb-cell-primary tabular-nums">{displayText(row.plateNo)}</span>
          <span className="ldb-cell-secondary" title={vehicleLine}>{displayText(vehicleLine)}</span>
        </div>
      );
    }
    case 'stack-customer':
      return (
        <div className="ldb-cell-stack">
          <span className="ldb-cell-primary" title={row.customerName}>{displayText(row.customerName)}</span>
          <span className="ldb-cell-secondary" title={row.projectName}>{displayText(row.projectName)}</span>
        </div>
      );
    case 'deposit':
      if (isBlankDisplayValue(row.deposit)) return '';
      return typeof row.deposit === 'number' ? formatMoney(row.deposit) : displayText(row.deposit);
    case 'asset-owner':
      return <span title={row.assetOwner}>{displayText(row.assetOwner)}</span>;
    case 'signing-company':
      return <span className="ldb-cell-readonly" title="租赁合同甲方自动获取">{displayText(row.signingCompany)}</span>;
    case 'monthly-income':
      return (
        <span className="ldb-computed-val" title="租金 + 服务费 − 里程减免 − 其他减免">
          {formatMoney(calcMonthlyIncome(row))}
        </span>
      );
    case 'maintenance-income':
      return (
        <span
          className={row.maintenancePackageEnabled ? 'ldb-computed-val' : 'ldb-cell-readonly'}
          title={
            row.maintenancePackageEnabled
              ? `单价 ${row.maintenanceUnitPricePerKm} 元/km × ${row.mileage} km`
              : '合同未勾选维保包干，默认 0 不可编辑'
          }
        >
          {formatMoney(row.maintenanceIncome)}
        </span>
      );
    case 'insurance-surcharge': {
      const warn = needsAccidentLinkWarning(row, ctx.accidentRecords);
      return (
        <div className="ldb-income-cell">
          {warn && (
            <IncomeWarning title="有未关联的事故单据，请点击关联" onClick={() => ctx.onLinkAccident(row)} />
          )}
          <span className={warn ? 'ldb-income-pending' : ''}>{formatMoney(row.insuranceSurcharge)}</span>
        </div>
      );
    }
    case 'ops-fee-income': {
      const warn = needsMaintenanceLinkWarning(row, ctx.maintenanceOrders);
      return (
        <div className="ldb-income-cell">
          {warn && (
            <IncomeWarning title="维修/保养为客户承担，请关联维修保养单" onClick={() => ctx.onLinkMaintenance(row)} />
          )}
          <span className={warn ? 'ldb-income-pending' : ''}>{formatMoney(row.opsFeeIncome)}</span>
        </div>
      );
    }
    case 'ops-fee-cost':
      return (
        <span className="ldb-computed-val" title="与收入侧运维费平进平出">
          {formatMoney(row.opsFeeCost)}
        </span>
      );
    case 'other-income':
      if (!ctx.canEdit) return displayMoney(row.otherIncome, true);
      return (
        <MoneyInput
          value={row.otherIncome}
          placeholder="手工填写"
          ariaLabel={`${row.plateNo} 其他收入`}
          onChange={(v) => ctx.onOtherIncomeChange(row.id, v)}
        />
      );
    case 'other-cost':
      if (!ctx.canEdit) return displayMoney(row.otherCost, true);
      return (
        <MoneyInput
          value={row.otherCost}
          placeholder={row.otherIncome > 0 ? '必填' : '成本侧其他'}
          required={row.otherIncome > 0}
          ariaLabel={`${row.plateNo} 其他成本`}
          onChange={(v) => ctx.onOtherCostChange(row.id, v)}
        />
      );
    case 'brokerage-fee':
      if (!ctx.canEdit) return displayMoney(row.brokerageFee, true);
      return (
        <MoneyInput
          value={row.brokerageFee}
          placeholder="手工填写"
          ariaLabel={`${row.plateNo} 居间费`}
          onChange={(v) => ctx.onBrokerageFeeChange(row.id, v)}
        />
      );
    case 'received-amount':
      return (
        <span title={row.linkedReceiptIds?.length ? `已关联 ${row.linkedReceiptIds.length} 条收款明细` : '关联收款记录后自动归集'}>
          {formatMoney(row.receivedAmount)}
          {row.linkedReceiptIds?.length > 0 && (
            <span className="ldb-linked-badge">{row.linkedReceiptIds.length}</span>
          )}
        </span>
      );
    case 'invoice-date':
      return <span className="ldb-cell-readonly tabular-nums">{displayText(row.invoiceDate)}</span>;
    case 'vehicle-standard-cost':
      return (
        <span className="ldb-cell-readonly" title="车型明细维护的固定标准成本">
          {formatMoney(row.vehicleStandardCost)}
        </span>
      );
    case 'vehicle-actual-cost':
      return (
        <span className="ldb-computed-val" title={`标准成本 × (${row.avgDays}/30)`}>
          {formatMoney(row.vehicleActualCost)}
        </span>
      );
    case 'insurance-readonly':
      return (
        <span className="ldb-cell-readonly" title="暂不可编辑与导入，后续可能自动计算">
          {displayMoney(row.insuranceFee, true)}
        </span>
      );
    case 'hydrogen-fee':
      return (
        <span
          className={row.hydrogenBorneBy === '我司承担' ? 'ldb-computed-val' : 'ldb-cell-readonly'}
          title={row.hydrogenBorneBy === '我司承担' ? '我司承担氢费账单期汇总' : '客户承担或无氢费'}
        >
          {displayMoney(row.hydrogenFee, true)}
        </span>
      );
    case 'gps-mileage':
      return (
        <span className="ldb-computed-val tabular-nums" title="BI 里程 · 账单时间段">
          {displayText(row.gpsMileage)}
        </span>
      );
    case 'deduction-detail':
      if (!ctx.canEdit) return displayText(row.otherDeductionDetail);
      return (
        <TextInput
          value={row.otherDeductionDetail}
          placeholder="减免明细"
          ariaLabel={`${row.plateNo} 其他减免明细`}
          onChange={(v) => ctx.onDeductionDetailChange(row.id, v)}
        />
      );
    case 'remark-text':
      if (!ctx.canEdit) return displayText(row.remark);
      return (
        <TextInput
          value={row.remark}
          placeholder="备注"
          ariaLabel={`${row.plateNo} 备注`}
          onChange={(v) => ctx.onRemarkChange(row.id, v)}
        />
      );
    default:
      break;
  }

  if (col.key === 'unreceived') return formatMoney(calcUnreceived(row));

  if (col.key === 'profitLoss') {
    const val = row.profitLoss;
    return (
      <span className={val >= 0 ? 'ldb-kpi-val--profit' : 'ldb-kpi-val--loss'}>
        {formatMoney(val)}
      </span>
    );
  }

  const raw = col.key === '_index' ? index + 1 : row[col.key as keyof LeaseLedgerRow];
  if (col.money && typeof raw === 'number') return formatMoney(raw);
  if (isBlankDisplayValue(raw)) return '';
  return String(raw);
}

function TableSkeleton() {
  return (
    <div className="ldb-table-skeleton" aria-busy="true" aria-label="表格加载中">
      {Array.from({ length: 6 }, (_, i) => (
        <div key={i} className="ldb-skeleton-row" />
      ))}
    </div>
  );
}

export function LeaseLedgerTable({
  records,
  selectedIds,
  loading = false,
  maintenanceOrders,
  accidentRecords,
  onToggleRow,
  onToggleAll,
  onEdit,
  onDelete,
  onLinkReceipt,
  onLinkMaintenance,
  onLinkAccident,
  onOtherIncomeChange,
  onOtherCostChange,
  onBrokerageFeeChange,
  onRemarkChange,
  onDeductionDetailChange,
}: LeaseLedgerTableProps) {
  const [sortKey, setSortKey] = useState<string | null>(null);
  const [sortDir, setSortDir] = useState<SortDir>('asc');
  const [columnWidths, setColumnWidths] = useState<Record<string, number>>(() => ({ ...DEFAULT_COLUMN_WIDTHS }));
  const resizeRef = useRef<{ key: string; startX: number; startWidth: number } | null>(null);

  const sortedRecords = useMemo(() => {
    if (!sortKey) return records;
    const col = LEASE_TABLE_COLUMNS.find((c) => c.key === sortKey);
    if (!col) return records;
    const dir = sortDir === 'asc' ? 1 : -1;
    return [...records].sort((a, b) => {
      const av = getSortValue(a, col);
      const bv = getSortValue(b, col);
      if (typeof av === 'number' && typeof bv === 'number') return (av - bv) * dir;
      return String(av).localeCompare(String(bv), 'zh-CN') * dir;
    });
  }, [records, sortKey, sortDir]);

  const allSelected = sortedRecords.length > 0 && sortedRecords.every((r) => selectedIds.has(r.id));

  const handleSort = useCallback((key: string) => {
    setSortKey((prev) => {
      if (prev === key) {
        setSortDir((d) => (d === 'asc' ? 'desc' : 'asc'));
        return key;
      }
      setSortDir('asc');
      return key;
    });
  }, []);

  const handleResizeStart = useCallback((key: string, event: React.MouseEvent) => {
    event.preventDefault();
    event.stopPropagation();
    resizeRef.current = {
      key,
      startX: event.clientX,
      startWidth: columnWidths[key] ?? DEFAULT_COLUMN_WIDTHS[key] ?? 100,
    };
  }, [columnWidths]);

  useEffect(() => {
    const onMove = (event: MouseEvent) => {
      if (!resizeRef.current) return;
      const delta = event.clientX - resizeRef.current.startX;
      const next = Math.max(56, resizeRef.current.startWidth + delta);
      setColumnWidths((prev) => ({ ...prev, [resizeRef.current!.key]: next }));
    };
    const onUp = () => {
      resizeRef.current = null;
    };
    window.addEventListener('mousemove', onMove);
    window.addEventListener('mouseup', onUp);
    return () => {
      window.removeEventListener('mousemove', onMove);
      window.removeEventListener('mouseup', onUp);
    };
  }, []);

  if (loading) {
    return (
      <div className="vm-table-wrap ldb-table-wrap" data-annotation-id="lbl-table">
        <TableSkeleton />
      </div>
    );
  }

  if (!sortedRecords.length) {
    return <div className="vm-empty" data-annotation-id="lbl-table"><p>暂无符合条件的台账记录</p></div>;
  }

  const tableMinWidth = CHECK_COL_WIDTH + ACTION_COL_WIDTH + LEASE_TABLE_COLUMNS.reduce(
    (sum, col) => sum + (columnWidths[col.key] ?? DEFAULT_COLUMN_WIDTHS[col.key] ?? 100),
    0,
  );

  return (
    <div className="vm-table-wrap ldb-table-wrap" data-annotation-id="lbl-table">
      <table className="vm-table ldb-table" style={{ minWidth: tableMinWidth }}>
        <colgroup>
          <col style={{ width: CHECK_COL_WIDTH }} />
          {LEASE_TABLE_COLUMNS.map((col) => (
            <col key={col.key} style={{ width: columnWidths[col.key] ?? DEFAULT_COLUMN_WIDTHS[col.key] ?? 100 }} />
          ))}
          <col style={{ width: ACTION_COL_WIDTH }} />
        </colgroup>
        <thead>
          <tr>
            <th className="ldb-col-check sticky-col-left">
              <input type="checkbox" checked={allSelected} onChange={(e) => onToggleAll(e.target.checked)} aria-label="全选" />
            </th>
            {LEASE_TABLE_COLUMNS.map((col) => {
              const sortable = col.sortable !== false && col.key !== '_index';
              return (
                <th
                  key={col.key}
                  className={[
                    col.money ? 'ldb-col-money' : '',
                    col.className,
                    col.sticky === 'left' ? 'sticky-col-left' : '',
                    'ldb-col-resizable',
                  ].filter(Boolean).join(' ')}
                  data-annotation-id={col.annotationId}
                  title={
                    col.key === 'opsFeeIncome'
                      ? '收入侧运维费'
                      : col.key === 'opsFeeCost'
                        ? '成本侧运维费，与收入侧平进平出'
                        : undefined
                  }
                >
                  <div className="ldb-th-inner">
                    <HeaderWithTip
                      title={col.title}
                      tip={col.headerTip}
                      sortable={sortable}
                      sortActive={sortKey === col.key}
                      sortDir={sortDir}
                      onSort={() => handleSort(col.key)}
                    />
                    <span
                      className="ldb-col-resize-handle"
                      role="separator"
                      aria-orientation="vertical"
                      aria-label={`调整${col.title}列宽`}
                      onMouseDown={(e) => handleResizeStart(col.key, e)}
                    />
                  </div>
                </th>
              );
            })}
            <th className="sticky-col-right ldb-col-actions">操作</th>
          </tr>
        </thead>
        <tbody>
          {sortedRecords.map((row, index) => {
            const canEdit = canStaffEditRow(row);
            const canDelete = canStaffDeleteRow(row);
            const isDraft = row.status === '草稿';
            const showReceiptLink = row.status === '已确认' || row.status === '部分收款';
            const cellCtx = {
              maintenanceOrders,
              accidentRecords,
              canEdit,
              onLinkMaintenance,
              onLinkAccident,
              onOtherIncomeChange,
              onOtherCostChange,
              onBrokerageFeeChange,
              onRemarkChange,
              onDeductionDetailChange,
            };

            return (
              <tr key={row.id}>
                <td className="ldb-col-check sticky-col-left">
                  <input
                    type="checkbox"
                    checked={selectedIds.has(row.id)}
                    onChange={(e) => onToggleRow(row.id, e.target.checked)}
                    aria-label={`选择第 ${index + 1} 行`}
                  />
                </td>
                {LEASE_TABLE_COLUMNS.map((col) => (
                  <td
                    key={col.key}
                    className={[
                      col.money ? 'ldb-col-money tabular-nums' : '',
                      col.className,
                      col.sticky === 'left' ? 'sticky-col-left' : '',
                    ].filter(Boolean).join(' ')}
                  >
                    {renderCell(row, col, index, cellCtx)}
                  </td>
                ))}
                <td className="sticky-col-right ldb-col-actions">
                  <div className="ldb-row-actions">
                    {showReceiptLink && (
                      <button type="button" className="ldb-action-btn ldb-action-btn--link" onClick={() => onLinkReceipt(row)}>
                        关联收款
                      </button>
                    )}
                    {canEdit && (
                      <button type="button" className="ldb-action-btn ldb-action-btn--edit" onClick={() => onEdit(row)}>
                        编辑
                      </button>
                    )}
                    {isDraft && canDelete && (
                      <button type="button" className="ldb-action-btn ldb-action-btn--delete" onClick={() => onDelete(row)}>
                        删除
                      </button>
                    )}
                  </div>
                </td>
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
}
