import { useEffect, useMemo, useRef, useState } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { toast } from 'sonner';
import { UserCircleIcon, PlusIcon, TrashIcon } from '@heroicons/react/24/outline';
import { api } from '../../lib/api';
import type { ApiResponse } from '../../lib/api';
import type { BankAccount, Pos } from '../../hooks/usePaymentMethods';
import { formatRial, rialToToman, tomanToRial } from '../../lib/utils';
import { DEFAULT_SERVICE_CATEGORY } from '../../lib/insuranceShares';
import { useAppointmentInsurance } from '../../hooks/useAppointmentInsurance';
import Modal from '../ui/Modal';
import PriceInput from '../ui/PriceInput';
import SearchableSelect from '../ui/SearchableSelect';

/** همان چهار روشِ SessionPayment::METHODS در بک‌اند. */
const METHOD_OPTIONS = [
  { value: 'cash', label: 'پرداخت نقدی' },
  { value: 'pos', label: 'پرداخت از طریق کارت خوان' },
  { value: 'card', label: 'کارت به کارت' },
  { value: 'wallet', label: 'پرداخت از طریق کیف پول' },
];

interface ServiceItem {
  uuid: string;
  name: string;
  price_rials?: number | null;
  service_category?: string | null;
  insurance_covered?: boolean;
}

interface AppointmentLike {
  uuid: string;
  version?: number;
  visit_price_rials?: number | null;
  service_items?: ServiceItem[] | null;
  patient_name?: string | null;
  insurance_service_category?: string | null;
  insurance_base_id?: number | null;
  insurance_supplementary_id?: number | null;
}

interface Props {
  open: boolean;
  appointmentUuid: string;
  /** اگر صفحه از قبل نوبت را دارد، پاس بده تا درخواست اضافه نرود. */
  appointment?: AppointmentLike | null;
  onClose: () => void;
  /** کلید کوئریِ لیستی که بعد از قطعی‌شدن باید invalidate شود. */
  queryKey?: unknown[];
}

/** یک ردیفِ پرداخت در تسویهٔ چندروشی. */
interface PaymentRow {
  id: number;
  method: string;
  amountToman: number;
  /** uuid کارت‌خوان (pos) یا حساب بانکیِ (card) ثبت‌شده. */
  methodUuid: string;
  /** شناسه تراکنش / شماره پیگیری. */
  reference: string;
}

const rowStyle: React.CSSProperties = {
  display: 'flex',
  justifyContent: 'space-between',
  alignItems: 'center',
  gap: 12,
  padding: '9px 0',
  fontSize: 13.5,
  color: 'var(--text-2)',
};

/** رنگ چیپِ «وضعیت پرداخت» بر اساس نسبت پرداخت به جمع کل. */
const STATE_TONE: Record<string, { fg: string; bg: string }> = {
  'بدون پرداخت': { fg: 'var(--text-2)', bg: 'var(--surface-3)' },
  'پرداخت جزئی': { fg: 'var(--warning)', bg: 'var(--warning-bg)' },
  'تسویه کامل': { fg: 'var(--success)', bg: 'var(--success-bg)' },
};

/**
 * «قطعی کردن نوبت» — هزینه‌های نوبت را نشان می‌دهد، پرداخت را بین چند روش
 * (نقدی/کارت‌خوان/کارت‌به‌کارت/کیف پول) تقسیم می‌کند و نوبت را «قطعی» می‌کند.
 *
 * سرور همین یک درخواست را اتمیک انجام می‌دهد: وضعیت + پرونده/مراجعه + پرداخت‌ها.
 * مبلغ پرداختی می‌تواند کمتر از جمع کل باشد (پرداخت جزئی)، ولی نباید بیشتر شود.
 */
export default function ConfirmAppointmentModal({
  open,
  appointmentUuid,
  appointment,
  onClose,
  queryKey,
}: Props) {
  const qc = useQueryClient();
  const nextId = useRef(1);
  const makeRow = (over: Partial<PaymentRow> = {}): PaymentRow => ({
    id: nextId.current++, method: 'cash', amountToman: 0, methodUuid: '', reference: '', ...over,
  });
  const [rows, setRows] = useState<PaymentRow[]>([makeRow()]);
  /** تا وقتی کاربر مبلغ را دست نزده، ردیفِ اول با کل مبلغ پر می‌ماند. */
  const [touched, setTouched] = useState(false);

  // وقتی صفحه‌ی میزبان نوبت را ندارد (مثل ردیف لیست) خودمان جزئیات را می‌گیریم:
  // مبلغ ویزیت و قیمت سرویس‌ها فقط در detail هستند.
  const detailQuery = useQuery({
    queryKey: ['appointment', appointmentUuid],
    queryFn: () => api.get<ApiResponse<AppointmentLike>>(`/api/v1/appointment/${appointmentUuid}`),
    enabled: open && !appointment,
  });

  // روش‌های پرداختِ ثبت‌شده — فقط وقتی مودال باز است.
  const posQuery = useQuery<ApiResponse<Pos[]>>({
    queryKey: ['payment-methods', 'pos'],
    queryFn: () => api.get('/api/v1/my/payment-methods/pos'),
    enabled: open,
  });
  const bankQuery = useQuery<ApiResponse<BankAccount[]>>({
    queryKey: ['payment-methods', 'bank-accounts'],
    queryFn: () => api.get('/api/v1/my/payment-methods/bank-accounts'),
    enabled: open,
  });
  const posOptions = useMemo(
    () => ((posQuery.data?.data ?? []) as Pos[])
      .filter(p => p.is_active)
      .map(p => ({ value: p.uuid, label: `${p.bank_name} — ${p.terminal_number}` })),
    [posQuery.data],
  );
  const bankOptions = useMemo(
    () => ((bankQuery.data?.data ?? []) as BankAccount[])
      .filter(b => b.is_active)
      .map(b => ({ value: b.uuid, label: `${b.bank_name}${b.card_number ? ` — ${b.card_number}` : ''}` })),
    [bankQuery.data],
  );

  const appt: AppointmentLike | null = appointment
    ?? ((detailQuery.data?.data as any)?.data ?? detailQuery.data?.data ?? null);

  // ── بیمه: نوع خدمت + بیمهٔ پایهٔ نوبت ──────────────────────────────────────
  const insurance = useAppointmentInsurance(open);

  // نوبتِ بدون هزینهٔ ویزیت، سرِ ساختِ مراجعه «قیمت ویزیت آزاد» تنظیمات را می‌گیرد؛
  // مودال هم باید همان را نشان دهد، وگرنه صفر نشان می‌دهد و مبلغ ثبت‌شده فرق می‌کند.
  const visitPrice = insurance.visitPriceOf(appt?.visit_price_rials);
  const services = appt?.service_items ?? [];
  const servicesTotal = useMemo(
    () => services.reduce((sum, s) => sum + Number(s.price_rials ?? 0), 0),
    [services],
  );
  const total = visitPrice + servicesTotal;
  const [serviceCategory, setServiceCategory] = useState<string>('');
  const [insuranceId, setInsuranceId] = useState<string>('');
  const [supplementaryId, setSupplementaryId] = useState<string>('');

  // مقدارِ نوبت مبنا است؛ در نبودش نوع پیش‌فرضِ tenant.
  useEffect(() => {
    if (!open) return;
    setServiceCategory(appt?.insurance_service_category ?? insurance.defaultCategory ?? '');
    setInsuranceId(appt?.insurance_base_id ? String(appt.insurance_base_id) : '');
    setSupplementaryId(appt?.insurance_supplementary_id ? String(appt.insurance_supplementary_id) : '');
  }, [open, appt?.uuid, insurance.defaultCategory]);

  const effectiveCategory = serviceCategory || insurance.defaultCategory || DEFAULT_SERVICE_CATEGORY;

  // آینهٔ سرور: ویزیت با نوع انتخابی، هر خدمت با نوع خودش.
  const shares = useMemo(() => insurance.breakdown([
    { total: visitPrice, category: effectiveCategory, insured: true },
    ...services.map(s => ({
      total: Number(s.price_rials ?? 0),
      category: s.service_category ?? DEFAULT_SERVICE_CATEGORY,
      insured: s.insurance_covered !== false,
    })),
  ], insuranceId, supplementaryId), [visitPrice, services, effectiveCategory, insuranceId, supplementaryId, insurance.breakdown]);

  const hasInsurance = !!insuranceId || !!supplementaryId;
  const payable = hasInsurance ? shares.patient : total;

  // ردیفِ اول تا لحظه‌ای که کاربر مبلغ را دستی تغییر ندهد پیش‌فرضِ «پرداخت کامل» است؛
  // نوبت هنوز session ندارد، پس باقی‌مانده‌اش برابر مبلغِ قابل پرداخت است.
  useEffect(() => {
    if (!open || touched || payable <= 0) return;
    setRows(prev => prev.map((r, i) => (i === 0 ? { ...r, amountToman: rialToToman(payable) } : r)));
  }, [open, touched, payable]);

  const paidRials = useMemo(
    () => rows.reduce((sum, r) => sum + tomanToRial(r.amountToman), 0),
    [rows],
  );
  const remaining = Math.max(0, payable - paidRials);
  const overpaid = paidRials > payable;

  const paymentState = paidRials === 0
    ? 'بدون پرداخت'
    : remaining === 0
      ? 'تسویه کامل'
      : 'پرداخت جزئی';

  const confirmMut = useMutation({
    mutationFn: () =>
      api.post<ApiResponse<unknown>>(`/api/v1/appointment/${appointmentUuid}/confirm`, {
        version: appt?.version,
        ...(serviceCategory ? { insurance_service_category: serviceCategory } : {}),
        ...(insuranceId ? { insurance_base_id: Number(insuranceId) } : {}),
        ...(supplementaryId ? { insurance_supplementary_id: Number(supplementaryId) } : {}),
        payments: rows
          .filter(r => tomanToRial(r.amountToman) > 0)
          .map(r => ({
            method: r.method,
            amount_rials: tomanToRial(r.amountToman),
            ...(r.methodUuid ? { payment_method_uuid: r.methodUuid } : {}),
            ...(r.reference.trim() ? { reference: r.reference.trim() } : {}),
          })),
      }),
    onSuccess: () => {
      toast.success('نوبت قطعی شد');
      if (queryKey) qc.invalidateQueries({ queryKey });
      qc.invalidateQueries({ queryKey: ['appointment', appointmentUuid] });
      qc.invalidateQueries({ queryKey: ['appointment-events', appointmentUuid] });
      reset();
      onClose();
    },
    onError: (e: any) => toast.error(e?.message || 'قطعی کردن نوبت ناموفق بود'),
  });

  function reset() {
    nextId.current = 1;
    setRows([makeRow()]);
    setTouched(false);
  }

  function patchRow(id: number, patch: Partial<PaymentRow>) {
    setTouched(true);
    setRows(prev => prev.map(r => (r.id === id ? { ...r, ...patch } : r)));
  }

  /** روش که عوض شد، جزئیاتِ مخصوصِ روشِ قبلی بی‌معنا می‌شود. */
  function changeMethod(id: number, method: string) {
    patchRow(id, { method, methodUuid: '', reference: '' });
  }

  function addRow() {
    setTouched(true);
    // ردیفِ جدید پیش‌فرض با باقی‌مانده پر می‌شود تا تسویه سریع‌تر باشد.
    setRows(prev => [...prev, makeRow({ amountToman: rialToToman(remaining) })]);
  }

  function removeRow(id: number) {
    setTouched(true);
    setRows(prev => (prev.length > 1 ? prev.filter(r => r.id !== id) : prev));
  }

  function handleClose() {
    reset();
    onClose();
  }

  const loading = detailQuery.isLoading && !appointment;

  return (
    <Modal
      open={open}
      title="قطعی کردن نوبت"
      size="md"
      onClose={handleClose}
      footer={
        <>
          <button type="button" className="btn ghost" onClick={handleClose}>
            انصراف
          </button>
          <button
            type="button"
            className="btn primary"
            disabled={loading || overpaid || confirmMut.isPending}
            onClick={() => confirmMut.mutate()}
          >
            {confirmMut.isPending ? 'در حال ثبت…' : 'تأیید و قطعی کردن'}
          </button>
        </>
      }
    >
      {loading ? (
        <p style={{ color: 'var(--text-2)' }}>در حال دریافت اطلاعات نوبت…</p>
      ) : (
        <>
          {appt?.patient_name && (
            <div
              style={{
                display: 'flex', alignItems: 'center', gap: 10, marginBottom: 16,
                padding: '10px 14px', borderRadius: 'var(--r-sm)',
                background: 'var(--primary-soft)',
              }}
            >
              <UserCircleIcon style={{ width: 20, height: 20, color: 'var(--primary-700)', flexShrink: 0 }} />
              <span style={{ fontSize: 13.5, color: 'var(--text-2)' }}>بیمار</span>
              <strong style={{ fontSize: 14, color: 'var(--primary-700)' }}>{appt.patient_name}</strong>
            </div>
          )}

          {/* بیمه — نوع خدمت فقط وقتی چند نوع فعال است پرسیده می‌شود. */}
          <div style={{ display: 'flex', gap: 10, marginBottom: 16, flexWrap: 'wrap' }}>
            {insurance.needsCategoryChoice && (
              <div className="field-block" style={{ flex: 1, minWidth: 180 }}>
                <label>نوع خدمت</label>
                <SearchableSelect
                  value={serviceCategory}
                  onChange={(v) => setServiceCategory(v == null ? '' : String(v))}
                  options={insurance.categoryOptions}
                  placeholder="انتخاب نوع خدمت"
                  height={40}
                />
              </div>
            )}
            <div className="field-block" style={{ flex: 1, minWidth: 180 }}>
              <label>بیمه پایه</label>
              <SearchableSelect
                value={insuranceId}
                onChange={(v) => setInsuranceId(v == null ? '' : String(v))}
                options={insurance.insuranceOptions}
                placeholder="بدون بیمه"
                noOptionsMessage="قرارداد بیمهٔ فعالی ندارید"
                isClearable
                height={40}
              />
            </div>
            {insurance.hasSupplementary && (
              <div className="field-block" style={{ flex: 1, minWidth: 180 }}>
                <label>بیمه تکمیلی</label>
                <SearchableSelect
                  value={supplementaryId}
                  onChange={(v) => setSupplementaryId(v == null ? '' : String(v))}
                  options={insurance.supplementaryOptions}
                  placeholder="بدون بیمه تکمیلی"
                  isClearable
                  height={40}
                />
              </div>
            )}
          </div>

          {/* هزینه‌ها */}
          <div
            style={{
              border: '1px solid var(--border)', borderRadius: 'var(--r)',
              padding: '4px 14px 10px', marginBottom: 20,
            }}
          >
            <div style={rowStyle}>
              <span>ویزیت</span>
              <strong style={{ color: 'var(--text)' }}>{formatRial(visitPrice)}</strong>
            </div>
            {services.map((s) => (
              <div key={s.uuid} style={{ ...rowStyle, borderTop: '1px solid var(--border)' }}>
                <span>{s.name}</span>
                <strong style={{ color: 'var(--text)' }}>{formatRial(Number(s.price_rials ?? 0))}</strong>
              </div>
            ))}
            <div style={{ ...rowStyle, borderTop: '1px solid var(--border)' }}>
              <span>جمع کل</span>
              <strong style={{ color: 'var(--text)' }}>{formatRial(total)}</strong>
            </div>
            {/* سهم‌ها زنجیره‌ای‌اند: پایه روی کل، تکمیلی روی باقیمانده — جدا نشان داده
                می‌شوند تا معلوم باشد هرکدام چقدر برداشته‌اند. */}
            {insuranceId !== '' && (
              <div style={{ ...rowStyle, borderTop: '1px solid var(--border)' }}>
                <span>
                  سهم بیمه پایه
                  {insurance.insuranceNameOf(insuranceId) ? ` — ${insurance.insuranceNameOf(insuranceId)}` : ''}
                  {insurance.categoryLabelOf(effectiveCategory) ? ` (${insurance.categoryLabelOf(effectiveCategory)})` : ''}
                </span>
                <strong style={{ color: 'var(--success)' }}>{formatRial(shares.base)}</strong>
              </div>
            )}
            {supplementaryId !== '' && (
              <div style={{ ...rowStyle, borderTop: '1px solid var(--border)' }}>
                <span>
                  سهم بیمه تکمیلی
                  {insurance.insuranceNameOf(supplementaryId) ? ` — ${insurance.insuranceNameOf(supplementaryId)}` : ''}
                  <span style={{ color: 'var(--text-3)', fontSize: 11.5 }}> (روی باقیمانده)</span>
                </span>
                <strong style={{ color: 'var(--success)' }}>{formatRial(shares.supplementary)}</strong>
              </div>
            )}
            <div
              style={{
                ...rowStyle, borderTop: '1px solid var(--border)', marginTop: 2,
                paddingTop: 12, fontSize: 14, fontWeight: 700, color: 'var(--text)',
              }}
            >
              <span>{hasInsurance ? 'سهم بیمار (قابل پرداخت)' : 'مبلغ قابل پرداخت'}</span>
              <strong style={{ fontSize: 16, color: 'var(--primary)' }}>{formatRial(payable)}</strong>
            </div>
          </div>

          {/* پرداخت‌ها — تقسیم بین چند روش */}
          <div style={{ marginBottom: 12 }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>
              <label style={{ fontSize: 13.5, fontWeight: 700, color: 'var(--text)' }}>روش‌های پرداخت</label>
              <button type="button" className="btn ghost sm" onClick={addRow}>
                <PlusIcon style={{ width: 15, height: 15 }} />
                افزودن روش
              </button>
            </div>

            <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
              {rows.map((r) => (
                <div
                  key={r.id}
                  style={{
                    border: '1px solid var(--border)', borderRadius: 'var(--r-sm)',
                    padding: 12, display: 'flex', flexDirection: 'column', gap: 10,
                  }}
                >
                  <div style={{ display: 'flex', gap: 10, alignItems: 'flex-end' }}>
                    <div className="field-block" style={{ flex: 1 }}>
                      <label>روش پرداخت</label>
                      <SearchableSelect
                        value={r.method}
                        onChange={(v) => changeMethod(r.id, String(v ?? 'cash'))}
                        options={METHOD_OPTIONS}
                        placeholder="روش پرداخت"
                        height={40}
                      />
                    </div>
                    <div className="field-block" style={{ flex: 1 }}>
                      <label>مبلغ (تومان)</label>
                      <div className="field">
                        <PriceInput
                          value={r.amountToman}
                          onChange={(v) => patchRow(r.id, { amountToman: v })}
                          suffix="تومان"
                        />
                      </div>
                    </div>
                    {rows.length > 1 && (
                      <button
                        type="button"
                        className="btn ghost sm"
                        aria-label="حذف روش پرداخت"
                        onClick={() => removeRow(r.id)}
                        style={{ marginBottom: 2, color: 'var(--danger)' }}
                      >
                        <TrashIcon style={{ width: 16, height: 16 }} />
                      </button>
                    )}
                  </div>

                  {/* جزئیاتِ کارت‌خوان: انتخاب دستگاهِ ثبت‌شده + شناسه تراکنش */}
                  {r.method === 'pos' && (
                    <div style={{ display: 'flex', gap: 10 }}>
                      <div className="field-block" style={{ flex: 1 }}>
                        <label>کارت‌خوان</label>
                        <SearchableSelect
                          value={r.methodUuid}
                          onChange={(v) => patchRow(r.id, { methodUuid: String(v ?? '') })}
                          options={posOptions}
                          placeholder={posOptions.length ? 'انتخاب کارت‌خوان' : 'کارت‌خوانی ثبت نشده'}
                          height={40}
                        />
                      </div>
                      <div className="field-block" style={{ flex: 1 }}>
                        <label>شناسه تراکنش (اختیاری)</label>
                        <div className="field">
                          <input
                            type="text"
                            value={r.reference}
                            onChange={(e) => patchRow(r.id, { reference: e.target.value })}
                            placeholder="شماره پیگیری"
                            style={{ direction: 'ltr' }}
                          />
                        </div>
                      </div>
                    </div>
                  )}

                  {/* جزئیاتِ کارت‌به‌کارت: انتخاب حساب بانکیِ ثبت‌شده + شناسه تراکنش */}
                  {r.method === 'card' && (
                    <div style={{ display: 'flex', gap: 10 }}>
                      <div className="field-block" style={{ flex: 1 }}>
                        <label>حساب بانکی (اختیاری)</label>
                        <SearchableSelect
                          value={r.methodUuid}
                          onChange={(v) => patchRow(r.id, { methodUuid: String(v ?? '') })}
                          options={bankOptions}
                          placeholder={bankOptions.length ? 'انتخاب حساب' : 'حسابی ثبت نشده'}
                          height={40}
                        />
                      </div>
                      <div className="field-block" style={{ flex: 1 }}>
                        <label>شناسه تراکنش (اختیاری)</label>
                        <div className="field">
                          <input
                            type="text"
                            value={r.reference}
                            onChange={(e) => patchRow(r.id, { reference: e.target.value })}
                            placeholder="شماره پیگیری"
                            style={{ direction: 'ltr' }}
                          />
                        </div>
                      </div>
                    </div>
                  )}
                </div>
              ))}
            </div>
          </div>

          {overpaid && (
            <p className="field-err" style={{ marginBottom: 14 }}>
              مجموع پرداخت‌ها از مبلغ قابل پرداخت بیشتر است.
            </p>
          )}

          {/* خلاصه */}
          <div
            style={{
              background: 'var(--surface-2)', border: '1px solid var(--border)',
              borderRadius: 'var(--r)', padding: '4px 14px 10px',
            }}
          >
            <div style={rowStyle}>
              <span>پرداخت‌شده</span>
              <strong style={{ color: 'var(--text)' }}>{formatRial(Math.min(paidRials, payable))}</strong>
            </div>
            <div style={{ ...rowStyle, borderTop: '1px solid var(--border)' }}>
              <span>باقی‌مانده</span>
              <strong style={{ color: remaining > 0 ? 'var(--danger)' : 'var(--success)' }}>
                {formatRial(remaining)}
              </strong>
            </div>
            <div style={{ ...rowStyle, borderTop: '1px solid var(--border)' }}>
              <span>وضعیت پرداخت</span>
              <span
                style={{
                  padding: '4px 12px', borderRadius: 'var(--r-pill)',
                  fontSize: 12.5, fontWeight: 700,
                  color: STATE_TONE[paymentState].fg,
                  background: STATE_TONE[paymentState].bg,
                }}
              >
                {paymentState}
              </span>
            </div>
          </div>
        </>
      )}
    </Modal>
  );
}
