import React, { useState, useEffect, useMemo, useRef, useCallback } from 'react';
import { createPortal } from 'react-dom';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import {
  PencilIcon, TrashIcon, PlusIcon, CalendarIcon,
  ChevronDownIcon, ChevronRightIcon, ChevronLeftIcon,
  CheckCircleIcon, XCircleIcon, XMarkIcon, ExclamationTriangleIcon,
  LockClosedIcon, MapPinIcon, GlobeAltIcon,
} from '@heroicons/react/24/outline';
import { toast } from 'sonner';
import { api, ApiError } from '../../lib/api';
import type { ApiResponse } from '../../lib/api';
import { formatNumber, digitsOnly } from '../../lib/utils';
import Modal from '../ui/Modal';
import ConfirmDialog from '../ui/ConfirmDialog';
import GlobalSearchableSelect from '../ui/SearchableSelect';

/**
 * ساختار واحد تنظیمات نوبت‌دهی یک پزشک — برنامه هفتگی، استثناهای تاریخ و تعطیلات.
 *
 * همین کامپوننت هم در پنل شخصی پزشک رندر می‌شود و هم در تب‌های پنل کلینیک؛
 * تنها ورودی متمایزکننده `doctorUuid` است تا دو پیاده‌سازی موازی به وجود نیاید.
 */

export interface AddressData {
  id: string; uuid: string;
  type: 'personal' | 'clinic';
  clinic_id: string | null;
  clinic_name: string | null;
  name: string | null; address: string | null;
  telephone: string | null;
  map: { latitude: string | null; longitude: string | null };
  city:     { id: string; name: string } | null;
  province: { id: string; name: string } | null;
}

// ── Schedule types ─────────────────────────────────────────────────────────

interface SlotConfig       { start: string; end: string; duration: number; }
interface DateOverrideData   { uuid: string; doctor_uuid: string; date: number; active: boolean; reason: string | null; custom_slots: SessionConfig[]; }
interface HolidayData        { uuid: string; doctor_uuid: string; start_date: number; end_date: number; active: boolean; reason: string | null; }

interface SessionConfig {
  active: boolean;
  location_id: number | null;
  start_time: string;
  end_time: string;
  duration_per_patient: number;
  has_rest: boolean;
  rest_interval: number;
  time_to_rest: number;
  patient_limit: number | null;
}
interface NewDayConfig { sessions: SessionConfig[]; }
type NewScheduleMap = Record<string, NewDayConfig>;
interface BookingMeta {
  online_booking_enabled: boolean;
  booking_window_value: number;
  booking_window_unit: 'week' | 'month';
  booking_mode: 'slot' | 'service';
  buffer_minutes: number;
}
const DEFAULT_BOOKING_META: BookingMeta = {
  online_booking_enabled: true,
  booking_window_value: 1,
  booking_window_unit: 'month',
  booking_mode: 'slot',
  buffer_minutes: 0,
};
interface WeeklyScheduleData { uuid: string; doctor_uuid: string; schedule: NewScheduleMap; meta?: BookingMeta; booking_mode_locked?: boolean; }

// ── Persian (Jalali) date utilities ───────────────────────────────────────

// eslint-disable-next-line @typescript-eslint/no-require-imports
const jalaali = require('jalaali-js') as {
  toJalaali: (gy: number, gm: number, gd: number) => { jy: number; jm: number; jd: number };
  toGregorian: (jy: number, jm: number, jd: number) => { gy: number; gm: number; gd: number };
  jalaaliMonthLength: (jy: number, jm: number) => number;
};

const JALALI_MONTHS     = ['فروردین','اردیبهشت','خرداد','تیر','مرداد','شهریور','مهر','آبان','آذر','دی','بهمن','اسفند'];
const JALALI_DAYS_SHORT = ['ش','ی','د','س','چ','پ','ج'];

function toPersianNums(n: number | string): string {
  return String(n).replace(/\d/g, d => '۰۱۲۳۴۵۶۷۸۹'[parseInt(d)]);
}
function gToJ(gDate: string): { jy: number; jm: number; jd: number } | null {
  if (!gDate) return null;
  const [gy, gm, gd] = gDate.split('-').map(Number);
  return jalaali.toJalaali(gy, gm, gd);
}
function jToG(jy: number, jm: number, jd: number): string {
  const { gy, gm, gd } = jalaali.toGregorian(jy, jm, jd);
  return `${gy}-${String(gm).padStart(2,'0')}-${String(gd).padStart(2,'0')}`;
}
function formatPersianDate(gDate: string): string {
  const j = gToJ(gDate);
  if (!j) return gDate;
  return `${toPersianNums(j.jd)} ${JALALI_MONTHS[j.jm - 1]} ${toPersianNums(j.jy)}`;
}
function jFirstDayOfWeek(jy: number, jm: number): number {
  const { gy, gm, gd } = jalaali.toGregorian(jy, jm, 1);
  const dow = new Date(gy, gm - 1, gd).getDay(); // 0=Sunday
  return (dow + 1) % 7; // 0=Saturday, 1=Sunday, ..., 6=Friday
}
function todayGregorian(): string { return new Date().toISOString().slice(0, 10); }

// ── Persian Date Picker ────────────────────────────────────────────────────

function PersianDateInput({ value, onChange, minDate, placeholder }: {
  value: string; onChange: (v: string) => void; minDate?: string; placeholder?: string;
}) {
  const [open,    setOpen]    = useState(false);
  const [viewJy,  setViewJy]  = useState(0);
  const [viewJm,  setViewJm]  = useState(0);
  const [rect,    setRect]    = useState<DOMRect | null>(null);
  const btnRef  = useRef<HTMLButtonElement>(null);
  const dropRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (!open) return;
    const j = gToJ(value || todayGregorian());
    if (j) { setViewJy(j.jy); setViewJm(j.jm); }
  }, [open, value]);

  useEffect(() => {
    if (!open) return;
    const onDown = (e: MouseEvent) => {
      if (dropRef.current && !dropRef.current.contains(e.target as Node) &&
          btnRef.current  && !btnRef.current.contains(e.target as Node)) setOpen(false);
    };
    document.addEventListener('mousedown', onDown);
    return () => document.removeEventListener('mousedown', onDown);
  }, [open]);

  const openPicker = () => {
    if (!btnRef.current) return;
    setRect(btnRef.current.getBoundingClientRect());
    setOpen(v => !v);
  };

  const prevMonth = () => viewJm === 1  ? (setViewJy(y => y - 1), setViewJm(12)) : setViewJm(m => m - 1);
  const nextMonth = () => viewJm === 12 ? (setViewJy(y => y + 1), setViewJm(1))  : setViewJm(m => m + 1);

  const selectDay = (jd: number) => { onChange(jToG(viewJy, viewJm, jd)); setOpen(false); };

  const selectedJ = gToJ(value);
  const minJ      = minDate ? gToJ(minDate) : null;
  const todayJ    = gToJ(todayGregorian());

  const daysInMonth = viewJy && viewJm ? jalaali.jalaaliMonthLength(viewJy, viewJm) : 0;
  const firstDow    = viewJy && viewJm ? jFirstDayOfWeek(viewJy, viewJm) : 0;

  const isSelected = (jd: number) => !!selectedJ && selectedJ.jy === viewJy && selectedJ.jm === viewJm && selectedJ.jd === jd;
  const isToday    = (jd: number) => !!todayJ    && todayJ.jy    === viewJy && todayJ.jm    === viewJm && todayJ.jd    === jd;
  const isDisabled = (jd: number) => {
    if (!minJ) return false;
    if (viewJy < minJ.jy) return true;
    if (viewJy === minJ.jy && viewJm < minJ.jm) return true;
    if (viewJy === minJ.jy && viewJm === minJ.jm && jd < minJ.jd) return true;
    return false;
  };

  const dropStyle: React.CSSProperties = rect
    ? { position: 'fixed', top: rect.bottom + 4, left: rect.left, zIndex: 9999, width: 288 }
    : {};

  return (
    <div>
      <button ref={btnRef} type="button" onClick={openPicker}
        className="cp-input h-11 flex items-center justify-between w-full cursor-pointer">
        <span className={value ? 'text-slate-800 dark:text-slate-200' : 'text-slate-400 dark:text-slate-500'}>
          {value ? formatPersianDate(value) : (placeholder ?? 'انتخاب تاریخ')}
        </span>
        <CalendarIcon className="w-4 h-4 text-slate-400 shrink-0 mr-2" />
      </button>
      {open && createPortal(
        <div ref={dropRef} style={dropStyle}
          className="bg-white dark:bg-gray-900 border border-slate-200 dark:border-gray-700 rounded-2xl shadow-2xl overflow-hidden">
          <div className="flex items-center justify-between px-4 py-3 border-b border-slate-100 dark:border-gray-800">
            <button type="button" onClick={nextMonth}
              className="w-8 h-8 flex items-center justify-center rounded-lg hover:bg-slate-100 dark:hover:bg-gray-800 text-slate-500 transition-colors">
              <ChevronRightIcon className="w-4 h-4" />
            </button>
            <span className="text-sm font-semibold text-slate-800 dark:text-slate-100" dir="rtl">
              {viewJm > 0 ? JALALI_MONTHS[viewJm - 1] : ''} {toPersianNums(viewJy)}
            </span>
            <button type="button" onClick={prevMonth}
              className="w-8 h-8 flex items-center justify-center rounded-lg hover:bg-slate-100 dark:hover:bg-gray-800 text-slate-500 transition-colors">
              <ChevronLeftIcon className="w-4 h-4" />
            </button>
          </div>
          <div className="grid grid-cols-7 px-3 pt-2 pb-1">
            {JALALI_DAYS_SHORT.map(d => (
              <div key={d} className="text-center text-xs font-medium text-slate-400 dark:text-slate-500 py-1">{d}</div>
            ))}
          </div>
          <div className="grid grid-cols-7 gap-0.5 px-3 pb-3">
            {Array.from({ length: firstDow }).map((_, i) => <div key={`e-${i}`} />)}
            {Array.from({ length: daysInMonth }).map((_, i) => {
              const jd  = i + 1;
              const sel = isSelected(jd);
              const tod = isToday(jd);
              const dis = isDisabled(jd);
              return (
                <button key={jd} type="button" disabled={dis} onClick={() => selectDay(jd)}
                  className={`w-full aspect-square flex items-center justify-center rounded-lg text-sm transition-colors
                    ${dis ? 'text-slate-300 dark:text-gray-600 cursor-not-allowed'
                          : sel ? 'bg-primary-500 text-white font-semibold shadow-sm'
                               : tod ? 'ring-1 ring-primary-400 text-primary-700 dark:text-primary-300 font-medium'
                                     : 'text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-gray-800'}`}>
                  {toPersianNums(jd)}
                </button>
              );
            })}
          </div>
        </div>,
        document.body
      )}
    </div>
  );
}

const SCHEDULE_DAYS = [
  { key: '0', label: 'شنبه'     },
  { key: '1', label: 'یکشنبه'   },
  { key: '2', label: 'دوشنبه'   },
  { key: '3', label: 'سه‌شنبه'  },
  { key: '4', label: 'چهارشنبه' },
  { key: '5', label: 'پنجشنبه'  },
  { key: '6', label: 'جمعه'     },
];
const DURATION_OPTS = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60];
const DEFAULT_SESSION: SessionConfig = {
  active: true, location_id: null,
  start_time: '09:00', end_time: '13:00',
  duration_per_patient: 20,
  has_rest: false, rest_interval: 60, time_to_rest: 10,
  patient_limit: null,
};
const EMPTY_NEW_SCHEDULE: NewScheduleMap = Object.fromEntries(
  SCHEDULE_DAYS.map(d => [d.key, { sessions: [] }])
);

function parseMinutes(t: string): number {
  const [h, m] = t.split(':').map(Number);
  return h * 60 + m;
}

function hasOverlap(sessions: SessionConfig[]): boolean {
  const active = sessions.filter(s => s.active);
  const sorted = [...active].sort((a, b) => parseMinutes(a.start_time) - parseMinutes(b.start_time));
  for (let i = 0; i < sorted.length - 1; i++) {
    if (parseMinutes(sorted[i].end_time) > parseMinutes(sorted[i + 1].start_time)) return true;
  }
  return false;
}

function addMinutes(time: string, mins: number): string {
  const total   = Math.min(parseMinutes(time) + mins, 23 * 60 + 59);
  const h = Math.floor(total / 60).toString().padStart(2, '0');
  const m = (total % 60).toString().padStart(2, '0');
  return `${h}:${m}`;
}

function calcSlotCount(session: SessionConfig): number {
  const totalMins = parseMinutes(session.end_time) - parseMinutes(session.start_time);
  if (totalMins <= 0 || session.duration_per_patient <= 0) return 0;
  const dur   = session.duration_per_patient;
  const limit = session.patient_limit ?? Infinity;
  let current = 0, elapsedWork = 0, count = 0;
  while (current + dur <= totalMins) {
    if (count >= limit) break;
    if (session.has_rest && session.rest_interval > 0 && elapsedWork > 0 && elapsedWork >= session.rest_interval) {
      current += session.time_to_rest; elapsedWork = 0; continue;
    }
    current += dur; elapsedWork += dur; count++;
  }
  return count;
}
function tsToDate(ts: number): string {
  return new Date(ts * 1000).toISOString().slice(0, 10);
}

// ── Schedule components ────────────────────────────────────────────────────

// انتخاب ساعت و دقیقه به صورت دو منوی جدا (24 ساعته، دقیقه با گام 5)
const HOUR_VALUES   = Array.from({ length: 24 }, (_, h) => h.toString().padStart(2, '0'));
const MINUTE_VALUES = Array.from({ length: 12 }, (_, i) => (i * 5).toString().padStart(2, '0'));

function TimeSelect({ value, onChange }: { value: string; onChange: (v: string) => void }) {
  const [hRaw, mRaw] = (value || '00:00').split(':');
  const h = (hRaw ?? '00').padStart(2, '0');
  // دقیقه را به نزدیک‌ترین گام ۵ گرد کن تا همیشه در لیست موجود باشد
  const mNum = Math.round((Number(mRaw) || 0) / 5) * 5;
  const m = (mNum >= 60 ? 55 : mNum).toString().padStart(2, '0');

  return (
    <div className="cp-time-select" style={{ display: 'flex', alignItems: 'center', gap: 6 }} dir="ltr">
      <div style={{ width: 92 }}>
        <GlobalSearchableSelect
          options={HOUR_VALUES.map(hv => ({ value: hv, label: hv }))}
          value={h}
          onChange={v => onChange(`${v ? String(v) : h}:${m}`)}
          height={38}
        />
      </div>
      <span style={{ fontWeight: 700, color: 'var(--text-2)' }}>:</span>
      <div style={{ width: 92 }}>
        <GlobalSearchableSelect
          options={MINUTE_VALUES.map(mv => ({ value: mv, label: mv }))}
          value={m}
          onChange={v => onChange(`${h}:${v ? String(v) : m}`)}
          height={38}
        />
      </div>
    </div>
  );
}

function SlotEditor({ slots, onChange }: {
  slots: SlotConfig[];
  onChange: (slots: SlotConfig[]) => void;
}) {
  const add    = () => onChange([...slots, { start: '09:00', end: '13:00', duration: 30 }]);
  const remove = (i: number) => onChange(slots.filter((_, idx) => idx !== i));
  const update = (i: number, field: keyof SlotConfig, val: string | number) =>
    onChange(slots.map((s, idx) => idx === i ? { ...s, [field]: val } : s));

  return (
    <div className="space-y-2">
      {slots.map((slot, i) => (
        <div key={i} className="flex items-center gap-2 flex-wrap">
          <span className="text-xs text-slate-500 dark:text-slate-400 shrink-0">از</span>
          <input type="time" value={slot.start} onChange={e => update(i, 'start', e.target.value)}
            className="cp-input h-8 w-28 text-sm font-mono text-center px-2" />
          <span className="text-xs text-slate-500 dark:text-slate-400 shrink-0">تا</span>
          <input type="time" value={slot.end} onChange={e => update(i, 'end', e.target.value)}
            className="cp-input h-8 w-28 text-sm font-mono text-center px-2" />
          <div style={{ width: 110 }}>
            <GlobalSearchableSelect
              options={DURATION_OPTS.map(d => ({ value: d, label: `${d} دقیقه` }))}
              value={slot.duration}
              onChange={(v) => update(i, 'duration', Number(v))}
              height={32}
            />
          </div>
          <button type="button" onClick={() => remove(i)}
            className="w-7 h-7 flex items-center justify-center rounded-lg text-slate-400 hover:text-red-500 hover:bg-red-50 dark:hover:bg-red-500/10 transition-colors shrink-0">
            <XMarkIcon className="w-3.5 h-3.5" />
          </button>
        </div>
      ))}
      <button type="button" onClick={add}
        className="flex items-center gap-1.5 text-xs text-primary-600 dark:text-primary-400 hover:underline mt-1">
        <PlusIcon className="w-3.5 h-3.5" />افزودن بازه زمانی
      </button>
    </div>
  );
}

function SessionEditor({ session, onChange, onRemove, addresses, serviceMode = false }: {
  session: SessionConfig;
  onChange: (s: SessionConfig) => void;
  onRemove: () => void;
  addresses: AddressData[];
  /** حالت نوبت‌دهی سرویسی: فیلدهای اسلاتی (بازه هر نوبت، استراحت، شمارش) نمایش داده نمی‌شوند. */
  serviceMode?: boolean;
}) {
  const upd = <K extends keyof SessionConfig>(k: K, v: SessionConfig[K]) =>
    onChange({ ...session, [k]: v });
  const slotCount = calcSlotCount(session);

  return (
    <div style={{ border: '1px solid var(--border)', borderRadius: 'var(--r)', background: 'var(--surface)', overflow: 'hidden' }}>

      {/* Time inputs */}
      <div style={{ padding: '14px 16px 12px', display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(140px, 1fr))', gap: 12, alignItems: 'end' }}>
        <div>
          <div style={{ fontSize: 12, color: 'var(--text-2)', marginBottom: 5 }}>از ساعت</div>
          <TimeSelect value={session.start_time} onChange={v => upd('start_time', v)} />
        </div>
        <div>
          <div style={{ fontSize: 12, color: 'var(--text-2)', marginBottom: 5 }}>تا ساعت</div>
          <TimeSelect value={session.end_time} onChange={v => upd('end_time', v)} />
        </div>
        <button type="button" className="mini-btn danger" onClick={onRemove} style={{ marginBottom: 1 }}>
          <TrashIcon style={{ width: 15, height: 15 }} />
        </button>
      </div>

      {/* Duration (slot mode only) + Location */}
      <div style={{ padding: '0 16px 14px', display: 'grid', gridTemplateColumns: serviceMode ? '1fr' : '1fr 1fr', gap: 12 }}>
        {!serviceMode && (
          <div>
            <div style={{ fontSize: 12, color: 'var(--text-2)', marginBottom: 5 }}>بازه هر نوبت</div>
            <GlobalSearchableSelect
              options={DURATION_OPTS.map(d => ({ value: d, label: `${d} دقیقه` }))}
              value={session.duration_per_patient}
              onChange={(v) => upd('duration_per_patient', Number(v))}
            />
          </div>
        )}
        <div>
          <div style={{ fontSize: 12, color: 'var(--text-2)', marginBottom: 5 }}>مکان نوبت</div>
          <GlobalSearchableSelect
            options={[
              ...addresses.filter(a => a.type === 'personal').map(a => ({
                value: Number(a.id),
                label: `🏥 ${a.name ?? a.address ?? `مطب ${a.id}`}`,
              })),
              ...addresses.filter(a => a.type === 'clinic').map(a => ({
                value: Number(a.id),
                label: `🏨 ${a.clinic_name ? `${a.clinic_name}${a.name ? ` — ${a.name}` : ''}` : (a.name ?? a.address ?? `کلینیک ${a.id}`)}`,
              })),
            ]}
            value={session.location_id ?? null}
            onChange={(v) => upd('location_id', v ? Number(v) : null)}
            placeholder="انتخاب مکان"
            isClearable
          />
        </div>
      </div>

      {/* Rest toggle (slot mode only) */}
      {!serviceMode && (
      <div style={{
        padding: '12px 16px', display: 'flex', alignItems: 'center',
        justifyContent: 'space-between', borderTop: '1px solid var(--border)',
      }}>
        <div>
          <b style={{ fontSize: 13 }}>استراحت دوره‌ای بین نوبت‌ها</b>
          <div className="muted" style={{ fontSize: 12, marginTop: 2 }}>توقف خودکار پس از مدت کاری مشخص</div>
        </div>
        <button type="button" onClick={() => upd('has_rest', !session.has_rest)}
          style={{
            position: 'relative', width: 40, height: 22, borderRadius: 99,
            border: 'none', cursor: 'pointer', flexShrink: 0,
            background: session.has_rest ? 'var(--primary)' : 'var(--surface-3)',
            transition: 'background .2s',
          }}>
          <span style={{
            position: 'absolute', top: 3, borderRadius: '50%',
            width: 16, height: 16, background: '#fff',
            boxShadow: '0 1px 3px rgba(0,0,0,.25)',
            insetInlineStart: session.has_rest ? 20 : 3,
          }} />
        </button>
      </div>
      )}

      {/* Rest params */}
      {!serviceMode && session.has_rest && (
        <div style={{ padding: '0 16px 14px', display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <div>
            <div style={{ fontSize: 12, color: 'var(--text-2)', marginBottom: 5 }}>هر (دقیقه کار)</div>
            <div className="field">
              <input type="text" inputMode="numeric" dir="ltr" value={session.rest_interval}
                onChange={e => upd('rest_interval', Number(digitsOnly(e.target.value)) || 0)} />
            </div>
          </div>
          <div>
            <div style={{ fontSize: 12, color: 'var(--text-2)', marginBottom: 5 }}>استراحت (دقیقه)</div>
            <div className="field">
              <input type="text" inputMode="numeric" dir="ltr" value={session.time_to_rest}
                onChange={e => upd('time_to_rest', Number(digitsOnly(e.target.value)) || 0)} />
            </div>
          </div>
        </div>
      )}

      {/* Slot count footer (slot mode only) */}
      {!serviceMode && (
      <div style={{
        padding: '10px 16px', display: 'flex', alignItems: 'center',
        justifyContent: 'space-between', borderTop: '1px solid var(--border)',
        background: 'var(--surface-2)',
      }}>
        <span className="muted" style={{ fontSize: 12 }}>تعداد نوبت محاسبه‌شده در این بازه</span>
        {slotCount > 0 ? (
          <span className="badge green">
            <CheckCircleIcon style={{ width: 13, height: 13 }} />
            {slotCount} نوبت
          </span>
        ) : (
          <span className="muted" style={{ fontSize: 12 }}>—</span>
        )}
      </div>
      )}
    </div>
  );
}

// ── Weekly Schedule Tab ────────────────────────────────────────────────────

/**
 * هر درخواست تنظیمات نوبت‌دهی باید محیطش را حمل کند: بدون clinic_uuid یعنی مطب
 * شخصی پزشک، و با آن یعنی همان پزشک داخل آن کلینیک. این دو داده‌ی جدا دارند.
 */
const withClinic = (url: string, clinicUuid?: string | null): string =>
  clinicUuid ? `${url}${url.includes('?') ? '&' : '?'}clinic_uuid=${encodeURIComponent(clinicUuid)}` : url;

export function WeeklyScheduleTab({ doctorUuid, clinicUuid, addresses, readOnly = false }: { doctorUuid: string; clinicUuid?: string | null; addresses: AddressData[]; readOnly?: boolean }) {
  const qc = useQueryClient();
  const [scheduleMap,  setScheduleMap]  = useState<NewScheduleMap>(EMPTY_NEW_SCHEDULE);
  const [scheduleUuid, setScheduleUuid] = useState<string | null>(null);
  const [expandedDay,  setExpandedDay]  = useState<string | null>(null);
  const [meta, setMeta] = useState<BookingMeta>(DEFAULT_BOOKING_META);
  // نوع نوبت‌دهی پس از اولین ثبت قفل می‌شود؛ confirmMode = دیالوگ هشدار قبل از ثبت اول.
  const [modeLocked, setModeLocked] = useState(false);
  const [confirmMode, setConfirmMode] = useState(false);

  const scheduleQ = useQuery({
    queryKey: ['doctor-schedule', doctorUuid, clinicUuid ?? null],
    queryFn:  () => api.get<ApiResponse<any>>(withClinic(`/api/v1/appointment-settings/weekly-schedule/${doctorUuid}`, clinicUuid)),
    staleTime: 0,
    retry: (count, err) => !(err instanceof ApiError && err.status === 404),
  });

  useEffect(() => {
    if (scheduleQ.data) {
      const d: WeeklyScheduleData = scheduleQ.data?.data?.data ?? scheduleQ.data?.data;
      if (d?.schedule) {
        const merged: NewScheduleMap = { ...EMPTY_NEW_SCHEDULE };
        for (const key of Object.keys(d.schedule)) {
          const raw = d.schedule[key] as any;
          if (raw?.sessions) merged[key] = { sessions: raw.sessions };
        }
        setScheduleMap(merged);
        setScheduleUuid(d.uuid);
      }
      if (d?.meta) setMeta({ ...DEFAULT_BOOKING_META, ...d.meta });
      setModeLocked(!!d?.booking_mode_locked);
    } else if (scheduleQ.error instanceof ApiError && scheduleQ.error.status === 404) {
      setScheduleMap(EMPTY_NEW_SCHEDULE); setScheduleUuid(null);
    }
  }, [scheduleQ.data, scheduleQ.error]);

  const overlapDays = useMemo(() =>
    Object.fromEntries(SCHEDULE_DAYS.map(d => [d.key, hasOverlap(scheduleMap[d.key]?.sessions ?? [])]))
  , [scheduleMap]);
  const hasAnyOverlap = Object.values(overlapDays).some(Boolean);

  const totalSlots = useMemo(() =>
    SCHEDULE_DAYS.reduce((sum, d) => {
      const sessions = scheduleMap[d.key]?.sessions ?? [];
      return sum + sessions.filter(s => s.active).reduce((s2, s) => s2 + calcSlotCount(s), 0);
    }, 0)
  , [scheduleMap]);

  const missingLocation = addresses.length > 0 && SCHEDULE_DAYS.some(d =>
    (scheduleMap[d.key]?.sessions ?? []).some(s => s.active && s.location_id === null)
  );

  const saveMut = useMutation({
    mutationFn: () => {
      if (hasAnyOverlap) throw new Error('تداخل زمانی در برنامه وجود دارد');
      if (missingLocation) throw new Error('مکان مطب برای همه بازه‌های فعال الزامی است');
      return scheduleUuid
        ? api.patch<ApiResponse<any>>(`/api/v1/appointment-settings/weekly-schedule/${doctorUuid}`, { schedule: scheduleMap, meta, clinic_uuid: clinicUuid ?? null })
        : api.post<ApiResponse<any>>('/api/v1/appointment-settings/weekly-schedule', { doctor_uuid: doctorUuid, schedule: scheduleMap, meta, clinic_uuid: clinicUuid ?? null });
    },
    onSuccess: (res) => {
      const d: WeeklyScheduleData = res?.data?.data ?? res?.data;
      if (d?.uuid && !scheduleUuid) setScheduleUuid(d.uuid);
      setModeLocked(true);  // پس از ثبت، نوع نوبت‌دهی قفل می‌شود
      toast.success('برنامه هفتگی ذخیره شد');
      qc.invalidateQueries({ queryKey: ['doctor-schedule', doctorUuid, clinicUuid ?? null] });
    },
    onError: (e: Error) => toast.error(e.message),
  });

  const setDaySessions = (key: string, sessions: SessionConfig[]) =>
    setScheduleMap(prev => ({ ...prev, [key]: { sessions } }));

  const addSession = (key: string) => {
    const existing = scheduleMap[key]?.sessions ?? [];
    const lastEnd  = existing.length > 0
      ? existing.reduce((max, s) => parseMinutes(s.end_time) > parseMinutes(max) ? s.end_time : max, '00:00')
      : '09:00';
    const newStart    = existing.length > 0 ? addMinutes(lastEnd, 30) : '09:00';
    const newEnd      = addMinutes(newStart, 240);
    const defaultLoc  = addresses.length > 0 ? Number(addresses[0].id) : null;
    setDaySessions(key, [...existing, { ...DEFAULT_SESSION, start_time: newStart, end_time: newEnd, location_id: defaultLoc }]);
    setExpandedDay(key);
  };

  const removeSession = (key: string, idx: number) =>
    setDaySessions(key, (scheduleMap[key]?.sessions ?? []).filter((_, i) => i !== idx));

  const updateSession = (key: string, idx: number, s: SessionConfig) =>
    setDaySessions(key, (scheduleMap[key]?.sessions ?? []).map((old, i) => i === idx ? s : old));

  if (scheduleQ.isLoading) return (
    <div className="space-y-3">{Array.from({ length: 4 }).map((_, i) => <div key={i} className="h-12 rounded-xl skeleton" />)}</div>
  );

  if (addresses.length === 0) return (
    <div className="flex flex-col items-center justify-center gap-3 py-12 text-center">
      <div className="w-12 h-12 rounded-full bg-amber-50 dark:bg-amber-500/10 border border-amber-200 dark:border-amber-500/30 flex items-center justify-center">
        <MapPinIcon className="w-6 h-6 text-amber-500" />
      </div>
      <div>
        <p className="text-sm font-medium text-slate-700 dark:text-slate-200">ابتدا آدرس مطب را ثبت کنید</p>
        <p className="text-xs text-slate-400 dark:text-slate-500 mt-1">برنامه کاری نیاز به حداقل یک مکان نوبت دارد</p>
      </div>
    </div>
  );

  // نمای فقط‌خواندنی برای نماینده: برنامه‌ی هفتگی به‌صورت متن، بدون فرم.
  if (readOnly) {
    if (scheduleQ.isLoading) {
      return <div className="space-y-2">{Array.from({ length: 4 }).map((_, i) => <div key={i} className="h-12 rounded-xl skeleton" />)}</div>;
    }
    return (
      <div className="space-y-2">
        {totalSlots > 0 && (
          <div className="flex items-center gap-2 mb-3 p-3 rounded-xl bg-emerald-50 dark:bg-emerald-500/10 border border-emerald-200 dark:border-emerald-500/30">
            <CalendarIcon className="w-4 h-4 text-emerald-600 dark:text-emerald-400 shrink-0" />
            <span className="text-sm text-emerald-700 dark:text-emerald-300">
              مجموع <strong>{totalSlots}</strong> نوبت در هفته
            </span>
          </div>
        )}
        {SCHEDULE_DAYS.map(day => {
          const activeSessions = (scheduleMap[day.key]?.sessions ?? []).filter(s => s.active);
          const daySlots = activeSessions.reduce((sum, s) => sum + calcSlotCount(s), 0);
          return (
            <div key={day.key} className="flex items-center gap-3 px-4 py-3 rounded-xl border border-slate-200 dark:border-gray-700 bg-white dark:bg-gray-800/40">
              <b style={{ fontSize: 14, minWidth: 56, flexShrink: 0 }}>{day.label}</b>
              <div className="flex-1 flex gap-2 items-center flex-wrap min-w-0">
                {activeSessions.length > 0 ? activeSessions.map((s, i) => (
                  <span key={i} className="text-xs px-2 py-1 rounded-lg bg-slate-100 dark:bg-gray-700 text-slate-700 dark:text-slate-200" style={{ fontFamily: 'monospace', direction: 'ltr', whiteSpace: 'nowrap' }}>
                    {s.start_time} – {s.end_time}
                  </span>
                )) : (
                  <span className="muted text-xs">تعطیل</span>
                )}
              </div>
              {daySlots > 0 && (
                <span className="badge green" style={{ flexShrink: 0 }}>
                  <span className="bdot" />{daySlots} نوبت
                </span>
              )}
            </div>
          );
        })}
      </div>
    );
  }

  return (
    <div className="space-y-2">
      {/* ─ خلاصه کل هفته */}
      {totalSlots > 0 && (
        <div className="flex items-center gap-2 mb-3 p-3 rounded-xl bg-emerald-50 dark:bg-emerald-500/10 border border-emerald-200 dark:border-emerald-500/30">
          <CalendarIcon className="w-4 h-4 text-emerald-600 dark:text-emerald-400 shrink-0" />
          <span className="text-sm text-emerald-700 dark:text-emerald-300">
            مجموع <strong>{totalSlots}</strong> نوبت در هفته
          </span>
        </div>
      )}

      {/* ─ روش نوبت‌دهی */}
      <div className="mb-3 rounded-xl border border-slate-200 dark:border-gray-700 overflow-hidden">
        <div className="px-4 py-3 bg-slate-50 dark:bg-gray-800/50">
          <span className="text-sm font-medium text-slate-700 dark:text-slate-200">روش نوبت‌دهی</span>
        </div>
        <div className="px-4 py-3 space-y-3">
          <div className="grid grid-cols-1 sm:grid-cols-2 gap-2">
            {([
              ['slot', 'نوبت‌دهی اسلاتی', 'شما بازه‌های کاری و «مدت هر نوبت» را مشخص می‌کنید؛ سیستم بازه را به نوبت‌های هم‌اندازه تقسیم می‌کند. مناسب ویزیت‌های با زمان یکسان.'],
              ['service', 'نوبت‌دهی سرویسی', 'مدت هر نوبت از «مدت سرویس» انتخاب‌شده تعیین می‌شود؛ سیستم نزدیک‌ترین زمان خالیِ کافی را پیشنهاد می‌دهد. مناسب خدمات با زمان متفاوت.'],
            ] as const).map(([val, lbl, desc]) => {
              const selected = meta.booking_mode === val;
              return (
                <button
                  key={val}
                  type="button"
                  disabled={modeLocked}
                  onClick={() => !modeLocked && setMeta(m => ({ ...m, booking_mode: val }))}
                  className={`text-right p-3 rounded-lg border transition-colors ${
                    selected
                      ? 'border-[var(--primary)] bg-[var(--primary)]/5'
                      : 'border-slate-200 dark:border-gray-700 bg-white dark:bg-gray-900'
                  } ${modeLocked ? 'opacity-70 cursor-not-allowed' : 'hover:border-[var(--primary)]'}`}
                >
                  <div className="flex items-center gap-2 mb-1">
                    <span className={`w-3.5 h-3.5 rounded-full border shrink-0 ${selected ? 'border-[var(--primary)] bg-[var(--primary)]' : 'border-slate-300 dark:border-gray-600'}`} />
                    <span className="text-sm font-medium text-slate-700 dark:text-slate-200">{lbl}</span>
                  </div>
                  <p className="text-xs text-slate-500 dark:text-slate-400 leading-relaxed">{desc}</p>
                </button>
              );
            })}
          </div>
          {modeLocked ? (
            <p className="text-xs text-slate-500 dark:text-slate-400 flex items-center gap-1.5">
              <LockClosedIcon className="w-3.5 h-3.5 shrink-0" />
              نوع نوبت‌دهی ثبت شده و دیگر قابل تغییر نیست.
            </p>
          ) : (
            <p className="text-xs text-amber-600 dark:text-amber-400 leading-relaxed">
              ⚠️ توجه: نوع نوبت‌دهی پس از اولین ثبت <span className="font-medium">به‌هیچ‌عنوان قابل تغییر نیست</span>. پیش از ذخیره با دقت انتخاب کنید.
            </p>
          )}
          {meta.booking_mode === 'service' ? (
            <>
              <div className="flex flex-wrap items-center gap-2">
                <span className="text-sm text-slate-600 dark:text-slate-400">فاصله بین نوبت‌ها</span>
                <input
                  type="text"
                  inputMode="numeric"
                  dir="ltr"
                  value={meta.buffer_minutes}
                  onChange={(e) => setMeta(m => ({ ...m, buffer_minutes: Math.max(0, Number(digitsOnly(e.target.value)) || 0) }))}
                  className="w-16 text-center text-sm rounded-lg border border-slate-200 dark:border-gray-700 bg-white dark:bg-gray-900 px-2 py-1.5 focus:outline-none focus:ring-0"
                />
                <span className="text-sm text-slate-600 dark:text-slate-400">دقیقه</span>
              </div>
              <p className="text-xs text-slate-400 dark:text-slate-500 leading-relaxed">
                مدت هر نوبت از «مدت سرویس» انتخاب‌شده تعیین می‌شود. لازم است حداقل یک سرویس با «نمایش در نوبت‌دهی» در بخش <span className="font-medium">{clinicUuid ? 'سرویس‌های کلینیک' : 'سرویس‌ها'}</span> تعریف کنید، وگرنه ذخیره نمی‌شود.
              </p>
            </>
          ) : (
            <p className="text-xs text-slate-400 dark:text-slate-500 leading-relaxed">
              مدت هر نوبت از «زمان هر نوبت» در شیفت‌های زیر تعیین می‌شود.
            </p>
          )}
        </div>
      </div>

      {/* ─ نوبت‌دهی آنلاین */}
      <div className="mb-3 rounded-xl border border-slate-200 dark:border-gray-700 overflow-hidden">
        {/* header + toggle */}
        <label className="flex items-center justify-between gap-3 px-4 py-3 cursor-pointer bg-slate-50 dark:bg-gray-800/50">
          <div className="flex items-center gap-2">
            <GlobeAltIcon className="w-4 h-4 text-slate-500 dark:text-slate-400 shrink-0" />
            <span className="text-sm font-medium text-slate-700 dark:text-slate-200">نوبت‌دهی آنلاین</span>
          </div>
          <span className="relative inline-flex shrink-0">
            <input
              type="checkbox"
              className="peer sr-only"
              checked={meta.online_booking_enabled}
              onChange={(e) => setMeta(m => ({ ...m, online_booking_enabled: e.target.checked }))}
            />
            <span className="w-10 h-6 rounded-full bg-slate-300 dark:bg-gray-600 transition-colors peer-checked:bg-emerald-500" />
            <span className="absolute top-0.5 right-0.5 w-5 h-5 rounded-full bg-white shadow transition-transform peer-checked:-translate-x-4" />
          </span>
        </label>

        {/* booking window control */}
        <div className={`px-4 py-3 transition-opacity ${meta.online_booking_enabled ? '' : 'opacity-50 pointer-events-none'}`}>
          <div className="flex flex-wrap items-center gap-2">
            <span className="text-sm text-slate-600 dark:text-slate-400">رزرو آنلاین تا</span>
            <div className="flex items-stretch gap-2">
              <input
                type="text"
                inputMode="numeric"
                dir="ltr"
                value={meta.booking_window_value}
                disabled={!meta.online_booking_enabled}
                onChange={(e) => setMeta(m => ({ ...m, booking_window_value: Math.max(1, Number(digitsOnly(e.target.value)) || 1) }))}
                className="w-14 text-center text-sm rounded-lg border border-slate-200 dark:border-gray-700 bg-white dark:bg-gray-900 focus:outline-none focus:ring-0 px-2 py-1.5"
              />
              <div style={{ width: 110 }}>
                <GlobalSearchableSelect
                  options={[{ value: 'week', label: 'هفته' }, { value: 'month', label: 'ماه' }]}
                  value={meta.booking_window_unit}
                  onChange={(v) => setMeta(m => ({ ...m, booking_window_unit: (v as 'week' | 'month') }))}
                  isDisabled={!meta.online_booking_enabled}
                  height={38}
                />
              </div>
            </div>
            <span className="text-sm text-slate-600 dark:text-slate-400">آینده</span>
          </div>
          <p className="text-xs text-slate-400 dark:text-slate-500 mt-2 leading-relaxed">
            بیمار فقط تا این بازه می‌تواند آنلاین نوبت بگیرد؛ روزهای بعد از آن روی تقویم غیرفعال‌اند.
          </p>
        </div>
      </div>

      {SCHEDULE_DAYS.map(day => {
        const sessions       = scheduleMap[day.key]?.sessions ?? [];
        const isOverlap      = overlapDays[day.key];
        const isExpanded     = expandedDay === day.key;
        const activeSessions = sessions.filter(s => s.active);
        const daySlots       = activeSessions.reduce((sum, s) => sum + calcSlotCount(s), 0);

        return (
          <div key={day.key} className="card" style={{ overflow: 'hidden' }}>
            {/* Day header */}
            <div
              style={{ padding: '12px 16px', display: 'flex', alignItems: 'center', gap: 10, cursor: 'pointer', userSelect: 'none' }}
              onClick={() => setExpandedDay(isExpanded ? null : day.key)}
            >
              <b style={{ fontSize: 14, minWidth: 56, flexShrink: 0 }}>{day.label}</b>
              <div style={{ flex: 1, display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap', minWidth: 0 }}>
                {activeSessions.map((s, i) => (
                  <span key={i} style={{ fontSize: 13, fontFamily: 'monospace', color: 'var(--text-2)', direction: 'ltr', whiteSpace: 'nowrap' }}>
                    {s.start_time} — {s.end_time}
                  </span>
                ))}
                {sessions.length === 0 && <span className="muted" style={{ fontSize: 12 }}>تعطیل</span>}
              </div>
              {daySlots > 0 && (
                <span className="badge green" style={{ flexShrink: 0 }}>
                  <span className="bdot" />{daySlots} نوبت
                </span>
              )}
              {isOverlap && (
                <span className="badge red" style={{ flexShrink: 0 }}>
                  <ExclamationTriangleIcon style={{ width: 12, height: 12 }} />تداخل
                </span>
              )}
              <button type="button" className="btn ghost sm" style={{ flexShrink: 0 }}
                onClick={e => { e.stopPropagation(); addSession(day.key); }}>
                <PlusIcon style={{ width: 13, height: 13 }} />
                بازه
              </button>
              <ChevronDownIcon style={{
                width: 16, height: 16, flexShrink: 0, color: 'var(--text-3)',
                transform: isExpanded ? 'rotate(180deg)' : 'none',
                transition: 'transform .2s',
              }} />
            </div>

            {/* Expanded sessions */}
            {isExpanded && (
              <div style={{ borderTop: '1px solid var(--border)', padding: '12px 16px 16px', display: 'flex', flexDirection: 'column', gap: 10 }}>
                {sessions.length === 0 ? (
                  <div style={{ textAlign: 'center', padding: '16px 0' }}>
                    <p className="muted" style={{ fontSize: 13, marginBottom: 10 }}>هیچ بازه‌ای برای این روز تنظیم نشده</p>
                    <button type="button" onClick={() => addSession(day.key)} className="btn ghost sm">
                      <PlusIcon style={{ width: 14, height: 14 }} />
                      افزودن اولین بازه
                    </button>
                  </div>
                ) : sessions.map((session, idx) => (
                  <SessionEditor key={idx} session={session} addresses={addresses}
                    serviceMode={meta.booking_mode === 'service'}
                    onChange={s => updateSession(day.key, idx, s)}
                    onRemove={() => removeSession(day.key, idx)} />
                ))}
              </div>
            )}
          </div>
        );
      })}

      <div className="flex items-center justify-between pt-3">
        {(hasAnyOverlap || missingLocation) && (
          <p className="text-xs text-red-500 dark:text-red-400 flex items-center gap-1">
            <ExclamationTriangleIcon className="w-3.5 h-3.5" />
            {hasAnyOverlap ? 'تداخل زمانی در برنامه وجود دارد' : 'مکان مطب برای همه بازه‌ها الزامی است'}
          </p>
        )}
        {!readOnly && (
          <button type="button" onClick={() => modeLocked ? saveMut.mutate() : setConfirmMode(true)}
            disabled={saveMut.isPending || hasAnyOverlap || missingLocation}
            className="btn primary sm" style={{ marginInlineStart: 'auto', opacity: (saveMut.isPending || hasAnyOverlap || missingLocation) ? 0.5 : 1 }}>
            {saveMut.isPending ? 'در حال ذخیره...' : 'ذخیره برنامه هفتگی'}
          </button>
        )}
      </div>

      <ConfirmDialog
        open={confirmMode}
        danger
        title="تأیید نوع نوبت‌دهی"
        message={`روش «${meta.booking_mode === 'service' ? 'نوبت‌دهی سرویسی' : 'نوبت‌دهی اسلاتی'}» را انتخاب کرده‌اید. این انتخاب پس از ثبت به‌هیچ‌عنوان قابل تغییر نیست. ادامه می‌دهید؟`}
        confirmLabel="ثبت و قفل"
        loading={saveMut.isPending}
        onConfirm={() => { setConfirmMode(false); saveMut.mutate(); }}
        onCancel={() => setConfirmMode(false)}
      />
    </div>
  );
}

// ── Date Override Modal ────────────────────────────────────────────────────

function DateOverrideModal({ open, onClose, existing, doctorUuid, clinicUuid, onSaved, addresses }: {
  open: boolean; onClose: () => void;
  existing: DateOverrideData | null; doctorUuid: string; clinicUuid?: string | null;
  onSaved: () => void; addresses: AddressData[];
}) {
  const [dateStr,      setDateStr]      = useState('');
  const [overrideType, setOverrideType] = useState<'closed' | 'custom'>('closed');
  const [reason,       setReason]       = useState('');
  const [slots,        setSlots]        = useState<SessionConfig[]>([]);

  const toSession = useCallback((s: any): SessionConfig => ({
    active:               true,
    start_time:           s.start_time ?? s.start ?? '09:00',
    end_time:             s.end_time   ?? s.end   ?? '13:00',
    duration_per_patient: s.duration_per_patient ?? s.duration ?? 20,
    location_id:          s.location_id ?? null,
    has_rest:             s.has_rest    ?? false,
    rest_interval:        s.rest_interval ?? 60,
    time_to_rest:         s.time_to_rest  ?? 10,
    patient_limit:        s.patient_limit ?? null,
  }), []);

  useEffect(() => {
    if (open) {
      if (existing) {
        setDateStr(tsToDate(existing.date));
        setOverrideType(existing.active ? 'custom' : 'closed');
        setReason(existing.reason ?? '');
        setSlots((existing.custom_slots ?? []).map(toSession));
      } else {
        setDateStr(new Date().toISOString().slice(0, 10));
        setOverrideType('closed'); setReason(''); setSlots([]);
      }
    }
  }, [open, existing, toSession]);

  const saveMut = useMutation({
    mutationFn: () => {
      const active = overrideType === 'custom';
      const body   = { date: dateStr, active, reason: reason || undefined, custom_slots: active ? slots : [] };
      if (existing)
        return api.patch<ApiResponse<any>>(`/api/v1/appointment-settings/date-override/${existing.uuid}`, body);
      return api.post<ApiResponse<any>>('/api/v1/appointment-settings/date-override', { ...body, doctor_uuid: doctorUuid, clinic_uuid: clinicUuid ?? null });
    },
    onSuccess: () => { toast.success(existing ? 'ویرایش شد' : 'تاریخ خاص اضافه شد'); onSaved(); onClose(); },
    onError: (e: Error) => toast.error(e.message),
  });

  return (
    <Modal open={open} title={existing ? 'ویرایش تاریخ خاص' : 'افزودن تاریخ خاص'} size="md" onClose={onClose}
      footer={
        <>
          <button type="button" onClick={onClose} className="cp-btn-secondary px-5">لغو</button>
          <button type="button" onClick={() => saveMut.mutate()} disabled={saveMut.isPending || !dateStr}
            className="btn primary sm">
            {saveMut.isPending ? 'در حال ذخیره...' : 'ذخیره'}
          </button>
        </>
      }
    >
      <div className="space-y-4">
        <div>
          <label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1.5">تاریخ</label>
          <PersianDateInput value={dateStr} onChange={setDateStr} placeholder="انتخاب تاریخ" />
        </div>

        {/* ─ نوع override */}
        <div>
          <label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">نوع این روز</label>
          <div className="grid grid-cols-2 gap-2">
            <button type="button"
              onClick={() => setOverrideType('closed')}
              className={`flex items-center gap-2 p-3 rounded-xl border-2 text-sm transition-colors text-right ${overrideType === 'closed' ? 'border-red-400 bg-red-50 dark:bg-red-500/10 text-red-700 dark:text-red-300' : 'border-slate-200 dark:border-gray-700 text-slate-600 dark:text-slate-400 hover:border-slate-300'}`}>
              <XCircleIcon className="w-5 h-5 shrink-0" />
              <div>
                <p className="font-medium leading-tight">تعطیل است</p>
                <p className="text-xs opacity-70 mt-0.5">هیچ نوبتی داده نمی‌شود</p>
              </div>
            </button>
            <button type="button"
              onClick={() => setOverrideType('custom')}
              className={`flex items-center gap-2 p-3 rounded-xl border-2 text-sm transition-colors text-right ${overrideType === 'custom' ? 'border-amber-400 bg-amber-50 dark:bg-amber-500/10 text-amber-700 dark:text-amber-300' : 'border-slate-200 dark:border-gray-700 text-slate-600 dark:text-slate-400 hover:border-slate-300'}`}>
              <CalendarIcon className="w-5 h-5 shrink-0" />
              <div>
                <p className="font-medium leading-tight">ساعات خاص</p>
                <p className="text-xs opacity-70 mt-0.5">جایگزین برنامه هفتگی</p>
              </div>
            </button>
          </div>
        </div>

        <div>
          <label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1.5">دلیل (اختیاری)</label>
          <input type="text" value={reason} onChange={e => setReason(e.target.value)}
            placeholder={overrideType === 'closed' ? 'مثال: سفر، مریضی، کنگره...' : 'مثال: شیفت اضطراری، ویزیت خاص...'}
            className="input" />
        </div>

        {overrideType === 'custom' && (
          <div>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 10 }}>
              <label style={{ fontSize: 13, fontWeight: 600, color: 'var(--text-2)' }}>بازه‌های زمانی</label>
              <button type="button" className="btn ghost sm"
                onClick={() => setSlots(prev => [...prev, {
                  ...DEFAULT_SESSION,
                  location_id: addresses[0] ? Number(addresses[0].id) : null,
                }])}>
                <PlusIcon style={{ width: 13, height: 13 }} />
                افزودن بازه
              </button>
            </div>
            {slots.length === 0 ? (
              <p className="muted" style={{ fontSize: 12 }}>اگر خالی بماند از برنامه هفتگی استفاده می‌شود</p>
            ) : (
              <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
                {slots.map((session, idx) => (
                  <SessionEditor key={idx} session={session} addresses={addresses}
                    onChange={s => setSlots(prev => prev.map((old, i) => i === idx ? s : old))}
                    onRemove={() => setSlots(prev => prev.filter((_, i) => i !== idx))} />
                ))}
              </div>
            )}
          </div>
        )}

        {overrideType === 'closed' && (
          <div className="flex items-start gap-2 p-3 rounded-xl bg-red-50 dark:bg-red-500/10 border border-red-200 dark:border-red-500/30">
            <ExclamationTriangleIcon className="w-4 h-4 text-red-500 shrink-0 mt-0.5" />
            <p className="text-xs text-red-700 dark:text-red-400">
              در این روز هیچ نوبتی داده نخواهد شد، حتی اگر در برنامه هفتگی ساعات کاری داشته باشید.
            </p>
          </div>
        )}
      </div>
    </Modal>
  );
}

// ── Date Overrides Tab ─────────────────────────────────────────────────────

function DateOverridesTab({ doctorUuid, clinicUuid, addresses, readOnly = false }: { doctorUuid: string; clinicUuid?: string | null; addresses: AddressData[]; readOnly?: boolean }) {
  const qc = useQueryClient();
  const [modalOpen,    setModalOpen]    = useState(false);
  const [editing,      setEditing]      = useState<DateOverrideData | null>(null);
  const [deletingUuid, setDeletingUuid] = useState<string | null>(null);

  const listQ = useQuery({
    queryKey: ['doctor-overrides', doctorUuid, clinicUuid ?? null],
    queryFn:  () => api.get<ApiResponse<any>>(withClinic(`/api/v1/appointment-settings/date-override/list/${doctorUuid}`, clinicUuid)),
    staleTime: 0,
  });
  const overrides: DateOverrideData[] = useMemo(
    () => listQ.data?.data?.data ?? listQ.data?.data ?? [], [listQ.data]
  );

  const deleteMut = useMutation({
    mutationFn: (uuid: string) => api.delete<ApiResponse<any>>(`/api/v1/appointment-settings/date-override/${uuid}`),
    onSuccess: () => { toast.success('حذف شد'); setDeletingUuid(null); qc.invalidateQueries({ queryKey: ['doctor-overrides', doctorUuid, clinicUuid ?? null] }); },
    onError: (e: Error) => toast.error(e.message),
  });

  if (listQ.isLoading) return (
    <div className="space-y-2">{Array.from({ length: 3 }).map((_, i) => <div key={i} className="h-14 rounded-xl skeleton" />)}</div>
  );

  if (addresses.length === 0) return (
    <div className="flex flex-col items-center justify-center gap-3 py-12 text-center">
      <div className="w-12 h-12 rounded-full bg-amber-50 dark:bg-amber-500/10 border border-amber-200 dark:border-amber-500/30 flex items-center justify-center">
        <MapPinIcon className="w-6 h-6 text-amber-500" />
      </div>
      <div>
        <p className="text-sm font-medium text-slate-700 dark:text-slate-200">ابتدا آدرس مطب را ثبت کنید</p>
        <p className="text-xs text-slate-400 dark:text-slate-500 mt-1">برنامه کاری نیاز به حداقل یک مکان نوبت دارد</p>
      </div>
    </div>
  );

  return (
    <div className="space-y-3">
      {!readOnly && (
        <div className="flex justify-end">
          <button type="button" onClick={() => { setEditing(null); setModalOpen(true); }}
            className="flex items-center gap-1.5 text-sm cp-btn-primary">
            <PlusIcon className="w-4 h-4" />تاریخ خاص جدید
          </button>
        </div>
      )}
      {overrides.length === 0 ? (
        <div className="text-center py-10 text-slate-400 dark:text-slate-500">
          <CalendarIcon className="w-10 h-10 mx-auto mb-2 opacity-30" />
          <p className="text-sm">هیچ تاریخ خاصی تنظیم نشده</p>
        </div>
      ) : (
        <div className="space-y-2">
          {overrides.map(ov => (
            <div key={ov.uuid} className="flex items-center gap-3 p-3.5 rounded-xl border border-slate-200 dark:border-gray-700 bg-white dark:bg-gray-800/60">
              <div className="flex-1 min-w-0">
                <div className="flex items-center gap-2 flex-wrap">
                  <span className="text-sm font-medium text-slate-800 dark:text-slate-200">{formatPersianDate(tsToDate(ov.date))}</span>
                  {ov.active ? (
                    <span className="text-xs px-2 py-0.5 rounded-full font-medium bg-amber-100 dark:bg-amber-500/20 text-amber-700 dark:text-amber-300">
                      {ov.custom_slots.length > 0 ? `${ov.custom_slots.length} بازه سفارشی` : 'ساعات خاص'}
                    </span>
                  ) : (
                    <span className="text-xs px-2 py-0.5 rounded-full font-medium bg-red-100 dark:bg-red-500/20 text-red-600 dark:text-red-400">
                      تعطیل
                    </span>
                  )}
                </div>
                {ov.reason && <p className="text-xs text-slate-400 dark:text-slate-500 mt-0.5">{ov.reason}</p>}
              </div>
              {!readOnly && (
                <div className="flex items-center gap-1 shrink-0">
                  <button onClick={() => { setEditing(ov); setModalOpen(true); }}
                    className="w-8 h-8 flex items-center justify-center rounded-lg text-slate-400 hover:text-blue-600 hover:bg-blue-50 dark:hover:bg-blue-500/10 transition-colors">
                    <PencilIcon className="w-3.5 h-3.5" />
                  </button>
                  <button onClick={() => setDeletingUuid(ov.uuid)}
                    className="w-8 h-8 flex items-center justify-center rounded-lg text-slate-400 hover:text-red-600 hover:bg-red-50 dark:hover:bg-red-500/10 transition-colors">
                    <TrashIcon className="w-3.5 h-3.5" />
                  </button>
                </div>
              )}
            </div>
          ))}
        </div>
      )}
      <DateOverrideModal open={modalOpen} onClose={() => { setModalOpen(false); setEditing(null); }}
        existing={editing} doctorUuid={doctorUuid} clinicUuid={clinicUuid} addresses={addresses}
        onSaved={() => qc.invalidateQueries({ queryKey: ['doctor-overrides', doctorUuid, clinicUuid ?? null] })} />
      <ConfirmDialog open={!!deletingUuid} title="حذف تاریخ خاص" message="آیا از حذف این تاریخ خاص اطمینان دارید؟"
        confirmLabel="بله، حذف کن" danger loading={deleteMut.isPending}
        onConfirm={() => deletingUuid && deleteMut.mutate(deletingUuid)} onCancel={() => setDeletingUuid(null)} />
    </div>
  );
}

// ── Holiday Modal ──────────────────────────────────────────────────────────

function HolidayModal({ open, onClose, existing, doctorUuid, clinicUuid, onSaved }: {
  open: boolean; onClose: () => void;
  existing: HolidayData | null; doctorUuid: string; clinicUuid?: string | null;
  onSaved: () => void;
}) {
  const [startDate, setStartDate] = useState('');
  const [endDate,   setEndDate]   = useState('');
  const [reason,    setReason]    = useState('');

  useEffect(() => {
    if (open) {
      if (existing) {
        setStartDate(tsToDate(existing.start_date));
        setEndDate(tsToDate(existing.end_date));
        setReason(existing.reason ?? '');
      } else {
        const today = new Date().toISOString().slice(0, 10);
        setStartDate(today); setEndDate(today); setReason('');
      }
    }
  }, [open, existing]);

  const invalid = !startDate || !endDate || endDate < startDate;

  const saveMut = useMutation({
    mutationFn: () => {
      const body = { start_date: startDate, end_date: endDate, reason: reason || undefined };
      if (existing)
        return api.patch<ApiResponse<any>>(`/api/v1/appointment-settings/holidays/${existing.uuid}`, body);
      return api.post<ApiResponse<any>>('/api/v1/appointment-settings/holidays', { ...body, doctor_uuid: doctorUuid, clinic_uuid: clinicUuid ?? null });
    },
    onSuccess: () => { toast.success(existing ? 'تعطیلات ویرایش شد' : 'تعطیلات اضافه شد'); onSaved(); onClose(); },
    onError: (e: Error) => toast.error(e.message),
  });

  return (
    <Modal open={open} title={existing ? 'ویرایش تعطیلات' : 'افزودن تعطیلات'} size="md" onClose={onClose}
      footer={
        <>
          <button type="button" onClick={onClose} className="cp-btn-secondary px-5">لغو</button>
          <button type="button" onClick={() => saveMut.mutate()} disabled={saveMut.isPending || invalid}
            className="btn primary sm">
            {saveMut.isPending ? 'در حال ذخیره...' : 'ذخیره'}
          </button>
        </>
      }
    >
      <div className="space-y-4">
        <div className="grid grid-cols-2 gap-3">
          <div>
            <label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1.5">از تاریخ</label>
            <PersianDateInput value={startDate} onChange={v => { setStartDate(v); if (endDate && v > endDate) setEndDate(v); }} />
          </div>
          <div>
            <label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1.5">تا تاریخ</label>
            <PersianDateInput value={endDate} onChange={setEndDate} minDate={startDate} />
          </div>
        </div>
        {endDate && startDate && endDate < startDate && (
          <p className="text-xs text-red-500">تاریخ پایان نمی‌تواند قبل از تاریخ شروع باشد</p>
        )}
        <div>
          <label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1.5">دلیل (اختیاری)</label>
          <input type="text" value={reason} onChange={e => setReason(e.target.value)}
            placeholder="مثال: سفر، کنگره پزشکی..." className="input" />
        </div>
      </div>
    </Modal>
  );
}

// ── Holidays Tab ───────────────────────────────────────────────────────────

function HolidaysTab({ doctorUuid, clinicUuid, readOnly = false }: { doctorUuid: string; clinicUuid?: string | null; readOnly?: boolean }) {
  const qc = useQueryClient();
  const [modalOpen,    setModalOpen]    = useState(false);
  const [editing,      setEditing]      = useState<HolidayData | null>(null);
  const [deletingUuid, setDeletingUuid] = useState<string | null>(null);

  const listQ = useQuery({
    queryKey: ['doctor-holidays', doctorUuid, clinicUuid ?? null],
    queryFn:  () => api.get<ApiResponse<any>>(withClinic(`/api/v1/appointment-settings/holidays/list/${doctorUuid}`, clinicUuid)),
    staleTime: 0,
  });
  const holidays: HolidayData[] = useMemo(
    () => listQ.data?.data?.data ?? listQ.data?.data ?? [], [listQ.data]
  );

  const deleteMut = useMutation({
    mutationFn: (uuid: string) => api.delete<ApiResponse<any>>(`/api/v1/appointment-settings/holidays/${uuid}`),
    onSuccess: () => { toast.success('حذف شد'); setDeletingUuid(null); qc.invalidateQueries({ queryKey: ['doctor-holidays', doctorUuid, clinicUuid ?? null] }); },
    onError: (e: Error) => toast.error(e.message),
  });

  const toggleMut = useMutation({
    mutationFn: (h: HolidayData) => api.patch<ApiResponse<any>>(`/api/v1/appointment-settings/holidays/${h.uuid}`, { active: !h.active }),
    onSuccess: () => { toast.success('وضعیت بروز شد'); qc.invalidateQueries({ queryKey: ['doctor-holidays', doctorUuid, clinicUuid ?? null] }); },
    onError: (e: Error) => toast.error(e.message),
  });

  if (listQ.isLoading) return (
    <div className="space-y-2">{Array.from({ length: 3 }).map((_, i) => <div key={i} className="h-14 rounded-xl skeleton" />)}</div>
  );

  return (
    <div className="space-y-3">
      {!readOnly && (
        <div className="flex justify-end">
          <button type="button" onClick={() => { setEditing(null); setModalOpen(true); }}
            className="flex items-center gap-1.5 text-sm cp-btn-primary">
            <PlusIcon className="w-4 h-4" />تعطیلات جدید
          </button>
        </div>
      )}
      {holidays.length === 0 ? (
        <div className="text-center py-10 text-slate-400 dark:text-slate-500">
          <CalendarIcon className="w-10 h-10 mx-auto mb-2 opacity-30" />
          <p className="text-sm">هیچ تعطیلاتی ثبت نشده</p>
        </div>
      ) : (
        <div className="space-y-2">
          {holidays.map(h => {
            const now       = Math.floor(Date.now() / 1000);
            const isPast    = h.end_date < now;
            const isCurrent = h.start_date <= now && h.end_date >= now;
            const sameDay   = tsToDate(h.start_date) === tsToDate(h.end_date);
            return (
              <div key={h.uuid} className={`flex items-center gap-3 p-3.5 rounded-xl border transition-colors ${isCurrent ? 'border-red-200 dark:border-red-500/30 bg-red-50/40 dark:bg-red-500/5' : isPast ? 'border-slate-200 dark:border-gray-700 bg-slate-50/40 dark:bg-gray-800/30 opacity-70' : 'border-orange-200 dark:border-orange-500/30 bg-orange-50/30 dark:bg-orange-500/5'}`}>
                <div className="flex-1 min-w-0">
                  <div className="flex items-center gap-2 flex-wrap">
                    <span className={`text-sm font-medium ${isPast ? 'text-slate-500 dark:text-slate-400' : 'text-slate-800 dark:text-slate-200'}`}>
                      {sameDay ? formatPersianDate(tsToDate(h.start_date)) : `${formatPersianDate(tsToDate(h.start_date))} تا ${formatPersianDate(tsToDate(h.end_date))}`}
                    </span>
                    {isCurrent && h.active && (
                      <span className="text-xs px-2 py-0.5 rounded-full font-medium bg-red-100 dark:bg-red-500/20 text-red-600 dark:text-red-400 animate-pulse">در جریان</span>
                    )}
                    {!isCurrent && !isPast && h.active && (
                      <span className="text-xs px-2 py-0.5 rounded-full font-medium bg-orange-100 dark:bg-orange-500/20 text-orange-600 dark:text-orange-400">آینده</span>
                    )}
                    {isPast && (
                      <span className="text-xs px-2 py-0.5 rounded-full bg-slate-100 dark:bg-gray-700 text-slate-400 dark:text-slate-500">گذشته</span>
                    )}
                    {!h.active && (
                      <span className="text-xs px-2 py-0.5 rounded-full bg-slate-100 dark:bg-gray-700 text-slate-400 dark:text-slate-500">غیرفعال</span>
                    )}
                  </div>
                  {h.reason && <p className="text-xs text-slate-400 dark:text-slate-500 mt-0.5">{h.reason}</p>}
                </div>
                {!readOnly && (
                  <div className="flex items-center gap-1 shrink-0">
                    <button onClick={() => toggleMut.mutate(h)} disabled={toggleMut.isPending}
                      className={`text-xs px-2.5 h-7 rounded-lg border transition-colors disabled:opacity-50 ${h.active ? 'border-slate-200 dark:border-gray-600 text-slate-500 dark:text-slate-400 hover:border-slate-300 hover:text-slate-700 dark:hover:text-slate-200' : 'border-emerald-200 dark:border-emerald-500/40 text-emerald-600 dark:text-emerald-400 hover:bg-emerald-50 dark:hover:bg-emerald-500/10'}`}>
                      {h.active ? 'غیرفعال' : 'فعال'}
                    </button>
                    <button onClick={() => { setEditing(h); setModalOpen(true); }}
                      className="w-8 h-8 flex items-center justify-center rounded-lg text-slate-400 hover:text-blue-600 hover:bg-blue-50 dark:hover:bg-blue-500/10 transition-colors">
                      <PencilIcon className="w-3.5 h-3.5" />
                    </button>
                    <button onClick={() => setDeletingUuid(h.uuid)}
                      className="w-8 h-8 flex items-center justify-center rounded-lg text-slate-400 hover:text-red-600 hover:bg-red-50 dark:hover:bg-red-500/10 transition-colors">
                      <TrashIcon className="w-3.5 h-3.5" />
                    </button>
                  </div>
                )}
              </div>
            );
          })}
        </div>
      )}
      <HolidayModal open={modalOpen} onClose={() => { setModalOpen(false); setEditing(null); }}
        existing={editing} doctorUuid={doctorUuid} clinicUuid={clinicUuid}
        onSaved={() => qc.invalidateQueries({ queryKey: ['doctor-holidays', doctorUuid, clinicUuid ?? null] })} />
      <ConfirmDialog open={!!deletingUuid} title="حذف تعطیلات" message="آیا از حذف این تعطیلات اطمینان دارید؟"
        confirmLabel="بله، حذف کن" danger loading={deleteMut.isPending}
        onConfirm={() => deletingUuid && deleteMut.mutate(deletingUuid)} onCancel={() => setDeletingUuid(null)} />
    </div>
  );
}

// ── Schedule Section ───────────────────────────────────────────────────────

const SCHEDULE_TABS = [
  { id: 'weekly'    as const, label: 'ساعات کاری هفتگی' },
  { id: 'overrides' as const, label: 'تاریخ‌های خاص'    },
  { id: 'holidays'  as const, label: 'تعطیلات'          },
];

export function ScheduleSection({ doctorUuid, clinicUuid, readOnly = false }: { doctorUuid: string; clinicUuid?: string | null; readOnly?: boolean }) {
  const [tab, setTab] = useState<'weekly' | 'overrides' | 'holidays'>('weekly');

  const locationsQ = useQuery({
    queryKey: ['available-locations', doctorUuid, clinicUuid ?? null],
    queryFn:  () => api.get<ApiResponse<any>>(withClinic(`/api/v1/appointment-settings/available-locations/${doctorUuid}`, clinicUuid)),
    enabled:  !!doctorUuid,
    staleTime: 30_000,
  });
  const availableLocations: AddressData[] = locationsQ.data?.data?.data ?? locationsQ.data?.data ?? [];

  return (
    <div className="cp-card p-6">
      <h2 className="text-sm font-semibold text-slate-700 dark:text-slate-300 mb-4">برنامه کاری</h2>
      <div className="flex gap-1 mb-5 bg-slate-100 dark:bg-gray-800 p-1 rounded-xl">
        {SCHEDULE_TABS.map(t => (
          <button key={t.id} type="button" onClick={() => setTab(t.id)}
            className={`flex-1 text-xs sm:text-sm font-medium px-2 py-1.5 rounded-lg transition-colors ${
              tab === t.id
                ? 'bg-white dark:bg-gray-700 text-slate-800 dark:text-slate-100 shadow-sm'
                : 'text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-slate-200'
            }`}>
            {t.label}
          </button>
        ))}
      </div>
      {tab === 'weekly'    && <WeeklyScheduleTab doctorUuid={doctorUuid} clinicUuid={clinicUuid} addresses={availableLocations} readOnly={readOnly} />}
      {tab === 'overrides' && <DateOverridesTab  doctorUuid={doctorUuid} clinicUuid={clinicUuid} addresses={availableLocations} readOnly={readOnly} />}
      {tab === 'holidays'  && <HolidaysTab        doctorUuid={doctorUuid} clinicUuid={clinicUuid} readOnly={readOnly} />}
    </div>
  );
}

