import type { LeaseBusinessDetailRow } from '../types';
import { DETAIL_EXPORT_SPECS } from '../components/tableColumns';
import { displayDeposit, displayMoney, displayText } from './detail';
import type { DetailOperator } from './role';

export interface DetailChangeLogEntry {
  id: string;
  operatedAt: string;
  operatorId: string;
  operatorName: string;
  field: string;
  fieldLabel: string;
  before: string;
  after: string;
}

export type DetailChangeLogsByRowId = Record<string, DetailChangeLogEntry[]>;

const EXTRA_FIELD_LABELS: Record<string, string> = {
  archiveStatus: '对账状态',
  reconciledAt: '对账日期',
  _delete: '删除记录',
  _import: '批量导入',
  _reconcile: '完成对账',
};

const FIELD_LABELS: Record<string, string> = Object.fromEntries(
  DETAIL_EXPORT_SPECS.map((spec) => [spec.key, spec.title]),
);

export function resolveFieldLabel(field: string): string {
  return EXTRA_FIELD_LABELS[field] ?? FIELD_LABELS[field] ?? field;
}

const MONEY_FIELDS = new Set<string>([
  'deposit', 'contractRent', 'receivableTotal', 'receivableRent', 'monthlyIncome', 'monthlyRent',
  'maintenanceIncome', 'insuranceSurcharge', 'opsFeeIncome', 'otherIncome', 'mileageDeduction',
  'otherDeduction', 'receivedAmount', 'outstanding', 'vehicleStandardCost', 'vehicleActualCost',
  'insuranceFee', 'hydrogenFee', 'opsFeeCost', 'brokerageFee', 'otherCost', 'totalCost', 'profitLoss',
]);

export function formatLogValue(field: string, value: unknown): string {
  if (field === 'archiveStatus') {
    if (value === 'archived') return '已对账';
    if (value === 'active') return '未对账';
    return displayText(value);
  }
  if (field === 'year' || field === 'month') {
    return value === null || value === undefined || value === '' ? '—' : String(value);
  }
  if (field === 'deposit') return displayDeposit(value as number | string) || '—';
  if (MONEY_FIELDS.has(field) && typeof value === 'number') {
    return displayMoney(value, false) || '0.00';
  }
  if (typeof value === 'number') return String(value);
  return displayText(value) || '—';
}

export function valuesEqualForLog(field: string, before: unknown, after: unknown): boolean {
  return formatLogValue(field, before) === formatLogValue(field, after);
}

const LOGGED_ROW_FIELDS: (keyof LeaseBusinessDetailRow)[] = [
  ...DETAIL_EXPORT_SPECS.map((spec) => spec.key),
  'archiveStatus',
  'reconciledAt',
];

export function createChangeLogEntry(
  operator: DetailOperator,
  field: string,
  before: unknown,
  after: unknown,
  meta?: { fieldLabel?: string; beforeText?: string; afterText?: string; force?: boolean },
): DetailChangeLogEntry | null {
  const beforeText = meta?.beforeText ?? formatLogValue(field, before);
  const afterText = meta?.afterText ?? formatLogValue(field, after);
  if (!meta?.force && beforeText === afterText) return null;

  const now = new Date();
  const operatedAt = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}`;

  return {
    id: `lbd-clog-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
    operatedAt,
    operatorId: operator.id,
    operatorName: operator.name,
    field,
    fieldLabel: meta?.fieldLabel ?? resolveFieldLabel(field),
    before: beforeText,
    after: afterText,
  };
}

export function appendChangeLogs(
  logs: DetailChangeLogsByRowId,
  rowId: string,
  entries: DetailChangeLogEntry[],
): DetailChangeLogsByRowId {
  if (!entries.length) return logs;
  return {
    ...logs,
    [rowId]: [...entries, ...(logs[rowId] ?? [])],
  };
}

export function collectRowChangeLogs(
  operator: DetailOperator,
  before: LeaseBusinessDetailRow,
  after: LeaseBusinessDetailRow,
): DetailChangeLogEntry[] {
  const entries: DetailChangeLogEntry[] = [];
  LOGGED_ROW_FIELDS.forEach((field) => {
    const entry = createChangeLogEntry(operator, field, before[field], after[field]);
    if (entry) entries.push(entry);
  });
  return entries;
}

export function canEditDetailRow(
  row: Pick<LeaseBusinessDetailRow, 'archiveStatus'>,
  isSupervisor: boolean,
): boolean {
  if (row.archiveStatus === 'archived') return isSupervisor;
  return true;
}
