import React, { useMemo, useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import Modal from '../ui/Modal';
import SearchableSelect from '../ui/SearchableSelect';
import { api, type ApiResponse } from '../../lib/api';
import { formatNumber } from '../../lib/utils';
import {
  REASON_LABELS,
  useAvailabilitySearch,
  useHold,
  type AvailableSlot,
} from '../../hooks/useResourceBooking';
import type { ClinicResource, ResourceServiceOffering } from '../../types';

const DAY = 86400;

function hhmm(ts: number): string {
  const d = new Date(ts * 1000);
  return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`;
}

/** نقشی از تخصیص که این منبع در آن پیشنهاد شده — `null` یعنی این وقت مالِ منبع دیگری است. */
function roleHolding(slot: AvailableSlot, resourceUuid: string): string | null {
  for (const [role, resources] of Object.entries(slot.assignment)) {
    if (resources.some((r) => r.uuid === resourceUuid)) return role;
  }
  return null;
}

/**
 * ثبت نوبت برای یک منبع مشخص — سرویس‌های خودِ منبع، بعد زمان، بعد پزشک مسئول.
 *
 * موتور همان `appointment-availability → hold → confirm` است که از قبل هست؛ تنها
 * تفاوت این است که جستجو خدمت‌محور جواب می‌دهد و ما نتیجه را به وقت‌هایی تنگ می‌کنیم
 * که موتور در آن‌ها **همین منبع** را پیشنهاد داده. وقتی که منبع در آن آزاد نبوده اصلاً
 * نشان داده نمی‌شود، وگرنه اپراتور چیزی را انتخاب می‌کند که در `hold` خطای ۴۰۹ می‌گیرد.
 *
 * پزشک مسئول اجباری است: هر نوبت در این سیستم پزشک دارد و `confirm` بدونش کار نمی‌کند.
 */
export default function ResourceBookingModal({ resource, onClose, onBooked }: {
  resource: ClinicResource;
  onClose: () => void;
  onBooked: () => void;
}) {
  const { create, confirm } = useHold();

  const [serviceUuid, setServiceUuid] = useState('');
  const [days, setDays] = useState('7');
  const [pickedSlot, setPickedSlot] = useState<AvailableSlot | null>(null);
  const [submitting, setSubmitting] = useState(false);

  // پزشکِ نوبت از ناظرِ خودِ منبع می‌آید، نه از یک انتخابگرِ دیگر: ارتباط پزشک و منبع
  // یک جا تعریف شده (فرم منبع) و تکرارش اینجا یعنی دو منبعِ حقیقت.
  const doctorUuid = resource.supervisor?.uuid ?? '';

  // سرویس‌های همین منبع، نه کل کاتالوگ: منبعی که سرویسی را ارائه نمی‌دهد نباید
  // در فهرست بیاید — سرور هم همان را با ۴۲۲ رد می‌کند.
  const offeringsQuery = useQuery<ApiResponse<ResourceServiceOffering[]>>({
    queryKey: ['resource-services', resource.uuid],
    queryFn: () => api.get(`/api/v1/resource/${resource.uuid}/services`),
  });
  const offerings = (offeringsQuery.data?.data ?? []).filter((o) => o.active);

  const range = useMemo(() => {
    const from = Math.floor(Date.now() / 1000);
    return { from, to: from + Number(days) * DAY };
  }, [days]);

  const { result, loading } = useAvailabilitySearch(
    { serviceUuid, branchUuid: resource.address_uuid, from: range.from, to: range.to },
    !!serviceUuid,
  );

  const slots = useMemo(
    () => (result?.slots ?? []).filter((s) => roleHolding(s, resource.uuid) !== null),
    [result, resource.uuid],
  );

  const reasonText = result?.reason ? REASON_LABELS[result.reason] ?? result.reason : null;
  const canSubmit = !!serviceUuid && !!pickedSlot && !!doctorUuid && !submitting;
  // ناظر در API الزامی است؛ ردیف‌های قدیمی‌ای که پزشکشان حذف شده `supervisor: null` دارند.
  const missingSupervisor = !resource.supervisor;

  const submit = async () => {
    if (!pickedSlot) return;
    setSubmitting(true);

    try {
      // تخصیص همان چیزی است که موتور برای این وقت داده، با یک قید: نقشی که این منبع
      // در آن آمده به خودش قفل می‌شود تا نوبت واقعاً روی همین دستگاه بنشیند.
      const role = roleHolding(pickedSlot, resource.uuid);
      const assignment = Object.fromEntries(
        Object.entries(pickedSlot.assignment).map(([r, list]) => [
          r,
          r === role ? [resource.uuid] : list.map((x) => x.uuid),
        ]),
      );

      const held = await create.mutateAsync({
        service_uuid: serviceUuid,
        branch_uuid: resource.address_uuid,
        start: pickedSlot.start,
        assignment,
      });

      await confirm.mutateAsync({ hold_uuid: held.data.hold_uuid, doctor_uuid: doctorUuid });
      onBooked();
      onClose();
    } finally {
      setSubmitting(false);
    }
  };

  return (
    <Modal
      open
      title={`ثبت نوبت — ${resource.name}`}
      size="sm"
      onClose={onClose}
      footer={
        <>
          <button type="button" className="btn ghost" onClick={onClose}>انصراف</button>
          <button type="button" className="btn primary" disabled={!canSubmit} onClick={submit}>
            {submitting ? 'در حال ثبت…' : 'ثبت نوبت'}
          </button>
        </>
      }
    >
      {missingSupervisor && (
        <p className="field-err" role="alert" style={{ marginTop: 0 }}>
          این منبع پزشک ناظر ندارد و نوبتی برایش ثبت نمی‌شود — از «منابع» ناظرش را تعیین کنید.
        </p>
      )}

      <div className="field-block" style={{ marginBottom: 14 }}>
        <label htmlFor="rb-service">سرویس‌های این منبع <span className="req">*</span></label>
        {offeringsQuery.isLoading ? (
          <div className="skeleton" style={{ height: 40, borderRadius: 'var(--r-sm)' }} />
        ) : offerings.length === 0 ? (
          <p className="field-err" style={{ marginTop: 0 }}>
            برای این منبع سرویسی تعریف نشده است — از تب «سرویس‌ها»ی همین منبع اضافه کنید.
          </p>
        ) : (
          <SearchableSelect
            inputId="rb-service"
            options={offerings.map((o) => ({
              value: o.service_uuid,
              label: o.effective_duration_minutes
                ? `${o.service_name} · ${formatNumber(o.effective_duration_minutes)} دقیقه`
                : o.service_name,
            }))}
            value={serviceUuid || null}
            onChange={(v) => { setServiceUuid(v ? String(v) : ''); setPickedSlot(null); }}
            placeholder="سرویس را انتخاب کنید"
            height={40}
          />
        )}
      </div>

      {serviceUuid && (
        <div className="field-block" style={{ marginBottom: 14 }}>
          <label htmlFor="rb-range">بازهٔ جستجو</label>
          <SearchableSelect
            inputId="rb-range"
            options={[
              { value: '1', label: 'امروز' },
              { value: '7', label: 'یک هفتهٔ آینده' },
              { value: '30', label: 'یک ماه آینده' },
            ]}
            value={days}
            onChange={(v) => { setDays(v ? String(v) : '7'); setPickedSlot(null); }}
            height={40}
          />
        </div>
      )}

      {serviceUuid && (
        <div style={{ marginBottom: 14 }}>
          <span className="field-label">زمان‌های خالی این منبع</span>
          {loading ? (
            <div style={{ fontSize: 12.5, color: 'var(--text-3)' }}>در حال محاسبه…</div>
          ) : slots.length === 0 ? (
            <p className="field-err" style={{ marginTop: 0 }}>
              {reasonText ?? 'برای این منبع در این بازه وقت آزادی نیست — بازه را بزرگ‌تر کنید.'}
            </p>
          ) : (
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
              {slots.slice(0, 40).map((s) => {
                const active = pickedSlot?.start === s.start;
                return (
                  <button
                    key={s.start}
                    type="button"
                    dir="ltr"
                    onClick={() => setPickedSlot(s)}
                    style={{
                      fontSize: 13, padding: '6px 12px', borderRadius: 'var(--r-sm)',
                      cursor: 'pointer', fontFamily: 'inherit',
                      border: active ? '1px solid var(--primary)' : '1px solid var(--border)',
                      background: active ? 'var(--primary)' : 'var(--surface)',
                      color: active ? 'var(--on-primary)' : 'var(--text)',
                    }}
                  >
                    {new Date(s.start * 1000).toLocaleDateString('fa-IR')} · {hhmm(s.start)}
                  </button>
                );
              })}
            </div>
          )}
        </div>
      )}

      <div className="toggle-row">
        <div>
          <div className="tr-title">پزشک ناظر: {resource.supervisor?.name ?? '—'}</div>
          <div className="tr-desc">
            نوبت به نام همین پزشک ثبت می‌شود. برای تغییرش، ناظرِ منبع را در «منابع» ویرایش کنید.
          </div>
        </div>
      </div>
    </Modal>
  );
}
