import React, { useRef, useState } from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import {
  PlusIcon, ChevronRightIcon, ChevronLeftIcon, CalendarDaysIcon,
  TableCellsIcon, ClockIcon, UserCircleIcon, PhoneIcon,
} from '@heroicons/react/24/outline';
import { toast } from 'sonner';
import { api } from '../lib/api';
import type { PaginatedResponse, ApiResponse } from '../lib/api';
import type { Appointment } from '../types';
import { formatDate, toGregorianDate } from '../lib/utils';
import { useAuthStore } from '../stores/authStore';
import AppointmentStatusDropdown from '../components/ui/AppointmentStatusDropdown';
import PersianCalendar from '../components/ui/PersianCalendar';
import SearchableSelect from '../components/ui/SearchableSelect';

const EMPTY_ARR: Appointment[] = [];

// ─────────────────────────────────────────────────────────────────────────────
// Status config
// ─────────────────────────────────────────────────────────────────────────────

const STATUS_META: Record<string, { label: string; color: string; bg: string }> = {
  pending:             { label: 'رزرو شده',   color: 'var(--info)',    bg: 'var(--info-bg)' },
  confirmed:           { label: 'تأیید شده',  color: 'var(--success)', bg: 'var(--success-bg)' },
  completed:           { label: 'تکمیل شده',  color: 'var(--success)', bg: 'var(--success-bg)' },
  cancelled_by_doctor: { label: 'لغو پزشک',   color: 'var(--danger)',  bg: 'var(--danger-bg)' },
  cancelled_by_user:   { label: 'لغو بیمار',  color: 'var(--danger)',  bg: 'var(--danger-bg)' },
  no_show:             { label: 'غیبت',        color: 'var(--text-3)', bg: 'var(--surface-2)' },
  expired:             { label: 'منقضی',        color: 'var(--text-3)', bg: 'var(--surface-2)' },
};

function statusMeta(s: string) {
  return STATUS_META[s] ?? { label: s, color: 'var(--text-3)', bg: 'var(--surface-2)' };
}

// ─────────────────────────────────────────────────────────────────────────────
// Stats icons (inline SVG)
// ─────────────────────────────────────────────────────────────────────────────

function IconTotal() {
  const dots: [number, number][] = [];
  for (const x of [10, 16, 22, 28, 34]) for (const y of [10, 16, 22, 28, 34]) dots.push([x, y]);
  return (
    <svg width="44" height="44" viewBox="0 0 44 44" fill="none">
      <circle cx="22" cy="22" r="22" fill="#ede9fe" />
      {dots.map(([x, y]) => <circle key={`${x}-${y}`} cx={x} cy={y} r="1.8" fill="#7c3aed" opacity="0.6" />)}
    </svg>
  );
}

function IconCompleted() {
  return (
    <svg width="44" height="44" viewBox="0 0 44 44" fill="none">
      <circle cx="22" cy="22" r="22" fill="#dcfce7" />
      <ellipse cx="22" cy="18" rx="6" ry="7" fill="#16a34a" opacity="0.8" />
      <ellipse cx="22" cy="32" rx="10" ry="6" fill="#16a34a" opacity="0.5" />
    </svg>
  );
}

function IconWaiting() {
  return (
    <svg width="44" height="44" viewBox="0 0 44 44" fill="none">
      <circle cx="22" cy="22" r="22" fill="#fff7ed" />
      <path d="M22 14v8l5 3" stroke="#ea580c" strokeWidth="2.5" strokeLinecap="round" />
      <circle cx="22" cy="22" r="9" stroke="#ea580c" strokeWidth="2" />
    </svg>
  );
}

function IconCancelled() {
  return (
    <svg width="44" height="44" viewBox="0 0 44 44" fill="none">
      <circle cx="22" cy="22" r="22" fill="#fef2f2" />
      <circle cx="22" cy="22" r="9" stroke="#ef4444" strokeWidth="2" />
      <path d="M17 17l10 10M27 17l-10 10" stroke="#ef4444" strokeWidth="2" strokeLinecap="round" />
    </svg>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// Stats Bar
// ─────────────────────────────────────────────────────────────────────────────

interface TodayStats { total: number; completed: number; waiting: number; cancelled: number; }

function StatsBar({ date, isAdmin }: { date: string; isAdmin: boolean }) {
  const { data } = useQuery<ApiResponse<TodayStats>>({
    queryKey: ['appt-today-stats', date, isAdmin],
    queryFn: () => api.get(
      isAdmin
        ? `/api/v1/admin/appointments/today-stats?date=${date}`
        : `/api/v1/my/appointments/today-stats?date=${date}`
    ),
  });
  const s = data?.data ?? { total: 0, completed: 0, waiting: 0, cancelled: 0 };
  const stats = [
    { label: 'کل نوبت‌های امروز',    value: s.total,     icon: <IconTotal /> },
    { label: 'نوبت‌های انجام شده',   value: s.completed, icon: <IconCompleted /> },
    { label: 'مراجعین در انتظار',   value: s.waiting,   icon: <IconWaiting /> },
    { label: 'نوبت‌های لغو شده',    value: s.cancelled, icon: <IconCancelled /> },
  ];
  return (
    <div style={{
      display: 'flex', background: 'var(--surface)', border: '1px solid var(--border)',
      borderRadius: 'var(--r)', overflow: 'hidden', marginBottom: 16,
    }}>
      {stats.map((s, i) => (
        <div key={i} style={{
          flex: 1, padding: '16px 20px', display: 'flex', alignItems: 'center', gap: 14,
          borderRight: i < 3 ? '1px solid var(--border)' : 'none',
        }}>
          <div style={{ flexShrink: 0 }}>{s.icon}</div>
          <div>
            <div style={{ fontSize: 12, color: 'var(--text-2)', marginBottom: 4 }}>{s.label}</div>
            <div style={{ fontSize: 26, fontWeight: 800, color: 'var(--text)' }}>
              {s.value.toLocaleString('fa-IR')}
            </div>
          </div>
        </div>
      ))}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// Date Navigator
// ─────────────────────────────────────────────────────────────────────────────

const WEEK_DAYS_FA = ['یک‌شنبه', 'دوشنبه', 'سه‌شنبه', 'چهارشنبه', 'پنج‌شنبه', 'جمعه', 'شنبه'];

function getPersianWeekDay(gregorianDate: string): string {
  return WEEK_DAYS_FA[new Date(gregorianDate + 'T12:00:00').getDay()];
}

function DateNavigator({ date, onChange }: { date: string; onChange: (d: string) => void }) {
  const [showCal, setShowCal] = useState(false);
  const ref = useRef<HTMLDivElement>(null);

  const weekDay  = getPersianWeekDay(date);
  const isFriday = new Date(date + 'T12:00:00').getDay() === 5;

  function addDays(n: number) {
    const d = new Date(date + 'T12:00:00');
    d.setDate(d.getDate() + n);
    onChange(toGregorianDate(d));
  }

  return (
    <div ref={ref} style={{ display: 'flex', alignItems: 'center', gap: 2, position: 'relative' }}>
      <button className="btn sm" style={navBtnSx} onClick={() => addDays(1)}>
        <ChevronRightIcon style={{ width: 15, height: 15 }} />
      </button>
      <div style={{
        padding: '0 14px', height: 44,
        display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
        background: 'var(--surface)', border: '1px solid var(--border)',
        borderRadius: 'var(--r-sm)', minWidth: 130, gap: 1,
      }}>
        <span style={{ fontSize: 13, fontWeight: 700, lineHeight: 1.2, color: isFriday ? '#ef4444' : 'var(--text)' }}>
          {weekDay}
        </span>
        <span style={{ fontSize: 11, color: 'var(--text-2)', lineHeight: 1.2 }}>
          {formatDate(date)}
        </span>
      </div>
      <button className="btn sm" style={navBtnSx} onClick={() => addDays(-1)}>
        <ChevronLeftIcon style={{ width: 15, height: 15 }} />
      </button>
      <button className="btn sm" style={navBtnSx} onClick={() => setShowCal(c => !c)}>
        <CalendarDaysIcon style={{ width: 15, height: 15 }} />
      </button>
      {showCal && (
        <PersianCalendar value={date} onChange={v => { onChange(v); setShowCal(false); }} onClose={() => setShowCal(false)} />
      )}
    </div>
  );
}

const navBtnSx: React.CSSProperties = {
  background: 'var(--surface)', border: '1px solid var(--border)',
  borderRadius: 'var(--r-sm)', height: 36, width: 36,
  display: 'flex', alignItems: 'center', justifyContent: 'center',
  cursor: 'pointer', color: 'var(--text-2)',
};

// ─────────────────────────────────────────────────────────────────────────────
// Table View
// ─────────────────────────────────────────────────────────────────────────────

function TableView({
  items, loading, queryKey, showDoctor,
}: {
  items: Appointment[]; loading: boolean; queryKey: unknown[]; showDoctor: boolean;
}) {
  if (loading) return <div style={{ padding: 40, textAlign: 'center', color: 'var(--text-3)' }}>در حال بارگذاری...</div>;
  if (!items.length) return <div style={{ padding: 40, textAlign: 'center', color: 'var(--text-3)' }}>نوبتی برای این روز ثبت نشده است</div>;

  return (
    <div style={{ overflowX: 'auto' }}>
      <div className="table-wrap"><table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
        <thead>
          <tr style={{ borderBottom: '1px solid var(--border)', background: 'var(--surface-2)' }}>
            <th style={th}>ردیف</th>
            <th style={th}>نام بیمار</th>
            <th style={th}>شماره تماس</th>
            {showDoctor && <th style={th}>پزشک</th>}
            <th style={th}>شروع</th>
            <th style={th}>پایان</th>
            <th style={th}>وضعیت</th>
          </tr>
        </thead>
        <tbody>
          {items.map((a, i) => (
            <tr key={a.uuid} style={{ borderBottom: '1px solid var(--border)' }}>
              <td style={td}>{(i + 1).toLocaleString('fa-IR')}</td>
              <td style={td}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                  <UserCircleIcon style={{ width: 18, height: 18, color: 'var(--text-3)' }} />
                  {a.patient_name || '—'}
                </div>
              </td>
              <td style={{ ...td, direction: 'ltr', textAlign: 'right' }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 4, justifyContent: 'flex-end' }}>
                  <PhoneIcon style={{ width: 14, height: 14, color: 'var(--text-3)' }} />
                  {a.patient_mobile}
                </div>
              </td>
              {showDoctor && <td style={td}>{a.doctor_name}</td>}
              <td style={{ ...td, fontWeight: 600 }}>{a.appointment_time}</td>
              <td style={td}>{a.end_time}</td>
              <td style={td}>
                <AppointmentStatusDropdown
                  uuid={a.uuid}
                  currentStatus={a.status}
                  version={a.version}
                  queryKey={queryKey}
                />
              </td>
            </tr>
          ))}
        </tbody>
      </table></div>
    </div>
  );
}

const th: React.CSSProperties = { padding: '10px 14px', textAlign: 'right', fontWeight: 600, color: 'var(--text-2)', whiteSpace: 'nowrap' };
const td: React.CSSProperties = { padding: '10px 14px', textAlign: 'right', color: 'var(--text)', verticalAlign: 'middle' };

// ─────────────────────────────────────────────────────────────────────────────
// Schedule View — Slot Card
// ─────────────────────────────────────────────────────────────────────────────

interface SlotItem {
  start: number;
  end: number;
  start_time: string;
  end_time: string;
  is_available: boolean;
  appointment: Appointment | null;
  cancelled_appointment: Appointment | null;
}

interface SessionGroup {
  start_time: string;
  end_time: string;
  slots: SlotItem[];
}

function CancelledBadge({ appt }: { appt: Appointment }) {
  const sm = statusMeta(appt.status);
  return (
    <div style={{
      display: 'flex', alignItems: 'center', gap: 8, padding: '5px 10px',
      borderRadius: 'var(--r-sm)', background: '#f9fafb',
      border: '1px dashed var(--border-2)', fontSize: 12, color: 'var(--text-3)',
      marginBottom: 4,
    }}>
      <span style={{ fontSize: 14, lineHeight: 1 }}>⊘</span>
      <span style={{
        padding: '1px 6px', borderRadius: 99, fontSize: 11, fontWeight: 700,
        background: `${sm.color}15`, color: sm.color, whiteSpace: 'nowrap',
      }}>{sm.label}</span>
      <span style={{ direction: 'ltr', color: 'var(--text)', fontWeight: 600, whiteSpace: 'nowrap' }}>
        {appt.appointment_time} — {appt.end_time}
      </span>
      <span style={{ fontWeight: 600, color: 'var(--text)' }}>{appt.patient_name || '—'}</span>
      <span style={{ direction: 'ltr', color: 'var(--text-3)' }}>{appt.patient_mobile}</span>
    </div>
  );
}

function SlotCard({ slot, queryKey, onBook }: { slot: SlotItem; queryKey: unknown[]; onBook: (slot: SlotItem) => void }) {
  const isPast = slot.start < Math.floor(Date.now() / 1000);

  if (!slot.is_available && slot.appointment) {
    const a = slot.appointment;
    const sm = statusMeta(a.status);
    return (
      <div style={{
        border: `1.5px solid ${sm.color}40`, borderRadius: 'var(--r)',
        background: sm.bg, overflow: 'hidden',
        opacity: isPast ? 0.6 : 1,
      }}>
        <div style={{
          padding: '8px 12px', display: 'flex', alignItems: 'center', justifyContent: 'space-between',
          borderBottom: `1px solid ${sm.color}20`,
        }}>
          <AppointmentStatusDropdown uuid={a.uuid} currentStatus={a.status} version={a.version} queryKey={queryKey} />
          <div style={{ fontSize: 12, color: 'var(--text-3)', fontWeight: 600 }}>
            {slot.start_time} — {slot.end_time}
          </div>
        </div>
        <div style={{ padding: '8px 12px', display: 'flex', flexDirection: 'column', gap: 4 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 13 }}>
            <UserCircleIcon style={{ width: 16, height: 16, color: 'var(--text-3)' }} />
            <span style={{ fontWeight: 600 }}>{a.patient_name || '—'}</span>
          </div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 12, color: 'var(--text-2)' }}>
            <PhoneIcon style={{ width: 14, height: 14 }} />
            <span style={{ direction: 'ltr' }}>{a.patient_mobile}</span>
          </div>
        </div>
      </div>
    );
  }

  // Available slot — possibly with cancelled history
  if (isPast) {
    return (
      <div style={{ display: 'flex', flexDirection: 'column' }}>
        {slot.cancelled_appointment && <CancelledBadge appt={slot.cancelled_appointment} />}
        <div style={{
          border: '1.5px dashed var(--border-2)', borderRadius: 'var(--r)', padding: '10px 16px',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          cursor: 'not-allowed', color: 'var(--text-3)', fontSize: 13, fontWeight: 600,
          background: 'var(--surface-2)', gap: 6,
        }}>
          <span style={{ fontSize: 15 }}>⊘</span> گذشته
        </div>
      </div>
    );
  }

  return (
    <div style={{ display: 'flex', flexDirection: 'column' }}>
      {slot.cancelled_appointment && <CancelledBadge appt={slot.cancelled_appointment} />}
      <div
        onClick={() => onBook(slot)}
        style={{
          border: '1.5px dashed color-mix(in oklch, var(--info) 50%, transparent)', borderRadius: 'var(--r)', padding: '10px 16px',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          cursor: 'pointer', color: 'var(--info)', fontSize: 13, fontWeight: 600,
          background: 'var(--info-bg)', transition: 'all 0.15s', gap: 6,
        }}
        onMouseEnter={e => (e.currentTarget.style.background = 'color-mix(in oklch, var(--info) 20%, transparent)')}
        onMouseLeave={e => (e.currentTarget.style.background = 'var(--info-bg)')}
      >
        <span style={{ fontSize: 18 }}>⊕</span> نوبت جدید
      </div>
    </div>
  );
}

function SessionDivider({ startTime, endTime, count }: { startTime: string; endTime: string; count: number }) {
  const hour  = parseInt(startTime.split(':')[0], 10);
  const isAm  = hour < 12;
  const icon  = isAm ? '🌅' : '🌆';
  const label = isAm ? 'صبح' : 'عصر';
  const color = isAm ? '#f59e0b' : '#6366f1';
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 8, margin: '4px 0 2px' }}>
      <span style={{ fontSize: 15 }}>{icon}</span>
      <span style={{ fontWeight: 700, fontSize: 13, color }}>{label}</span>
      <span style={{ fontSize: 12, color: 'var(--text-3)', fontWeight: 500 }}>
        {startTime} — {endTime}
      </span>
      <span style={{
        background: `${color}18`, borderRadius: 99, padding: '1px 8px',
        fontSize: 11, color, fontWeight: 600,
      }}>{count} نوبت</span>
      <div style={{ flex: 1, height: 1, background: 'var(--border)' }} />
    </div>
  );
}

function ScheduleView({
  sessions, loading, queryKey, onBook,
}: {
  sessions: SessionGroup[]; loading: boolean; queryKey: unknown[]; onBook: (s: SlotItem) => void;
}) {
  if (loading) return <div style={{ padding: 40, textAlign: 'center', color: 'var(--text-3)' }}>در حال بارگذاری...</div>;
  if (!sessions.length) return (
    <div style={{ padding: 40, textAlign: 'center' }}>
      <div style={{ fontSize: 32, marginBottom: 8 }}>🏖️</div>
      <div style={{ fontWeight: 700, fontSize: 15, color: 'var(--text)' }}>این روز تعطیل است</div>
      <div style={{ fontSize: 12, color: 'var(--text-3)', marginTop: 4 }}>هیچ برنامه زمانبندی برای این روز تنظیم نشده است</div>
    </div>
  );

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 8, padding: '4px 0' }}>
      {sessions.map((session, si) => (
        <div key={si} style={{ display: 'flex', flexDirection: 'column', gap: 8, marginTop: si > 0 ? 16 : 0 }}>
          <SessionDivider startTime={session.start_time} endTime={session.end_time} count={session.slots.length} />
          {session.slots.map((slot, i) => (
            <div key={`${slot.start}-${i}`} style={{ display: 'grid', gridTemplateColumns: '1fr auto', gap: 12, alignItems: 'center' }}>
              <SlotCard slot={slot} queryKey={queryKey} onBook={onBook} />
              <div style={{
                display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 2,
                fontSize: 12, color: 'var(--text-3)', fontWeight: 600, minWidth: 48,
              }}>
                <span style={{ width: 8, height: 8, borderRadius: '50%', background: 'var(--text-3)', display: 'block' }} />
                {slot.start_time}
              </div>
            </div>
          ))}
        </div>
      ))}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// New Appointment Modal
// ─────────────────────────────────────────────────────────────────────────────

interface BookingSlot { start: number; end: number; start_time: string; end_time: string; doctor_uuid: string; doctor_name: string; }

function NewAppointmentModal({
  slot, onClose, onSuccess,
}: { slot: BookingSlot; onClose: () => void; onSuccess: () => void }) {
  const [mobile,      setMobile]      = useState('');
  const [patientName, setPatientName] = useState('');

  const role = useAuthStore(s => s.primaryRole);
  const createEndpoint = role === 'admin' ? '/api/v1/admin/appointment' : '/api/v1/my/appointment';

  const isValid = mobile.length >= 10 && patientName.trim().length >= 2;

  const mutation = useMutation({
    mutationFn: () => api.post(createEndpoint, {
      doctor_uuid:    slot.doctor_uuid,
      slot_start:     slot.start,
      slot_end:       slot.end,
      patient_mobile: mobile,
      patient_name:   patientName.trim(),
    }),
    onSuccess: () => {
      toast.success('نوبت با موفقیت ثبت شد');
      onSuccess();
      onClose();
    },
    onError: (e: any) => {
      const msg = e?.response?.data?.errors?.[0]?.message ?? e?.message ?? 'خطا در ثبت نوبت';
      toast.error(msg);
    },
  });

  const inputSx: React.CSSProperties = {
    width: '100%', height: 38, padding: '0 10px', borderRadius: 'var(--r-sm)',
    border: '1px solid var(--border)', background: 'var(--surface)', fontSize: 13,
    boxSizing: 'border-box',
  };
  const labelSx: React.CSSProperties = {
    display: 'block', fontSize: 12, fontWeight: 600, color: 'var(--text-2)', marginBottom: 6,
  };

  return (
    <div style={{
      position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.4)', zIndex: 500,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
    }} onClick={onClose}>
      <div style={{
        background: 'var(--surface)', borderRadius: 'var(--r)', padding: 24,
        minWidth: 320, maxWidth: 400, width: '90vw', boxShadow: 'var(--shadow-xl)',
      }} onClick={e => e.stopPropagation()}>
        <div style={{ fontWeight: 700, fontSize: 16, marginBottom: 4 }}>ثبت نوبت</div>
        <div style={{ fontSize: 13, color: 'var(--text-2)', marginBottom: 16 }}>
          {slot.start_time} تا {slot.end_time} — {slot.doctor_name}
        </div>

        <div style={{ marginBottom: 12 }}>
          <label style={labelSx}>نام و نام خانوادگی بیمار *</label>
          <input
            type="text"
            value={patientName}
            onChange={e => setPatientName(e.target.value)}
            placeholder="مثال: علی محمدی"
            style={inputSx}
            autoFocus
          />
        </div>

        <div style={{ marginBottom: 16 }}>
          <label style={labelSx}>شماره موبایل بیمار *</label>
          <input
            type="tel"
            value={mobile}
            onChange={e => setMobile(e.target.value)}
            placeholder="مثال: 09123456789"
            style={{ ...inputSx, direction: 'ltr' }}
          />
        </div>

        <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
          <button className="btn sm" onClick={onClose}>انصراف</button>
          <button
            className="btn primary sm"
            onClick={() => mutation.mutate()}
            disabled={!isValid || mutation.isPending}
          >
            {mutation.isPending ? '...' : 'ثبت نوبت'}
          </button>
        </div>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// Main Page
// ─────────────────────────────────────────────────────────────────────────────

export default function AppointmentsPage() {
  const primaryRole = useAuthStore(s => s.primaryRole);
  const dbUuid = useAuthStore(s => s.dbUuid);
  const isAdmin = primaryRole === 'admin';
  const isClinic = primaryRole === 'clinic';
  const isDoctor = primaryRole === 'doctor';
  const isRepresentation = primaryRole === 'representation';

  const today = new Date().toISOString().slice(0, 10);
  const [selectedDate, setSelectedDate] = useState(today);
  const [viewMode, setViewMode] = useState<'table' | 'schedule'>('schedule');
  const [selectedDoctorUuid, setSelectedDoctorUuid] = useState<string>(isDoctor && dbUuid ? dbUuid : '');
  const [bookingSlot,    setBookingSlot]    = useState<BookingSlot | null>(null);
  const [bookingHint,    setBookingHint]    = useState(false);
  const qc = useQueryClient();

  // ── Appointments query
  const apptEndpoint = isAdmin
    ? '/api/v1/admin/appointments'
    : isRepresentation
      ? '/api/v1/representation/appointments'
      : '/api/v1/my/appointments';
  const apptQueryKey = ['appointments', apptEndpoint, selectedDate, selectedDoctorUuid];
  const apptParams = new URLSearchParams({ date: selectedDate, limit: '500' });
  if (selectedDoctorUuid) apptParams.set('doctor_uuid', selectedDoctorUuid);

  const apptQuery = useQuery<PaginatedResponse<Appointment>>({
    queryKey: apptQueryKey,
    queryFn: () => api.get(`${apptEndpoint}?${apptParams}`),
  });
  const appointments: Appointment[] = apptQuery.data?.data ?? EMPTY_ARR;

  // ── Clinic: load doctors from clinic profile (not derived from appointments)
  const clinicDoctorsQuery = useQuery<ApiResponse<{ data: { uuid: string; name: string }[] }>>({
    queryKey: ['clinic-doctors', dbUuid],
    queryFn: () => api.get(`/api/v1/clinic/doctor-list/${dbUuid}`),
    enabled: isClinic && !!dbUuid,
  });
  const clinicDoctorsList = clinicDoctorsQuery.data?.data?.data ?? [];

  // ── Unique doctors from results (for clinic tabs) + merge with clinic list
  const doctors = React.useMemo(() => {
    const map = new Map<string, string>();
    // first from clinic API (authoritative list)
    clinicDoctorsList.forEach(d => map.set(d.uuid, d.name));
    // then supplement with appointment data (for admin view)
    appointments.forEach(a => {
      if (a.doctor_uuid && a.doctor_name && !map.has(a.doctor_uuid)) {
        map.set(a.doctor_uuid, a.doctor_name);
      }
    });
    return Array.from(map.entries()).map(([uuid, name]) => ({ uuid, name }));
  }, [appointments, clinicDoctorsList]);

  const showDoctorTabs = isClinic && doctors.length >= 2;
  const showDoctorCol = isAdmin || (isClinic && !selectedDoctorUuid);

  // ── Slots query (schedule view)
  const slotsQueryKey = ['appt-slots', selectedDoctorUuid, selectedDate];
  const slotsQuery = useQuery<ApiResponse<any>>({
    queryKey: slotsQueryKey,
    queryFn: () => api.get(`/api/v1/appointment-slots?doctor_uuid=${selectedDoctorUuid}&date=${selectedDate}`),
    enabled: viewMode === 'schedule' && !!selectedDoctorUuid,
  });

  // ── Merge sessions + appointments for schedule view
  const mergedSessions: SessionGroup[] = React.useMemo(() => {
    if (viewMode !== 'schedule') return [];
    const rawSessions: any[] = (slotsQuery.data?.data as any)?.sessions ?? [];

    const CANCELLED_STATUSES = new Set(['cancelled_by_doctor', 'cancelled_by_user', 'cancelled_by_admin', 'auto_cancel_unpaid', 'no_show', 'expired']);
    const activeByStart    = new Map<number, Appointment>();
    const cancelledByStart = new Map<number, Appointment>();

    appointments.forEach(a => {
      const key = typeof a.slot_start === 'number' ? a.slot_start : parseInt(String(a.slot_start), 10);
      if (CANCELLED_STATUSES.has(a.status)) {
        const existing = cancelledByStart.get(key);
        if (!existing || a.created_at > existing.created_at) cancelledByStart.set(key, a);
      } else {
        activeByStart.set(key, a);
      }
    });

    return rawSessions.map((session: any) => ({
      start_time: session.start_time as string,
      end_time:   session.end_time   as string,
      slots: (session.slots as any[]).map((s: any) => {
        const slotStart = typeof s.start === 'number' ? s.start : parseInt(String(s.start), 10);
        const slotEnd   = typeof s.end   === 'number' ? s.end   : parseInt(String(s.end),   10);
        return {
          start:      slotStart,
          end:        slotEnd,
          start_time: s.start_time ?? new Date(slotStart * 1000).toLocaleTimeString('fa-IR', { hour: '2-digit', minute: '2-digit' }),
          end_time:   s.end_time   ?? new Date(slotEnd   * 1000).toLocaleTimeString('fa-IR', { hour: '2-digit', minute: '2-digit' }),
          is_available:          s.is_available as boolean,
          appointment:           activeByStart.get(slotStart)    ?? null,
          cancelled_appointment: cancelledByStart.get(slotStart) ?? null,
        };
      }),
    }));
  }, [viewMode, slotsQuery.data, appointments]);

  // ── Handle slot click → open booking modal
  function handleSlotClick(slot: SlotItem) {
    // نماینده اجازه‌ی ثبت نوبت ندارد؛ صفحه برای او فقط مشاهده است.
    if (isRepresentation) return;
    const doctorName = doctors.find(d => d.uuid === selectedDoctorUuid)?.name ?? '';
    setBookingHint(false);
    setBookingSlot({
      start: slot.start,
      end: slot.end,
      start_time: slot.start_time,
      end_time: slot.end_time,
      doctor_uuid: selectedDoctorUuid,
      doctor_name: doctorName,
    });
  }

  return (
    <div style={{ padding: '20px 24px' }}>
      {/* Stats Bar */}
      <StatsBar date={selectedDate} isAdmin={isAdmin} />

      {/* Doctor tabs (clinic with ≥2 doctors) */}
      {showDoctorTabs && (
        <div style={{ display: 'flex', gap: 4, marginBottom: 12 }}>
          <button
            onClick={() => setSelectedDoctorUuid('')}
            style={tabStyle(selectedDoctorUuid === '')}
          >
            همه
          </button>
          {doctors.map(d => (
            <button
              key={d.uuid}
              onClick={() => setSelectedDoctorUuid(d.uuid)}
              style={tabStyle(selectedDoctorUuid === d.uuid)}
            >
              {d.name}
            </button>
          ))}
        </div>
      )}

      {/* Main card */}
      <div style={{
        background: 'var(--surface)', border: '1px solid var(--border)',
        borderRadius: 'var(--r)', overflow: 'hidden',
      }}>
        {/* Toolbar */}
        <div style={{
          padding: '12px 16px', borderBottom: '1px solid var(--border)',
          display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap',
        }}>
          {/* New appointment button — نماینده اجازه‌ی ثبت ندارد */}
          {!isRepresentation && (
            <button
              className="btn primary sm"
              onClick={() => {
                if (!selectedDoctorUuid) { toast.error('ابتدا یک پزشک انتخاب کنید'); return; }
                setViewMode('schedule');
                setBookingHint(true);
              }}
              style={{ display: 'flex', alignItems: 'center', gap: 5 }}
            >
              <PlusIcon style={{ width: 15, height: 15 }} />
              نوبت جدید
            </button>
          )}

          {/* View toggle */}
          <div style={{
            display: 'flex', background: 'var(--surface-2)', borderRadius: 'var(--r-sm)',
            padding: 2, gap: 1,
          }}>
            {(['table', 'schedule'] as const).map(mode => (
              <button
                key={mode}
                onClick={() => { setViewMode(mode); if (mode === 'table') setBookingHint(false); }}
                style={{
                  padding: '5px 12px', borderRadius: 'var(--r-sm)', fontSize: 12, fontWeight: 600,
                  border: 'none', cursor: 'pointer',
                  background: viewMode === mode ? 'var(--surface)' : 'transparent',
                  color: viewMode === mode ? 'var(--primary)' : 'var(--text-3)',
                  boxShadow: viewMode === mode ? 'var(--shadow-sm)' : 'none',
                }}
              >
                {mode === 'table' ? (
                  <span style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
                    <TableCellsIcon style={{ width: 14, height: 14 }} />نمایش جدولی
                  </span>
                ) : (
                  <span style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
                    <ClockIcon style={{ width: 14, height: 14 }} />زمانبندی
                  </span>
                )}
              </button>
            ))}
          </div>

          {/* Doctor selector (admin / clinic) */}
          {!isDoctor && (
            <div style={{ minWidth: 200 }}>
              <SearchableSelect
                options={doctors.map(d => ({ value: d.uuid, label: d.name }))}
                value={selectedDoctorUuid || null}
                onChange={(v) => setSelectedDoctorUuid(v ? String(v) : '')}
                placeholder="انتخاب پزشک..."
                isClearable
                height={36}
              />
            </div>
          )}

          <div style={{ flex: 1 }} />

          {/* Date navigator */}
          <DateNavigator date={selectedDate} onChange={setSelectedDate} />
        </div>

        {/* Content */}
        <div style={{ padding: 16 }}>
          {viewMode === 'table' ? (
            <TableView
              items={appointments}
              loading={apptQuery.isLoading}
              queryKey={apptQueryKey}
              showDoctor={showDoctorCol}
            />
          ) : (
            <>
              {bookingHint && !isRepresentation && (
                <div style={{
                  display: 'flex', alignItems: 'center', gap: 10, marginBottom: 12,
                  padding: '10px 16px', borderRadius: 'var(--r-sm)',
                  background: 'var(--info-bg)', border: '1px solid color-mix(in oklch, var(--info) 40%, transparent)',
                  fontSize: 13, color: 'var(--info)',
                }}>
                  <span style={{ fontSize: 18 }}>👆</span>
                  <span>روی یک زمان خالی <strong>کلیک کنید</strong> تا نوبت جدید ثبت شود</span>
                  <button
                    onClick={() => setBookingHint(false)}
                    style={{ marginRight: 'auto', background: 'none', border: 'none', cursor: 'pointer', color: 'var(--info)', fontSize: 16 }}
                  >
                    ✕
                  </button>
                </div>
              )}
              <ScheduleView
                sessions={mergedSessions}
                loading={apptQuery.isLoading || slotsQuery.isLoading}
                queryKey={apptQueryKey}
                onBook={handleSlotClick}
              />
            </>
          )}
        </div>
      </div>

      {/* New appointment modal */}
      {bookingSlot && (
        <NewAppointmentModal
          slot={bookingSlot}
          onClose={() => setBookingSlot(null)}
          onSuccess={() => {
            qc.invalidateQueries({ queryKey: apptQueryKey });
            qc.invalidateQueries({ queryKey: slotsQueryKey });
            qc.invalidateQueries({ queryKey: ['appt-today-stats', selectedDate] });
          }}
        />
      )}
    </div>
  );
}

function tabStyle(active: boolean): React.CSSProperties {
  return {
    padding: '6px 14px', borderRadius: 'var(--r-sm)', fontSize: 13, fontWeight: 600,
    border: active ? '1px solid var(--primary)' : '1px solid var(--border)',
    background: active ? '#eff6ff' : 'var(--surface)',
    color: active ? 'var(--primary)' : 'var(--text-2)',
    cursor: 'pointer',
  };
}
