import { useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
import { useQuery } from '@tanstack/react-query';
import { MagnifyingGlassIcon, PencilSquareIcon, XMarkIcon } from '@heroicons/react/24/outline';
import { api } from '../lib/api';
import type { ApiResponse } from '../lib/api';
import PageHeader from '../components/ui/PageHeader';
import StatusBadge from '../components/ui/StatusBadge';
import { formatDate, formatDateTime, formatNumber } from '../lib/utils';
import { useUrlState } from '../hooks/useUrlState';
import PersianDateInput from '../components/ui/PersianDateInput';
import TreatmentCaseEditModal from '../components/TreatmentCaseEditModal';
import { PatientsGridView, PatientsCategoryView } from '../components/icons/FilesToolbarIcons';
import type { TreatmentCaseSummary, StaffTreatmentSession, SlotSuggestionResponse } from '../types';

const TABS = [
  { id: 'cases',    label: 'پرونده‌های درمان' },
  { id: 'unbooked', label: 'جلسات بدون نوبت' },
] as const;

type TabId = typeof TABS[number]['id'];

const CASE_STATUS_LABEL: Record<TreatmentCaseSummary['status'], string> = {
  active:    'در جریان',
  completed: 'تمام شده',
  abandoned: 'رها شده',
};

/**
 * پرونده‌های درمان و کارِ باقی‌ماندهٔ منشی.
 *
 * صفِ «جلسات بدون نوبت» عمداً کنار فهرست پرونده‌هاست نه صفحهٔ جدا: هر دو یک سؤال
 * را جواب می‌دهند — «کدام بیمار در چه مرحله‌ای است و چه کاری مانده».
 */
export default function TreatmentCasesPage() {
  const [urlState, setUrlState] = useUrlState({ tab: 'cases', status: '', q: '', from: '', to: '', view: 'table' });
  const tab = (TABS.some((t) => t.id === urlState.tab) ? urlState.tab : 'cases') as TabId;

  return (
    <>
      <PageHeader title="درمان‌های چندجلسه‌ای" />

      <div className="tabs" style={{ marginBottom: 16 }}>
        {TABS.map((t) => (
          <button
            key={t.id}
            type="button"
            className={tab === t.id ? 'active' : ''}
            onClick={() => setUrlState({ tab: t.id })}
          >
            {t.label}
          </button>
        ))}
      </div>

      {tab === 'cases'
        ? <CasesTab
            status={urlState.status}
            onStatus={(s) => setUrlState({ status: s })}
            search={urlState.q}
            onSearch={(q) => setUrlState({ q })}
            from={urlState.from}
            onFrom={(from) => setUrlState({ from })}
            to={urlState.to}
            onTo={(to) => setUrlState({ to })}
            view={urlState.view === 'card' ? 'card' : 'table'}
            onView={(v) => setUrlState({ view: v })}
          />
        : <UnbookedTab />}
    </>
  );
}

const STATUS_FILTERS = [
  ['',          'همه'],
  ['active',    'در جریان'],
  ['completed', 'تمام شده'],
  ['abandoned', 'رها شده'],
] as const;

function CasesTab({ status, onStatus, search, onSearch, from, onFrom, to, onTo, view, onView }: {
  status: string;
  onStatus: (s: string) => void;
  search: string;
  onSearch: (s: string) => void;
  /** بازهٔ تاریخِ باز شدن پرونده، `YYYY-MM-DD` میلادی. خالی = بدون کران. */
  from: string;
  onFrom: (s: string) => void;
  to: string;
  onTo: (s: string) => void;
  /** جدولی یا کارتی — همان الگوی صفحهٔ پرونده‌ها، در URL تا «بازگشت» نما را نپراند. */
  view: 'table' | 'card';
  onView: (v: 'table' | 'card') => void;
}) {
  // فیلد جستجو محلی می‌ماند و فقط مقدار نهایی به URL می‌رود؛ وگرنه هر حرف یک ورودی
  // تاریخچه می‌سازد و «بازگشت» بی‌معنی می‌شود.
  const [term, setTerm] = useState(search);
  useEffect(() => setTerm(search), [search]);
  useEffect(() => {
    const t = setTimeout(() => { if (term !== search) onSearch(term); }, 350);
    return () => clearTimeout(t);
  }, [term]);

  const [editing, setEditing] = useState<string | null>(null);

  const { data, isLoading, isError, refetch } = useQuery({
    queryKey: ['treatment-cases', status, search, from, to],
    queryFn: () => {
      const qs = new URLSearchParams();
      if (status) qs.set('status', status);
      if (search) qs.set('q', search);
      if (from) qs.set('from', from);
      if (to) qs.set('to', to);
      const suffix = qs.toString();

      return api.get<ApiResponse<TreatmentCaseSummary[]>>(
        `/api/v1/treatment-cases${suffix ? `?${suffix}` : ''}`,
      );
    },
    staleTime: 30_000,
  });

  const cases = data?.data ?? [];

  return (
    <>
      <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', alignItems: 'center', marginBottom: 14 }}>
        <div className="field" style={{ flex: '1 1 260px', maxWidth: 380 }}>
          <MagnifyingGlassIcon style={{ width: 16, height: 16, flexShrink: 0, color: 'var(--text-3)' }} />
          <input
            value={term}
            onChange={(e) => setTerm(e.target.value)}
            placeholder="نام بیمار، پرسنل، موبایل، کد ملی، شمارهٔ پرونده یا سرویس"
            aria-label="جستجوی پرونده"
          />
          {term !== '' && (
            <button type="button" className="mini-btn" aria-label="پاک کردن جستجو" onClick={() => setTerm('')}>
              <XMarkIcon style={{ width: 15, height: 15 }} />
            </button>
          )}
        </div>

        <div style={{
          display: 'flex', flexShrink: 0, overflow: 'hidden',
          border: '1px solid var(--border-2)', borderRadius: 4,
        }}>
          {([['table', 'نمایش جدولی', PatientsGridView], ['card', 'نمایش کارتی', PatientsCategoryView]] as const).map(
            ([v, label, Icon]) => (
              <button
                key={v}
                type="button"
                aria-label={label}
                aria-pressed={view === v}
                onClick={() => onView(v)}
                style={{
                  padding: 8, border: 'none', cursor: 'pointer', display: 'grid', placeItems: 'center',
                  background: view === v ? 'var(--primary-soft)' : 'transparent',
                }}
              >
                <Icon color={view === v ? 'var(--primary)' : 'var(--text-2)'} />
              </button>
            ),
          )}
        </div>

        <div className="seg">
          {STATUS_FILTERS.map(([v, label]) => (
            <button
              key={v}
              type="button"
              className={status === v ? 'on' : ''}
              aria-pressed={status === v}
              onClick={() => onStatus(v)}
            >
              {label}
            </button>
          ))}
        </div>

        {/* بازه روی تاریخِ باز شدن پرونده است — همان چیزی که در کارت زیر «شروع» می‌آید. */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
          <span style={{ fontSize: 12.5, color: 'var(--text-3)' }}>شروع</span>
          {/* دو تاریخ و «تا»ی بینشان یک واحدند: اگر جدا بشکنند، «تا» از فیلدش
              می‌افتد و معلوم نیست کران بالا کدام است. */}
          <div style={{
            display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'nowrap',
            flex: '1 1 300px', minWidth: 260, maxWidth: 340,
          }}>
            <div style={{ flex: 1, minWidth: 0 }}>
              <PersianDateInput value={from} onChange={onFrom} ariaLabel="شروع از تاریخ" placeholder="از تاریخ" />
            </div>
            <span style={{ fontSize: 12.5, color: 'var(--text-3)', flexShrink: 0 }}>تا</span>
            <div style={{ flex: 1, minWidth: 0 }}>
              <PersianDateInput value={to} onChange={onTo} ariaLabel="شروع تا تاریخ" placeholder="تا تاریخ" />
            </div>
          </div>
          {(from !== '' || to !== '') && (
            <button
              type="button"
              className="btn ghost sm"
              onClick={() => { onFrom(''); onTo(''); }}
            >
              پاک کردن بازه
            </button>
          )}
        </div>
      </div>

      {from !== '' && to !== '' && from > to && (
        <div className="card card-pad" style={{ marginBottom: 12, fontSize: 12.5, color: 'var(--danger)' }}>
          «از تاریخ» بعد از «تا تاریخ» است، پس هیچ پرونده‌ای در این بازه نمی‌افتد.
        </div>
      )}

      {isLoading ? (
        <div style={{ display: 'grid', gap: 12 }}>
          {[0, 1].map((i) => <div key={i} className="card" style={{ height: 96 }} />)}
        </div>
      ) : isError ? (
        /* خطای سرور نباید «پرونده‌ای یافت نشد» خوانده شود — آن یعنی جستجو نتیجه نداشت. */
        <div className="card card-pad" style={{ display: 'grid', gap: 10, justifyItems: 'start' }}>
          <span style={{ fontSize: 13, color: 'var(--danger)' }}>خواندن پرونده‌ها ناموفق بود.</span>
          <button type="button" className="btn secondary sm" onClick={() => refetch()}>تلاش دوباره</button>
        </div>
      ) : cases.length === 0 ? (
        <div className="card card-pad" style={{ fontSize: 13, color: 'var(--text-3)', lineHeight: 1.9 }}>
          {search
            ? `برای «${search}» پرونده‌ای پیدا نشد.`
            : (from !== '' || to !== '')
              ? 'در این بازهٔ تاریخ پرونده‌ای باز نشده است.'
              : 'پرونده‌ای یافت نشد. پرونده وقتی ساخته می‌شود که نوبتِ سرویسی با «طول درمان» قطعی شود.'}
        </div>
      ) : view === 'table' ? (
        <CasesTable cases={cases} onEdit={setEditing} />
      ) : (
        <div style={{ display: 'grid', gap: 12 }}>
          {cases.map((c) => <CaseCard key={c.uuid} item={c} onEdit={() => setEditing(c.uuid)} />)}
        </div>
      )}

      {editing !== null && (
        <TreatmentCaseEditModal caseUuid={editing} onClose={() => setEditing(null)} />
      )}
    </>
  );
}

/**
 * انجام‌دهنده از جلسات می‌آید (سابقه) و اختصاص‌یافته برنامه است؛ تا وقتی جلسه‌ای
 * انجام نشده، همان برنامه را نشان می‌دهیم. هر دو نما یک قاعده دارند.
 */
function operatorOf(c: TreatmentCaseSummary): { text: string; planned: boolean } | null {
  if (c.performed_by.length > 0) {
    return { text: c.performed_by.map((s) => s.name).join('، '), planned: false };
  }

  if (c.assigned_staff.length > 0) {
    return { text: c.assigned_staff.map((s) => s.name).join('، '), planned: true };
  }

  return null;
}

const TABLE_HEADS = ['ردیف', 'بیمار', 'سرویس', 'پرسنل', 'وضعیت', 'جلسات', 'شروع', 'عملیات'];

function CasesTable({ cases, onEdit }: { cases: TreatmentCaseSummary[]; onEdit: (uuid: string) => void }) {
  return (
    <div style={{
      background: 'var(--surface)', border: '1px solid var(--border)',
      borderRadius: 'var(--r-lg)', overflow: 'auto',
    }}>
      <table style={{ width: '100%', borderCollapse: 'collapse', minWidth: 900 }}>
        <thead>
          <tr style={{ background: 'var(--surface-2)', color: 'var(--text-2)', fontSize: 13 }}>
            {TABLE_HEADS.map((h) => (
              <th key={h} style={{ padding: '12px 14px', textAlign: 'center', fontWeight: 600, whiteSpace: 'nowrap' }}>
                {h}
              </th>
            ))}
          </tr>
        </thead>
        <tbody>
          {cases.map((c, i) => {
            const operator = operatorOf(c);

            return (
              <tr key={c.uuid} style={{ borderTop: '1px solid var(--border)', fontSize: 13.5, textAlign: 'center' }}>
                <td style={{ padding: '12px 14px', color: 'var(--text-3)' }}>{formatNumber(i + 1)}</td>
                <td style={{ padding: '12px 14px' }}>
                  <div style={{ fontWeight: 600 }}>{c.patient.name || 'بیمار بدون نام'}</div>
                  <div style={{ fontSize: 12, color: 'var(--text-3)', direction: 'ltr' }}>{c.patient.mobile}</div>
                </td>
                <td style={{ padding: '12px 14px' }}>{c.service.name}</td>
                <td style={{ padding: '12px 14px', color: operator?.planned ? 'var(--text-3)' : 'var(--text)' }}>
                  {operator === null ? '—' : operator.planned ? `${operator.text} (هنوز انجام نشده)` : operator.text}
                </td>
                <td style={{ padding: '12px 14px' }}>
                  <span className={`badge ${c.status === 'active' ? 'blue' : c.status === 'completed' ? 'green' : 'gray'}`}>
                    <span className="bdot" />{CASE_STATUS_LABEL[c.status]}
                  </span>
                </td>
                <td style={{ padding: '12px 14px', whiteSpace: 'nowrap' }}>
                  {formatNumber(c.completed_sessions)} از {formatNumber(c.total_sessions)}
                </td>
                <td style={{ padding: '12px 14px', whiteSpace: 'nowrap' }}>{formatDateTime(c.opened_at)}</td>
                <td style={{ padding: '12px 14px' }}>
                  <button
                    type="button"
                    className="mini-btn"
                    aria-label={`ویرایش پروندهٔ ${c.patient.name ?? ''}`}
                    onClick={() => onEdit(c.uuid)}
                    style={{ color: 'var(--accent)' }}
                  >
                    <PencilSquareIcon style={{ width: 18, height: 18 }} />
                  </button>
                </td>
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
}

function CaseCard({ item: c, onEdit }: { item: TreatmentCaseSummary; onEdit: () => void }) {
  const percent = c.total_sessions > 0
    ? Math.round((c.completed_sessions / c.total_sessions) * 100)
    : 0;
  const operator = operatorOf(c);

  return (
    <div className="card card-pad" style={{ display: 'grid', gap: 10 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
        {/* بیمار سرتیتر است نه سرویس: دو پروندهٔ یک سرویس فقط با نام بیمار از هم جدا می‌شوند. */}
        <strong style={{ fontSize: 14 }}>{c.patient.name || 'بیمار بدون نام'}</strong>
        <span className={`badge ${c.status === 'active' ? 'blue' : c.status === 'completed' ? 'green' : 'gray'}`}>
          <span className="bdot" />{CASE_STATUS_LABEL[c.status]}
        </span>
        <span style={{ fontSize: 12.5, color: 'var(--text-3)' }}>
          {formatNumber(c.completed_sessions)} از {formatNumber(c.total_sessions)} جلسه
        </span>
        <button type="button" className="btn secondary sm" style={{ marginInlineStart: 'auto' }} onClick={onEdit}>
          <PencilSquareIcon style={{ width: 15, height: 15 }} />
          ویرایش
        </button>
      </div>

      <div style={{ display: 'flex', gap: 16, flexWrap: 'wrap', fontSize: 12.5, color: 'var(--text-2)' }}>
        <span>{c.service.name}</span>
        <span style={{ direction: 'ltr' }}>{c.patient.mobile}</span>
        {/* ساعت هم لازم است: چند پروندهٔ یک روز فقط با ساعت از هم جدا می‌شوند. */}
        <span>شروع: {formatDateTime(c.opened_at)}</span>
        {c.supervisor && <span>پزشک ناظر: {c.supervisor.name}</span>}
        {operator !== null && (
          operator.planned
            ? <span style={{ color: 'var(--text-3)' }}>پرسنل: {operator.text} (هنوز انجام نشده)</span>
            : <span>انجام‌دهنده: {operator.text}</span>
        )}
        {c.areas.length > 0 && <span>نواحی: {c.areas.map((a) => a.name).join('، ')}</span>}
      </div>

      {/* `<progress>` نیتیو ظاهر مرورگر را می‌گیرد و با توکن‌های تم نمی‌خواند. */}
      <div
        role="progressbar"
        aria-valuenow={c.completed_sessions}
        aria-valuemin={0}
        aria-valuemax={c.total_sessions}
        aria-label={`پیشرفت دوره: ${c.completed_sessions} از ${c.total_sessions}`}
        style={{ height: 6, borderRadius: 999, background: 'var(--surface-3)', overflow: 'hidden' }}
      >
        <div style={{
          width: `${percent}%`, height: '100%', borderRadius: 999,
          background: c.status === 'completed' ? 'var(--success)' : 'var(--primary)',
          transition: 'width .3s var(--ease)',
        }} />
      </div>
    </div>
  );
}

function UnbookedTab() {
  const { data, isLoading } = useQuery({
    queryKey: ['treatment-sessions-unbooked'],
    queryFn: () => api.get<ApiResponse<StaffTreatmentSession[]>>('/api/v1/treatment-sessions/unbooked?within_days=14'),
    staleTime: 30_000,
  });

  const sessions = data?.data ?? [];

  return (
    <>
      <p style={{ margin: '0 0 12px', fontSize: 12.5, color: 'var(--text-3)', lineHeight: 1.9 }}>
        جلساتی که سررسیدشان رسیده و هنوز نوبت نگرفته‌اند. رزرو عمداً خودکار نیست — وقتِ مناسب را
        باید با خود بیمار هماهنگ کرد.
      </p>

      {isLoading ? (
        <div className="card card-pad" style={{ fontSize: 13, color: 'var(--text-3)' }}>در حال بارگذاری...</div>
      ) : sessions.length === 0 ? (
        <div className="card card-pad" style={{ fontSize: 13, color: 'var(--text-3)' }}>
          جلسه‌ای در انتظار رزرو نیست.
        </div>
      ) : (
        <div style={{ display: 'grid', gap: 12 }}>
          {sessions.map((s) => (
            <div key={s.uuid} className="card card-pad" style={{ display: 'grid', gap: 8 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
                <strong style={{ fontSize: 14 }}>{s.service_name}</strong>
                <StatusBadge type="treatment-session" value={s.status} />
                <span style={{ fontSize: 12.5, color: 'var(--text-3)' }}>
                  جلسهٔ {s.session_number} از {s.total_sessions}
                </span>
              </div>

              {s.due_at !== null && (
                <span style={{ fontSize: 12.5, color: 'var(--warning)' }}>
                  سررسید: {formatDate(s.due_at)}
                </span>
              )}

              <SlotSuggestions sessionUuid={s.uuid} />
            </div>
          ))}
        </div>
      )}
    </>
  );
}

/**
 * وقت‌های آزادِ همان دستگاهی که جلسهٔ قبلی رویش انجام شد.
 *
 * پیشنهاد است نه رزرو: منشی با بیمار هماهنگ می‌کند و بعد از فرم عادی نوبت ثبتش
 * می‌کند. خودکار رزرو کردن یعنی سیستم به‌جای بیمار تصمیم بگیرد و بعد او نیاید.
 */
function SlotSuggestions({ sessionUuid }: { sessionUuid: string }) {
  const [open, setOpen] = useState(false);

  const { data, isLoading, isError } = useQuery({
    queryKey: ['session-slot-suggestions', sessionUuid],
    queryFn: () => api.get<ApiResponse<SlotSuggestionResponse>>(
      `/api/v1/treatment-session/${sessionUuid}/slot-suggestions?days=14`,
    ),
    enabled: open,
    staleTime: 60_000,
  });

  if (!open) {
    return (
      <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
        <button type="button" className="btn secondary sm" onClick={() => setOpen(true)}>
          پیشنهاد وقت
        </button>
        {/* لینک باید جلسه را ببرد، وگرنه منشی بیمار و سرویس را دستی می‌زند و اتصال
            به حدسِ سرویس سپرده می‌شود. */}
        <Link to={`/admin/appointments/new?session=${sessionUuid}`} className="btn primary sm">
          ثبت نوبت این جلسه
        </Link>
      </div>
    );
  }

  const days = data?.data?.days ?? [];

  return (
    <div style={{ display: 'grid', gap: 8 }}>
      {isLoading && <span style={{ fontSize: 12.5, color: 'var(--text-3)' }}>در حال جست‌وجوی وقت...</span>}

      {isError && (
        <span style={{ fontSize: 12.5, color: 'var(--text-3)' }}>
          دستگاهی برای پیشنهاد وقت مشخص نیست — این جلسه هنوز روی هیچ دستگاهی انجام نشده.
        </span>
      )}

      {!isLoading && !isError && days.length === 0 && (
        <span style={{ fontSize: 12.5, color: 'var(--text-3)' }}>
          در دو هفتهٔ آینده وقت آزادی روی این دستگاه نیست.
        </span>
      )}

      {days.slice(0, 3).map((day) => (
        <div key={day.date} style={{ display: 'flex', gap: 6, flexWrap: 'wrap', alignItems: 'center' }}>
          <span style={{ fontSize: 12.5, minWidth: 96, color: 'var(--text-2)' }}>
            {formatDate(Math.floor(new Date(day.date).getTime() / 1000))}
          </span>
          {day.slots.slice(0, 6).map((slot) => (
            <Link
              key={slot.start}
              to={`/admin/appointments/new?session=${sessionUuid}&date=${day.date}`}
              className="btn secondary sm"
              title={formatDateTime(slot.start)}
            >
              {slot.start_time}
            </Link>
          ))}
        </div>
      ))}

      <button type="button" className="btn ghost sm" onClick={() => setOpen(false)} style={{ justifySelf: 'start' }}>
        بستن
      </button>
    </div>
  );
}
