import React, { useEffect, useMemo, useState } from 'react';
import { InputNumber, Modal, Table, Tabs } from 'antd';
import type { ColumnsType } from 'antd/es/table';
import type { BillCandidate, BillType, LinkedBill, PaymentRecord } from '../types';
import { BILL_TYPE_LABELS } from '../types';
import { calcUnclaimedAmount, filterBillsByTypeAndCustomer, formatMoney } from '../utils/payment';

interface BillLinkModalProps {
  open: boolean;
  record: PaymentRecord | null;
  billPool: BillCandidate[];
  onClose: () => void;
  onConfirm: (recordId: string, linkedBills: LinkedBill[]) => void;
}

type BillTab = BillType | 'all';

export function BillLinkModal({ open, record, billPool, onClose, onConfirm }: BillLinkModalProps) {
  const [activeTab, setActiveTab] = useState<BillTab>('all');
  const [selected, setSelected] = useState<Set<string>>(new Set());
  const [allocations, setAllocations] = useState<Record<string, number>>({});

  useEffect(() => {
    if (!open || !record) return;
    const initialSelected = new Set<string>();
    const initialAlloc: Record<string, number> = {};
    record.linkedBills.forEach((bill) => {
      const key = `${bill.type}:${bill.id}`;
      initialSelected.add(key);
      initialAlloc[key] = bill.allocatedAmount;
    });
    setSelected(initialSelected);
    setAllocations(initialAlloc);
    setActiveTab('all');
  }, [open, record?.id]);

  const filteredBills = useMemo(() => {
    if (!record) return [];
    return filterBillsByTypeAndCustomer(billPool, activeTab, record.customerName);
  }, [record, billPool, activeTab]);

  const linkedTotal = useMemo(
    () => Object.values(allocations).reduce((sum, v) => sum + v, 0),
    [allocations],
  );

  const unclaimedBefore = record ? calcUnclaimedAmount(record) : 0;
  const remaining = record
    ? Math.max(0, Math.round((record.amount - linkedTotal) * 100) / 100)
    : 0;

  const toggleBill = (bill: BillCandidate, checked: boolean) => {
    if (!record) return;
    const key = `${bill.type}:${bill.id}`;
    if (!checked) {
      setSelected((prev) => {
        const next = new Set(prev);
        next.delete(key);
        return next;
      });
      setAllocations((prev) => {
        const copy = { ...prev };
        delete copy[key];
        return copy;
      });
      return;
    }
    setSelected((prev) => new Set(prev).add(key));
    setAllocations((prev) => {
      const used = Object.values(prev).reduce((sum, v) => sum + v, 0);
      const room = Math.max(0, record.amount - used);
      const alloc = Math.min(bill.unreceived, room);
      return { ...prev, [key]: alloc };
    });
  };

  const updateAllocation = (key: string, value: number, max: number) => {
    setAllocations((prev) => ({ ...prev, [key]: Math.min(Math.max(0, value), max) }));
  };

  const handleConfirm = () => {
    if (!record) return;
    const linkedBills: LinkedBill[] = Array.from(selected).map((key) => {
      const [type, id] = key.split(':') as [BillType, string];
      const bill = billPool.find((b) => b.id === id && b.type === type);
      return {
        id,
        type,
        label: bill?.label || id,
        period: bill?.period,
        customerName: bill?.customerName,
        projectName: bill?.projectName,
        contractCode: bill?.contractCode,
        allocatedAmount: allocations[key] ?? 0,
      };
    }).filter((b) => b.allocatedAmount > 0);
    onConfirm(record.id, linkedBills);
    setSelected(new Set());
    setAllocations({});
  };

  const columns = useMemo<ColumnsType<BillCandidate>>(() => {
    if (!record) return [];
    return [
      {
        title: '账单类型',
        key: 'type',
        width: 108,
        render: (_, bill) => BILL_TYPE_LABELS[bill.type],
      },
      {
        title: '账单摘要',
        dataIndex: 'label',
        key: 'label',
        width: 220,
        ellipsis: true,
      },
      {
        title: '账期',
        dataIndex: 'period',
        key: 'period',
        width: 120,
        className: 'tabular-nums',
      },
      {
        title: '未收金额',
        key: 'unreceived',
        width: 120,
        align: 'left',
        className: 'tabular-nums',
        render: (_, bill) => formatMoney(bill.unreceived),
      },
      {
        title: '本次认领',
        key: 'alloc',
        width: 140,
        align: 'left',
        render: (_, bill) => {
          const key = `${bill.type}:${bill.id}`;
          const checked = selected.has(key);
          const alloc = allocations[key] ?? 0;
          const maxAlloc = Math.min(bill.unreceived, record.amount);
          if (!checked) return '—';
          return (
            <InputNumber
              size="small"
              className="tabular-nums"
              value={alloc || undefined}
              min={0}
              max={maxAlloc}
              step={0.01}
              precision={2}
              aria-label={`${bill.label} 认领金额`}
              onChange={(value) => updateAllocation(key, Number(value) || 0, maxAlloc)}
            />
          );
        },
      },
    ];
  }, [record, selected, allocations]);

  const tabItems = [
    { key: 'all', label: '全部' },
    { key: 'lease', label: BILL_TYPE_LABELS.lease },
    { key: 'self-operated', label: BILL_TYPE_LABELS['self-operated'] },
    { key: 'clearing', label: BILL_TYPE_LABELS.clearing },
  ];

  return (
    <Modal
      title="关联账单"
      open={open}
      onCancel={onClose}
      onOk={handleConfirm}
      okText="确认关联"
      cancelText="取消"
      okButtonProps={{ disabled: selected.size === 0 }}
      width={920}
      destroyOnClose
      data-annotation-id="pr-bill-link-modal"
    >
      {record ? (
        <>
          <div className="pr-bill-summary">
            <span>客户 <strong>{record.customerName}</strong></span>
            <span>收款金额 <strong className="tabular-nums">{formatMoney(record.amount)}</strong></span>
            <span>当前未认领 <strong className="tabular-nums">{formatMoney(unclaimedBefore)}</strong></span>
            <span>本次认领合计 <strong className="tabular-nums">{formatMoney(linkedTotal)}</strong></span>
            <span>
              认领后剩余{' '}
              <strong className={`tabular-nums ${remaining > 0 ? 'pr-unclaimed--pending' : ''}`}>
                {formatMoney(remaining)}
              </strong>
            </span>
          </div>
          <p className="pr-bill-hint">
            支持单选或多选；可关联租赁账单、自营账单、氢费账单。仅展示与当前客户匹配且仍有未收金额的账单。
          </p>
          <Tabs
            activeKey={activeTab}
            onChange={(key) => setActiveTab(key as BillTab)}
            items={tabItems}
            style={{ marginBottom: 12 }}
          />
          <Table<BillCandidate>
            className="vm-list-table"
            rowKey={(bill) => `${bill.type}:${bill.id}`}
            columns={columns}
            dataSource={filteredBills}
            size="small"
            pagination={false}
            scroll={{ y: 320 }}
            rowSelection={{
              selectedRowKeys: Array.from(selected),
              onSelect: (bill, checked) => toggleBill(bill, checked),
              onSelectAll: (checked, _rows, changeRows) => {
                changeRows.forEach((bill) => toggleBill(bill, checked));
              },
            }}
            locale={{ emptyText: '暂无匹配的账单' }}
          />
        </>
      ) : null}
    </Modal>
  );
}
