import type {
  AccidentRecord,
  AssetOwnership,
  BiMileageRecord,
  HydrogenFeeRecord,
  LeaseDetailStatus,
  LeaseLedgerFilters,
  LeaseLedgerRow,
  LeaseKpiSummary,
  ListViewMode,
  MaintenanceBearBy,
  MaintenanceLedgerRecord,
  MaintenanceOrder,
  ReceiptRecord,
  ReturnSettlementFeeRecord,
} from '../types';
import { RETURN_SETTLEMENT_OPS_FEE_ITEMS } from './constants';

/** 原型：车牌主数据（导入/新增时按车牌自动匹配品牌型号） */
export const PLATE_VEHICLE_MAP: Record<string, { brand: string; model: string }> = {
  沪A32896F: { brand: '苏龙', model: '18T' },
  沪A61121F: { brand: '苏龙', model: '18T' },
  沪A69695F: { brand: '苏龙', model: '18T' },
  粤AGF4535: { brand: '现代', model: '4.5T/交投' },
  沪A65889F: { brand: '苏龙', model: '18T' },
  浙F08991F: { brand: '飞驰', model: '18T' },
  浙F05580F: { brand: '苏龙', model: '18T' },
  沪A50990F: { brand: '苏龙', model: '18T' },
};

/** 原型：按车牌匹配客户与项目 */
export const PLATE_CONTRACT_MAP: Record<string, { customerName: string; projectName: string }> = {
  沪A32896F: { customerName: '安徽驰远供应链管理有限公司', projectName: '安徽驰远供应链管租赁项目' },
  沪A61121F: { customerName: '安徽驰远供应链管理有限公司', projectName: '安徽驰远供应链管租赁项目' },
  沪A69695F: { customerName: '安徽驰远供应链管理有限公司', projectName: '安徽驰远供应链管租赁项目' },
  粤AGF4535: { customerName: '嘉兴港区韵达快递有限公司', projectName: '嘉兴港区韵达租赁项目' },
  沪A65889F: { customerName: '嘉兴港区韵达快递有限公司', projectName: '嘉兴港区韵达租赁项目' },
  浙F08991F: { customerName: '上海利合供应链管理有限公司', projectName: '上海利合供应链租赁项目' },
  浙F05580F: { customerName: '上海朔宇物流有限公司', projectName: '上海朔宇物流租赁项目' },
  沪A50990F: { customerName: '苏州望亭远方物流有限公司', projectName: '苏州望亭远方物流租赁项目' },
};

/** 原型：租赁合同甲方（签约公司） */
export const PLATE_SIGNING_COMPANY: Record<string, string> = {
  沪A32896F: '浙江羚牛氢能科技有限公司',
  沪A61121F: '浙江羚牛氢能科技有限公司',
  沪A69695F: '浙江羚牛氢能科技有限公司',
  粤AGF4535: '浙江羚牛氢能科技有限公司',
  沪A65889F: '浙江羚牛氢能科技有限公司',
  浙F08991F: '浙江羚牛氢能科技有限公司',
  浙F05580F: '浙江羚牛氢能科技有限公司',
  沪A50990F: '浙江羚牛氢能科技有限公司',
};

/** 原型：资产实际归属公司 */
export const PLATE_ASSET_OWNER: Record<string, string> = {
  沪A32896F: '安吉天地物流科技有限公司',
  沪A61121F: '安吉天地物流科技有限公司',
  沪A69695F: '安吉天地物流科技有限公司',
  粤AGF4535: '广州开发区交投氢能运营管理有限公司',
  沪A65889F: '羚牛新能源科技（上海）有限公司',
  浙F08991F: '浙江羚牛氢能科技有限公司',
  浙F05580F: '上海宇速物流有限公司',
  沪A50990F: '上海宇速物流有限公司',
};

/** 原型：车型标准成本（固定成本） */
export const PLATE_STANDARD_COST: Record<string, number> = {
  沪A32896F: 3900,
  沪A61121F: 3900,
  沪A69695F: 3900,
  粤AGF4535: 1500,
  沪A65889F: 3900,
  浙F08991F: 3000,
  浙F05580F: 3900,
  沪A50990F: 3900,
};

/** 原型：车牌增值服务（签订合同时勾选，一行一项） */
export const PLATE_VALUE_ADDED: Record<string, string[]> = {
  沪A32896F: ['GPS 定位服务', '商业险代办'],
  沪A61121F: ['ETC 办卡'],
  沪A69695F: ['GPS 定位服务'],
  粤AGF4535: ['氢气卡充值代办'],
  沪A65889F: ['GPS 定位服务', '年检代办'],
  浙F08991F: ['GPS 定位服务', 'ETC 办卡', '商业险代办'],
  浙F05580F: ['GPS 定位服务'],
  沪A50990F: ['ETC 办卡', '商业险代办'],
};

export const HYDROGEN_FEE_HEADER_TIP = '仅显示签订合同时氢费承担方式为「我司承担」的氢费在该账单期内的总和，取自车辆氢费明细所有状态的数据（包含未对账和已对账）';

/** 资产归属类型（内部） */
export const PLATE_ASSET_OWNERSHIP: Record<string, AssetOwnership> = {
  沪A32896F: '租赁',
  沪A61121F: '租赁',
  沪A69695F: '租赁',
  粤AGF4535: '租赁',
  沪A65889F: '自有',
  浙F08991F: '自有',
  浙F05580F: '挂靠',
  沪A50990F: '自有',
};

export const IS_SUPERVISOR = false;
export const CURRENT_STAFF_USER = '刘念念';
export const DEFAULT_MAINTAINER_TIME = '2026-01-10 14:30';
export const DEFAULT_MILEAGE_DEDUCTION_RATE = 0.5;

export const LOAD_BATCH_SIZE = 20;

export function formatMoney(value: number): string {
  return value.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
}

/** 表格/卡片空值：不展示占位横杠 */
export function isBlankDisplayValue(value: unknown): boolean {
  return value === null
    || value === undefined
    || value === ''
    || value === '—'
    || value === '-'
    || value === '/';
}

export function formatBillingYearMonth(
  year: number | null | undefined,
  month: number | null | undefined,
): string {
  if (year == null || month == null) return '';
  return `${year}-${String(month).padStart(2, '0')}`;
}

function parseDateOnly(raw: string): Date | null {
  if (isBlankDisplayValue(raw)) return null;
  const datePart = String(raw).trim().split(' ')[0];
  const parts = datePart.split('-');
  if (parts.length < 3) return null;
  const date = new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
  return Number.isNaN(date.getTime()) ? null : date;
}

function formatDateOnly(date: Date): string {
  return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
}

function getDaysInMonth(year: number, month: number): number {
  return new Date(year, month, 0).getDate();
}

function addMonths(date: Date, months: number): Date {
  const next = new Date(date);
  next.setMonth(next.getMonth() + months);
  return next;
}

function isInBillMonth(dateText: string, year: number, month: number): boolean {
  const date = parseDateOnly(dateText);
  if (!date) return false;
  return date.getFullYear() === year && date.getMonth() + 1 === month;
}

function roundMoney(value: number): number {
  return Math.round(value * 100) / 100;
}

function sumLineItems(items: { amount: number }[] | undefined): number {
  return roundMoney((items ?? []).reduce((sum, item) => sum + item.amount, 0));
}

/** 账单月内租赁起始日：月前已提车取当月 1 日，月内提车取提车日 */
export function calcPeriodStartDate(
  row: Pick<LeaseLedgerRow, 'year' | 'month' | 'pickupDate'>,
): string {
  if (!row.year || !row.month) return '';
  const monthStart = `${row.year}-${String(row.month).padStart(2, '0')}-01`;
  const pickupDate = parseDateOnly(row.pickupDate);
  if (!pickupDate) return monthStart;

  const billMonthStart = new Date(row.year, row.month - 1, 1);
  const billMonthEnd = new Date(row.year, row.month, 0);
  if (pickupDate > billMonthEnd) return '';
  if (pickupDate <= billMonthStart) return monthStart;
  return row.pickupDate.split(' ')[0];
}

/** 合同到期日：按租期月数自提车日起算，或取已存储到期日 */
export function calcContractEndDate(
  row: Pick<LeaseLedgerRow, 'pickupDate' | 'contractEndDate' | 'contractEndMode' | 'leaseTermMonths'>,
): string {
  if (row.contractEndMode === 'date' && !isBlankDisplayValue(row.contractEndDate)) {
    return row.contractEndDate.split(' ')[0];
  }
  if (row.leaseTermMonths && !isBlankDisplayValue(row.pickupDate)) {
    const pickupDate = parseDateOnly(row.pickupDate);
    if (pickupDate) {
      return formatDateOnly(addMonths(pickupDate, row.leaseTermMonths));
    }
  }
  if (!isBlankDisplayValue(row.contractEndDate)) {
    return row.contractEndDate.split(' ')[0];
  }
  return '';
}

/** 账单月内租赁天数（用于成本分摊与平均天数） */
export function calcLeaseDaysInMonth(
  row: Pick<LeaseLedgerRow, 'year' | 'month' | 'pickupDate' | 'returnDate' | 'periodStartDate'>,
): number {
  if (!row.year || !row.month) return 0;
  const daysInMonth = getDaysInMonth(row.year, row.month);
  const periodStartText = row.periodStartDate || calcPeriodStartDate(row);
  const periodStart = parseDateOnly(periodStartText);
  if (!periodStart) return 0;

  const monthEnd = new Date(row.year, row.month, 0);
  let periodEnd = monthEnd;
  const returnDate = parseDateOnly(row.returnDate);
  if (returnDate) {
    if (returnDate < periodStart) return 0;
    if (returnDate < periodEnd) periodEnd = returnDate;
  }

  const diffDays = Math.floor((periodEnd.getTime() - periodStart.getTime()) / 86400000) + 1;
  return Math.max(0, Math.min(diffDays, daysInMonth));
}

/** 平均天数 = 账单月租赁天数 / 当月自然日天数 */
export function calcAvgDays(leaseDaysInMonth: number, year: number, month: number): number {
  const daysInMonth = getDaysInMonth(year, month);
  if (!daysInMonth) return 0;
  return roundMoney(leaseDaysInMonth / daysInMonth);
}

/** 交车后设置的开始计费日期：优先取账单起始日期，否则取提车日期 */
export function resolveBillingStartDate(
  row: Pick<LeaseLedgerRow, 'periodStartDate' | 'pickupDate'>,
): string {
  if (row.periodStartDate && !isBlankDisplayValue(row.periodStartDate)) return row.periodStartDate;
  if (row.pickupDate && !isBlankDisplayValue(row.pickupDate)) return row.pickupDate;
  return '';
}

/** 应付款日：首期取开始计费日，后续每期取账单所属自然月 5 日 */
export function calcPaymentDueDate(
  row: Pick<LeaseLedgerRow, 'year' | 'month' | 'periodStartDate' | 'pickupDate'>,
): string {
  if (!row.year || !row.month) return '';
  const billingStart = resolveBillingStartDate(row);
  const billYm = row.year * 100 + row.month;
  const startDate = parseDateOnly(billingStart);
  if (startDate) {
    const startYm = startDate.getFullYear() * 100 + (startDate.getMonth() + 1);
    if (billYm === startYm) {
      return billingStart.split(' ')[0];
    }
  }
  return `${row.year}-${String(row.month).padStart(2, '0')}-05`;
}

export function resolveLinkedPaymentDate(
  row: Pick<LeaseLedgerRow, 'actualPaymentDate' | 'linkedReceiptIds' | 'receivedAmount'>,
): string {
  const hasReceipt = row.receivedAmount > 0
    && ((row.linkedReceiptIds?.length ?? 0) > 0 || !isBlankDisplayValue(row.actualPaymentDate));
  if (!hasReceipt || isBlankDisplayValue(row.actualPaymentDate)) return '';
  return extractReceiptPaymentDate(row.actualPaymentDate);
}

export function displayText(value: unknown): string {
  if (isBlankDisplayValue(value)) return '';
  return String(value);
}

export function displayMoney(value: number | null | undefined, treatZeroAsEmpty = false): string {
  if (value === null || value === undefined) return '';
  if (treatZeroAsEmpty && value === 0) return '';
  return formatMoney(value);
}

export function calcUnreceived(row: Pick<LeaseLedgerRow, 'receivableTotal' | 'receivedAmount'>): number {
  return roundMoney(row.receivableTotal - row.receivedAmount);
}

export function isUnpaidRow(row: LeaseLedgerRow): boolean {
  return row.status !== '已收款';
}

export function resolvePaymentMethod(cycleMonths: number): string {
  const map: Record<number, string> = {
    1: '月度预付',
    3: '季度预付',
    6: '半年预付',
    12: '年度预付',
  };
  return map[cycleMonths] ?? `每${cycleMonths}个月预付`;
}

export function calcMonthlyRent(contractRent: number): number {
  return contractRent;
}

export function calcReceivableRent(contractRent: number, cycleMonths: number): number {
  return roundMoney(contractRent * cycleMonths);
}

/** 根据收款分配金额与应收合计计算账单收款状态 */
export function resolvePaymentStatus(
  receivableTotal: number,
  receivedAmount: number,
): LeaseDetailStatus {
  if (receivedAmount >= receivableTotal && receivableTotal > 0) return '已收款';
  if (receivedAmount > 0) return '部分收款';
  return '未收款';
}

/** @deprecated 使用 resolvePaymentStatus */
export const resolveStatusAfterReceipt = resolvePaymentStatus;

export function filterRecordsByRole(rows: LeaseLedgerRow[]): LeaseLedgerRow[] {
  if (IS_SUPERVISOR) return rows;
  return rows.filter((row) => row.maintainerName === CURRENT_STAFF_USER);
}

export function calcVehicleActualCost(standardCost: number, leaseDaysInMonth: number): number {
  return roundMoney(standardCost * (leaseDaysInMonth / 30));
}

export function calcInsuranceFee(
  purchaseAmount: number | undefined,
  effectiveDays: number | undefined,
  leaseDaysInMonth: number,
): number {
  if (!purchaseAmount || !effectiveDays || effectiveDays <= 0 || leaseDaysInMonth <= 0) return 0;
  return roundMoney((purchaseAmount / effectiveDays) * leaseDaysInMonth);
}

export function calcMileageDeduction(
  gpsMileage: string,
  rate: number | undefined,
): number {
  if (isBlankDisplayValue(gpsMileage)) return 0;
  const mileage = Number(gpsMileage);
  if (!Number.isFinite(mileage) || mileage <= 0) return 0;
  const deductionRate = rate ?? DEFAULT_MILEAGE_DEDUCTION_RATE;
  return roundMoney(mileage * deductionRate);
}

export function lookupBiMileage(
  plateNo: string,
  year: number,
  month: number,
  records: BiMileageRecord[],
): string {
  const hit = records.find((item) => item.plateNo === plateNo && item.year === year && item.month === month);
  return hit ? String(hit.mileageKm) : '';
}

export function getMaintenanceOrdersForBill(
  row: Pick<LeaseLedgerRow, 'plateNo' | 'year' | 'month'>,
  orders: MaintenanceOrder[],
  bearBy?: MaintenanceBearBy,
): MaintenanceOrder[] {
  return orders.filter(
    (item) => item.plateNo === row.plateNo
      && isInBillMonth(item.completedAt, row.year, row.month)
      && (!bearBy || item.bearBy === bearBy),
  );
}

export function sumMaintenanceForBill(
  row: Pick<LeaseLedgerRow, 'plateNo' | 'year' | 'month'>,
  orders: MaintenanceOrder[],
  bearBy: MaintenanceBearBy,
): number {
  return roundMoney(
    getMaintenanceOrdersForBill(row, orders, bearBy)
      .reduce((sum, item) => sum + item.amount, 0),
  );
}

export function getReturnSettlementFeesForBill(
  row: Pick<LeaseLedgerRow, 'plateNo' | 'year' | 'month'>,
  records: ReturnSettlementFeeRecord[],
): ReturnSettlementFeeRecord[] {
  const allowedItems = new Set<string>(RETURN_SETTLEMENT_OPS_FEE_ITEMS);
  return records.filter(
    (item) => item.plateNo === row.plateNo
      && isInBillMonth(item.settlementDate, row.year, row.month)
      && allowedItems.has(item.feeItem),
  );
}

export function sumReturnSettlementOpsFeeForBill(
  row: Pick<LeaseLedgerRow, 'plateNo' | 'year' | 'month'>,
  records: ReturnSettlementFeeRecord[],
): number {
  return roundMoney(
    getReturnSettlementFeesForBill(row, records)
      .reduce((sum, item) => sum + item.amount, 0),
  );
}

export function getMaintenanceLedgerRecordsForBill(
  row: Pick<LeaseLedgerRow, 'plateNo' | 'year' | 'month'>,
  records: MaintenanceLedgerRecord[],
): MaintenanceLedgerRecord[] {
  return records.filter(
    (item) => item.plateNo === row.plateNo
      && isInBillMonth(item.repairDate, row.year, row.month),
  );
}

export function sumMaintenanceLedgerOpsFeeCostForBill(
  row: Pick<LeaseLedgerRow, 'plateNo' | 'year' | 'month'>,
  records: MaintenanceLedgerRecord[],
): number {
  return roundMoney(
    getMaintenanceLedgerRecordsForBill(row, records)
      .reduce((sum, item) => sum + item.totalCost, 0),
  );
}

export function getHydrogenFeesForBill(
  row: Pick<LeaseLedgerRow, 'plateNo' | 'year' | 'month'>,
  records: HydrogenFeeRecord[],
): HydrogenFeeRecord[] {
  return records.filter(
    (item) => item.plateNo === row.plateNo
      && item.year === row.year
      && item.month === row.month
      && item.borneBy === '我司承担',
  );
}

export function sumHydrogenFeeForBill(
  row: Pick<LeaseLedgerRow, 'plateNo' | 'year' | 'month'>,
  records: HydrogenFeeRecord[],
): number {
  return roundMoney(
    getHydrogenFeesForBill(row, records)
      .reduce((sum, item) => sum + (item.totalCost ?? item.amount), 0),
  );
}

export function getLinkedReceiptsForRow(
  row: Pick<LeaseLedgerRow, 'linkedReceiptIds'>,
  receipts: ReceiptRecord[],
): ReceiptRecord[] {
  const linkedIds = row.linkedReceiptIds ?? [];
  return receipts.filter((item) => linkedIds.includes(item.id));
}

export function resolveInvoiceDateFromReceipts(
  row: Pick<LeaseLedgerRow, 'invoiceDate' | 'linkedReceiptIds'>,
  receipts: ReceiptRecord[],
): string {
  const linked = getLinkedReceiptsForRow(row, receipts);
  if (linked.length === 0) {
    return isBlankDisplayValue(row.invoiceDate) ? '' : row.invoiceDate.split(' ')[0];
  }
  const dates = linked
    .map((item) => item.invoiceDate || extractReceiptPaymentDate(item.arrivalTime))
    .filter(Boolean)
    .sort();
  return dates[dates.length - 1] ?? '';
}

export function resolveValueAddedService(plateNo: string): string {
  const services = PLATE_VALUE_ADDED[plateNo] ?? [];
  return services.join('\n');
}

export function calcReceivedAmountFromReceipts(
  linkedIds: string[],
  receipts: { id: string; amount: number }[],
  receivableTotal: number,
): number {
  const total = receipts
    .filter((item) => linkedIds.includes(item.id))
    .reduce((sum, item) => sum + item.amount, 0);
  return Math.min(roundMoney(total), receivableTotal);
}

export function calcMaintenanceIncome(
  row: Pick<LeaseLedgerRow, 'maintenancePackageEnabled' | 'maintenanceUnitPricePerKm' | 'mileage'>,
): number {
  if (!row.maintenancePackageEnabled) return 0;
  return roundMoney(row.maintenanceUnitPricePerKm * row.mileage);
}

export function calcMonthlyIncome(
  row: Pick<
    LeaseLedgerRow,
    'monthlyRent' | 'maintenanceIncome' | 'insuranceSurcharge' | 'opsFeeIncome' | 'otherIncome' | 'mileageDeduction' | 'otherDeduction'
  >,
): number {
  return roundMoney(
    row.monthlyRent
    + row.maintenanceIncome
    + row.insuranceSurcharge
    + row.opsFeeIncome
    + row.otherIncome
    - row.mileageDeduction
    - row.otherDeduction,
  );
}

export function calcReceivableTotal(
  row: Pick<
    LeaseLedgerRow,
    'receivableRent' | 'insuranceSurcharge' | 'opsFeeIncome' | 'otherIncome' | 'mileageDeduction' | 'otherDeduction'
  >,
): number {
  return roundMoney(
    row.receivableRent
    + row.insuranceSurcharge
    + row.opsFeeIncome
    + row.otherIncome
    - row.mileageDeduction
    - row.otherDeduction,
  );
}

export function sumLinkedMaintenanceAmount(
  linkedIds: string[],
  orders: MaintenanceOrder[],
): number {
  return orders
    .filter((item) => linkedIds.includes(item.id) && item.bearBy === '客户承担')
    .reduce((sum, item) => sum + item.amount, 0);
}

export function sumLinkedAccidentSurcharge(
  linkedIds: string[],
  accidents: AccidentRecord[],
): number {
  return accidents
    .filter((item) => linkedIds.includes(item.id))
    .reduce((sum, item) => sum + item.insuranceSurcharge, 0);
}

export function needsMaintenanceLinkWarning(
  row: LeaseLedgerRow,
  orders: MaintenanceOrder[],
): boolean {
  if (!row.isLatestBill || !row.customerBearsMaintenance) return false;
  if (row.linkedMaintenanceIds.length > 0) return false;
  return getMaintenanceOrdersForBill(row, orders, '客户承担').length > 0;
}

export function needsAccidentLinkWarning(
  row: LeaseLedgerRow,
  accidents: AccidentRecord[],
): boolean {
  if (!row.isLatestBill) return false;
  if (row.linkedAccidentIds.length > 0) return false;
  return accidents.some((item) => item.plateNo === row.plateNo);
}

export function enrichLeaseRow(
  row: LeaseLedgerRow,
  options?: {
    maintenanceOrders?: MaintenanceOrder[];
    returnSettlementFees?: ReturnSettlementFeeRecord[];
    maintenanceLedgerRecords?: MaintenanceLedgerRecord[];
    accidentRecords?: AccidentRecord[];
    biMileage?: BiMileageRecord[];
    hydrogenFees?: HydrogenFeeRecord[];
    receipts?: ReceiptRecord[];
  },
): LeaseLedgerRow {
  const vehicle = PLATE_VEHICLE_MAP[row.plateNo];
  const contract = PLATE_CONTRACT_MAP[row.plateNo];
  const typeLine = row.vehicleType || '';
  let brand = row.vehicleBrand;
  let model = row.vehicleModel;
  if (!brand && typeLine) {
    const m = typeLine.match(/^([^\d/]+)(.*)$/);
    if (m?.[2]) {
      brand = m[1];
      model = m[2];
    } else {
      brand = typeLine;
      model = typeLine;
    }
  }

  const cycleMonths = row.paymentCycleMonths || 1;
  const contractRent = row.contractRent;
  const monthlyRent = calcMonthlyRent(contractRent);
  const receivableRent = calcReceivableRent(contractRent, cycleMonths);
  const linkedReceiptIds = row.linkedReceiptIds ?? [];
  const hasReceipt = row.receivedAmount > 0
    && (linkedReceiptIds.length > 0 || !isBlankDisplayValue(row.actualPaymentDate));
  const returnSettlementFees = options?.returnSettlementFees ?? [];
  const maintenanceLedgerRecords = options?.maintenanceLedgerRecords ?? [];
  const accidentRecords = options?.accidentRecords ?? [];
  const biMileage = options?.biMileage ?? [];
  const hydrogenFees = options?.hydrogenFees ?? [];
  const receipts = options?.receipts ?? [];
  const linkedAccidentIds = row.linkedAccidentIds ?? [];

  const periodStartDate = calcPeriodStartDate(row);
  const contractStartDate = isBlankDisplayValue(row.pickupDate) ? '' : row.pickupDate.split(' ')[0];
  const contractEndDate = calcContractEndDate(row);
  const returnDate = isBlankDisplayValue(row.returnDate) ? '' : row.returnDate.split(' ')[0];
  const actualLeaseDays = calcLeaseDaysInMonth({ ...row, periodStartDate });
  const avgDays = calcAvgDays(actualLeaseDays, row.year, row.month);
  const paymentDueDate = calcPaymentDueDate({ ...row, periodStartDate });

  const gpsMileage = lookupBiMileage(row.plateNo, row.year, row.month, biMileage) || row.gpsMileage;
  const mileageDeductionRate = row.mileageDeductionRate;
  const mileageDeduction = calcMileageDeduction(gpsMileage, mileageDeductionRate);
  const otherIncome = sumLineItems(row.otherIncomeItems) || row.otherIncome || 0;
  const otherDeduction = sumLineItems(row.otherDeductionItems) || row.otherDeduction || 0;

  const maintenanceIncome = calcMaintenanceIncome(row);
  const opsFeeIncome = sumReturnSettlementOpsFeeForBill(row, returnSettlementFees);
  const opsFeeCost = sumMaintenanceLedgerOpsFeeCostForBill(row, maintenanceLedgerRecords);
  const insuranceSurcharge = linkedAccidentIds.length > 0
    ? roundMoney(sumLinkedAccidentSurcharge(linkedAccidentIds, accidentRecords))
    : row.insuranceSurcharge;
  const monthlyIncome = calcMonthlyIncome({
    monthlyRent,
    maintenanceIncome,
    insuranceSurcharge,
    opsFeeIncome,
    otherIncome,
    mileageDeduction,
    otherDeduction,
  });
  const receivableTotal = calcReceivableTotal({
    receivableRent,
    insuranceSurcharge,
    opsFeeIncome,
    otherIncome,
    mileageDeduction,
    otherDeduction,
  });

  const vehicleStandardCost = PLATE_STANDARD_COST[row.plateNo] ?? row.vehicleStandardCost;
  const vehicleActualCost = calcVehicleActualCost(vehicleStandardCost, actualLeaseDays);
  const hydrogenFee = row.hydrogenBorneBy === '我司承担'
    ? sumHydrogenFeeForBill(row, hydrogenFees)
    : 0;
  const insuranceFee = calcInsuranceFee(
    row.insurancePurchaseAmount,
    row.insuranceEffectiveDays,
    actualLeaseDays,
  );
  const invoiceDate = resolveInvoiceDateFromReceipts(row, receipts);
  const valueAddedService = resolveValueAddedService(row.plateNo);
  const maintainerTime = row.maintainerTime || DEFAULT_MAINTAINER_TIME;
  const signingCompany = PLATE_SIGNING_COMPANY[row.plateNo] || row.signingCompany;
  const assetOwner = PLATE_ASSET_OWNER[row.plateNo] || row.assetOwner || '';

  const brokerageFee = row.brokerageFee ?? 0;
  const otherCost = row.otherCost ?? 0;
  const totalCost = roundMoney(
    vehicleActualCost + insuranceFee + hydrogenFee + opsFeeCost + brokerageFee + otherCost,
  );
  const profitLoss = roundMoney(monthlyIncome - totalCost);
  const receivedAmount = row.receivedAmount ?? 0;
  const status = resolvePaymentStatus(receivableTotal, receivedAmount);

  return {
    ...row,
    vehicleBrand: brand || vehicle?.brand || '',
    vehicleModel: model || vehicle?.model || '',
    customerName: row.customerName || contract?.customerName || '',
    projectName: row.projectName || contract?.projectName || '',
    paymentCycleMonths: cycleMonths,
    paymentMethod: resolvePaymentMethod(cycleMonths),
    linkedReceiptIds,
    linkedAccidentIds,
    periodStartDate,
    contractStartDate,
    contractEndDate,
    returnDate,
    actualLeaseDays,
    avgDays,
    monthlyRent,
    receivableRent,
    maintenanceIncome,
    opsFeeIncome,
    opsFeeCost,
    insuranceSurcharge,
    otherIncome,
    mileageDeduction,
    otherDeduction,
    monthlyIncome,
    receivableTotal,
    vehicleStandardCost,
    vehicleActualCost,
    gpsMileage,
    hydrogenFee,
    insuranceFee,
    invoiceDate,
    valueAddedService,
    maintainerTime,
    paymentDueDate,
    paymentDate: '',
    totalCost,
    profitLoss,
    signingCompany,
    assetOwner,
    assetOwnership: row.assetOwnership || PLATE_ASSET_OWNERSHIP[row.plateNo] || '自有',
    actualPaymentDate: hasReceipt ? row.actualPaymentDate : '',
    receivedAmount,
    status,
    archiveStatus: row.archiveStatus ?? '未归档',
  };
}

export function canStaffEditRow(row: LeaseLedgerRow): boolean {
  return row.archiveStatus === '草稿';
}

export function canStaffDeleteRow(row: LeaseLedgerRow): boolean {
  return row.status === '未收款';
}

export function sumLeaseKpi(rows: LeaseLedgerRow[]): LeaseKpiSummary {
  return rows.reduce(
    (acc, row) => ({
      count: acc.count + 1,
      receivableTotal: acc.receivableTotal + row.receivableTotal,
      receivedAmount: acc.receivedAmount + row.receivedAmount,
      unreceived: acc.unreceived + calcUnreceived(row),
      totalCost: acc.totalCost + row.totalCost,
      profitLoss: acc.profitLoss + row.profitLoss,
    }),
    { count: 0, receivableTotal: 0, receivedAmount: 0, unreceived: 0, totalCost: 0, profitLoss: 0 },
  );
}

export function applyLeaseFilters(rows: LeaseLedgerRow[], filters: LeaseLedgerFilters): LeaseLedgerRow[] {
  return rows.filter((row) => {
    if (filters.year && String(row.year) !== filters.year) return false;
    if (filters.month && String(row.month) !== filters.month) return false;
    if (filters.dept && row.dept !== filters.dept) return false;
    if (filters.salesman && row.salesman !== filters.salesman) return false;
    if (filters.plateNos.length > 0) {
      const rowPlate = row.plateNo.replace(/\s+/g, '').toUpperCase();
      if (!filters.plateNos.includes(rowPlate)) return false;
    }
    if (filters.status && row.status !== filters.status) return false;
    if (filters.customerName && !row.customerName.includes(filters.customerName)) return false;
    if (filters.paymentFrom && (row.paymentDueDate ?? '') < filters.paymentFrom) return false;
    if (filters.paymentTo && (row.paymentDueDate ?? '') > filters.paymentTo) return false;
    return true;
  });
}

export function applyListViewFilter(
  rows: LeaseLedgerRow[],
  options: { showUnpaidOnly: boolean; listViewMode: ListViewMode },
): LeaseLedgerRow[] {
  if (!options.showUnpaidOnly && options.listViewMode === 'all') return rows;
  return rows.filter(isUnpaidRow);
}

export function buildLeaseOptions(rows: LeaseLedgerRow[], key: keyof LeaseLedgerRow): string[] {
  const set = new Set<string>();
  rows.forEach((row) => {
    const value = row[key];
    if (typeof value === 'string' && value.trim()) set.add(value);
    if (typeof value === 'number') set.add(String(value));
  });
  return Array.from(set).sort((a, b) => a.localeCompare(b, 'zh-CN'));
}

export function extractReceiptPaymentDate(arrivalTime: string): string {
  return arrivalTime.split(' ')[0] || '';
}

export function latestReceiptPaymentDate(arrivalTimes: string[]): string {
  const dates = arrivalTimes.map(extractReceiptPaymentDate).filter(Boolean).sort();
  return dates[dates.length - 1] ?? '';
}
