import {
    ArrowDownOnSquareIcon,
    ArrowPathIcon,
    ArrowsRightLeftIcon,
    ClockIcon,
    EllipsisHorizontalIcon,
    EyeIcon,
    PencilIcon,
    PhoneIcon,
    PlusIcon,
    Squares2X2Icon,
    TagIcon,
    UserIcon,
    WalletIcon,
} from "@heroicons/react/24/outline";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import React, { useEffect, useMemo, useRef, useState } from "react";
import ReactDOM from "react-dom";
import { useNavigate } from "react-router-dom";
import { toast } from "sonner";
import type { ApiResponse } from "../lib/api";
import { api } from "../lib/api";
import { formatRial, tehranWallClockToUnix, rialToToman, tomanToRial } from "../lib/utils";
import type { Appointment } from "../types";
import AppointmentStatusDropdown from "./ui/AppointmentStatusDropdown";
import Modal from "./ui/Modal";
import PersianDateInput from "./ui/PersianDateInput";
import PriceInput from "./ui/PriceInput";
import SearchableSelect from "./ui/SearchableSelect";
import ServiceSlotPicker from "./appointments/ServiceSlotPicker";
import type { PickedService, ServicePick } from "./appointments/ServiceSlotPicker";
import { useDoctorBookingServices } from "../hooks/useDoctorBookingServices";

/** Row actions for the appointments table (Figma عملیات menu). */
type ModalKind = null | "info" | "move" | "transfer" | "replace";

const toEpoch = (isoDate: string, time: string) => tehranWallClockToUnix(isoDate, time);

/**
 * Resolve the patient-record uuid behind an appointment via the patient list
 * search (mobile is unique per user). Returns null when no record exists yet.
 */
export async function findRecordUuid(mobile: string): Promise<string | null> {
    const res: any = await api.get(
        `/api/v1/patients?search=${encodeURIComponent(mobile)}&limit=1`,
    );
    return res?.data?.[0]?.uuid ?? null;
}

/**
 * پروندهٔ بیمارِ یک نوبت — اگر هنوز ساخته نشده باشد، از روی خودِ نوبت ساخته می‌شود.
 * «ثبت سرویس» روی نوبتی که صاحبش هنوز پرونده ندارد نباید بن‌بست باشد؛ ساخت پرونده
 * روی سرور idempotent است و پروندهٔ موجود را برمی‌گرداند.
 */
export async function ensureRecordUuid(appointment: {
    patient_mobile?: string | null;
    patient_name?: string | null;
    patient_national_code?: string | null;
}): Promise<string | null> {
    const mobile = (appointment.patient_mobile ?? "").trim();
    if (mobile === "") return null;

    const found = await findRecordUuid(mobile);
    if (found) return found;

    const res: any = await api.post("/api/v1/patient", {
        mobile,
        name: (appointment.patient_name ?? "").trim(),
        ...(appointment.patient_national_code
            ? { national_code: appointment.patient_national_code }
            : {}),
    });

    return res?.data?.uuid ?? null;
}

/**
 * «شارژ کیف پول» accent link (appointment create/edit forms) — deep-links the
 * patient's wallet tab, where the manual top-up modal lives.
 */
export function WalletChargeLink({ mobile }: { mobile?: string }) {
    const navigate = useNavigate();
    const go = async () => {
        if (!mobile || mobile.trim().length < 10) {
            toast.error("ابتدا شماره تماس مراجعه کننده را وارد کنید");
            return;
        }
        try {
            const recordUuid = await findRecordUuid(mobile.trim());
            if (!recordUuid) {
                toast.error("پرونده‌ای برای این بیمار یافت نشد");
                return;
            }
            navigate(`/admin/patients/${recordUuid}?tab=wallet`);
        } catch {
            toast.error("خطا در یافتن پرونده بیمار");
        }
    };
    return (
        <button
            type="button"
            className="btn sm ghost"
            style={{ color: "var(--accent)" }}
            onClick={go}
        >
            شارژ کیف پول ‹
        </button>
    );
}

export default function AppointmentActionsMenu({
    appointment,
    queryKey,
}: {
    appointment: Appointment;
    queryKey: unknown[];
}) {
    const [open, setOpen] = useState(false);
    const [modal, setModal] = useState<ModalKind>(null);
    const [menuPos, setMenuPos] = useState<{
        top: number;
        right: number;
    } | null>(null);
    const btnRef = useRef<HTMLButtonElement>(null);
    const menuRef = useRef<HTMLDivElement>(null);
    const navigate = useNavigate();

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

    const openMenu = () => {
        if (!open && btnRef.current) {
            const r = btnRef.current.getBoundingClientRect();
            setMenuPos({
                top: r.bottom + 4,
                right: window.innerWidth - r.right,
            });
        }
        setOpen((o) => !o);
    };

    const goToServiceRegistration = async () => {
        setOpen(false);
        try {
            const recordUuid = await ensureRecordUuid(appointment);
            if (!recordUuid) {
                toast.error("این نوبت شماره تماس ندارد؛ ابتدا نوبت را ویرایش کنید");
                return;
            }
            navigate(`/admin/patients/${recordUuid}/session/new`);
        } catch (e: any) {
            toast.error(e?.message || "خطا در یافتن پرونده بیمار");
        }
    };

    const items: {
        label: string;
        icon: React.ElementType;
        onClick: () => void;
    }[] = [
        {
            label: "ویرایش",
            icon: PencilIcon,
            onClick: () => {
                setOpen(false);
                navigate(`/admin/appointments/${appointment.uuid}/edit`);
            },
        },
        {
            label: "ثبت سرویس",
            icon: PlusIcon,
            onClick: goToServiceRegistration,
        },
        {
            label: "مشاهده",
            icon: EyeIcon,
            onClick: () => {
                setOpen(false);
                setModal("info");
            },
        },
        {
            label: "جا به جایی نوبت",
            icon: ArrowsRightLeftIcon,
            onClick: () => {
                setOpen(false);
                setModal("move");
            },
        },
        {
            label: appointment.is_reserve
                ? "انتقال به لیست نوبت‌ها"
                : "انتقال به لیست رزرو",
            icon: ArrowDownOnSquareIcon,
            onClick: () => {
                setOpen(false);
                setModal("transfer");
            },
        },
        {
            label: "جایگزینی نوبت",
            icon: ArrowPathIcon,
            onClick: () => {
                setOpen(false);
                setModal("replace");
            },
        },
    ];

    return (
        <>
            <button
                ref={btnRef}
                onClick={openMenu}
                aria-label="عملیات"
                className="btn sm ghost"
                style={{ color: "var(--primary)", gap: 4 }}
            >
                <EllipsisHorizontalIcon style={{ width: 18 }} /> عملیات
            </button>

            {open &&
                menuPos &&
                ReactDOM.createPortal(
                    <div
                        ref={menuRef}
                        style={{
                            position: "fixed",
                            top: menuPos.top,
                            right: menuPos.right,
                            zIndex: 9000,
                            background: "var(--surface)",
                            border: "1px solid var(--border)",
                            borderRadius: "var(--r)",
                            boxShadow: "var(--shadow-lg)",
                            minWidth: 190,
                            overflow: "hidden",
                        }}
                    >
                        {items.map(({ label, icon: Icon, onClick }) => (
                            <button
                                key={label}
                                onClick={onClick}
                                style={{
                                    display: "flex",
                                    alignItems: "center",
                                    gap: 8,
                                    width: "100%",
                                    padding: "9px 12px",
                                    fontSize: 13,
                                    background: "transparent",
                                    border: "none",
                                    cursor: "pointer",
                                    color: "var(--text)",
                                    fontFamily: "inherit",
                                    textAlign: "right",
                                }}
                                onMouseEnter={(e) =>
                                    (e.currentTarget.style.background =
                                        "var(--surface-2)")
                                }
                                onMouseLeave={(e) =>
                                    (e.currentTarget.style.background =
                                        "transparent")
                                }
                            >
                                <Icon
                                    style={{
                                        width: 15,
                                        color: "var(--text-2)",
                                    }}
                                />{" "}
                                {label}
                            </button>
                        ))}
                    </div>,
                    document.body,
                )}

            {modal === "info" && (
                <AppointmentInfoModal
                    appointment={appointment}
                    queryKey={queryKey}
                    onClose={() => setModal(null)}
                />
            )}
            {modal === "move" && (
                <MoveAppointmentModal
                    appointment={appointment}
                    queryKey={queryKey}
                    onClose={() => setModal(null)}
                />
            )}
            {modal === "transfer" && (
                <TransferReserveModal
                    appointment={appointment}
                    queryKey={queryKey}
                    onClose={() => setModal(null)}
                />
            )}
            {modal === "replace" && (
                <ReplaceAppointmentModal
                    appointment={appointment}
                    queryKey={queryKey}
                    onClose={() => setModal(null)}
                />
            )}
        </>
    );
}

// ─────────────────────────────────────────────────────────────────────────────
// مشاهده — appointment info + patient wallet balance (Figma appointments-info)
// ─────────────────────────────────────────────────────────────────────────────

function InfoRow({
    icon: Icon,
    label,
    value,
    ltr,
}: {
    icon: React.ElementType;
    label: string;
    value?: string | null;
    ltr?: boolean;
}) {
    return (
        <div
            style={{
                display: "flex",
                justifyContent: "space-between",
                alignItems: "center",
                padding: "11px 0",
                borderBottom: "1px solid var(--border)",
                gap: 12,
            }}
        >
            <span
                style={{
                    display: "inline-flex",
                    alignItems: "center",
                    gap: 7,
                    fontSize: 13,
                    color: "var(--text-2)",
                }}
            >
                <Icon style={{ width: 16, color: "var(--text-3)" }} /> {label}
            </span>
            <span
                style={{
                    fontSize: 13.5,
                    fontWeight: 600,
                    color: "var(--text)",
                    direction: ltr ? "ltr" : undefined,
                }}
            >
                {value || "—"}
            </span>
        </div>
    );
}

export function AppointmentInfoModal({
    appointment: a,
    queryKey,
    onClose,
}: {
    appointment: Appointment;
    queryKey: unknown[];
    onClose: () => void;
}) {
    const navigate = useNavigate();

    // record uuid → wallet balance + «مشاهده پرونده» target (both need the record)
    const recordQ = useQuery<string | null>({
        queryKey: ["appt-record", a.patient_mobile],
        queryFn: () => findRecordUuid(a.patient_mobile),
    });
    const walletQ = useQuery<ApiResponse<{ balance_rials: number }>>({
        queryKey: ["appt-wallet", recordQ.data],
        queryFn: () => api.get(`/api/v1/patient/${recordQ.data}/wallet`),
        enabled: !!recordQ.data,
    });

    const durationMin = Math.max(
        0,
        Math.round((a.slot_end - a.slot_start) / 60),
    );

    return (
        <Modal open title={a.patient_name || "نوبت"} onClose={onClose}>
            <div>
                <InfoRow
                    icon={ClockIcon}
                    label="ساعت شروع:"
                    value={a.appointment_time}
                    ltr
                />
                <InfoRow
                    icon={ClockIcon}
                    label="مدت انجام:"
                    value={`${durationMin.toLocaleString("fa-IR")} دقیقه`}
                />
                <InfoRow
                    icon={PhoneIcon}
                    label="تلفن:"
                    value={a.patient_mobile}
                    ltr
                />
                <InfoRow
                    icon={Squares2X2Icon}
                    label="بخش:"
                    value={a.service_section?.name}
                />
                <InfoRow
                    icon={TagIcon}
                    label="سرویس:"
                    value={a.service_item?.name}
                />
                <InfoRow
                    icon={UserIcon}
                    label="پرسنل:"
                    value={a.staff?.full_name}
                />
                <InfoRow
                    icon={WalletIcon}
                    label="موجودی کیف پول:"
                    value={
                        walletQ.data?.data
                            ? `${formatRial(walletQ.data.data.balance_rials)}`
                            : undefined
                    }
                />

                <div style={{ margin: "14px 0" }}>
                    <AppointmentStatusDropdown
                        uuid={a.uuid}
                        currentStatus={a.status}
                        version={a.version}
                        queryKey={queryKey}
                    />
                </div>

                <button
                    className="btn"
                    style={{
                        width: "100%",
                        color: "var(--primary)",
                        border: "1px solid var(--primary-soft2, var(--border))",
                        background: "var(--primary-soft)",
                    }}
                    disabled={!recordQ.data}
                    onClick={() =>
                        recordQ.data &&
                        navigate(`/admin/patients/${recordQ.data}`)
                    }
                >
                    مشاهده پرونده
                </button>
            </div>
        </Modal>
    );
}

// ─────────────────────────────────────────────────────────────────────────────
// جا به جایی نوبت — pick a new date + start/end time
// ─────────────────────────────────────────────────────────────────────────────

export function MoveAppointmentModal({
    appointment: a,
    queryKey,
    onClose,
}: {
    appointment: Appointment;
    queryKey: unknown[];
    onClose: () => void;
}) {
    const qc = useQueryClient();
    const [date, setDate] = useState(a.appointment_date);
    const [start, setStart] = useState(a.appointment_time);
    const [end, setEnd] = useState(a.end_time);

    const move = useMutation({
        mutationFn: () =>
            api.patch(`/api/v1/appointment/${a.uuid}`, {
                slot_start: toEpoch(date, start),
                slot_end: toEpoch(date, end),
                version: a.version,
            }),
        onSuccess: () => {
            qc.invalidateQueries({ queryKey });
            toast.success("نوبت جا به جا شد");
            onClose();
        },
        onError: (e: any) => toast.error(e.message || "خطا در جا به جایی نوبت"),
    });

    return (
        <Modal open title="جا به جایی نوبت" onClose={onClose}>
            <div>
                <label style={{ fontSize: 12.5, color: "var(--text-3)" }}>
                    انتخاب تاریخ
                </label>
                <div style={{ margin: "6px 0 12px" }}>
                    <PersianDateInput value={date} onChange={setDate} />
                </div>
                <div style={{ display: "flex", gap: 10, marginBottom: 16 }}>
                    <div style={{ flex: 1 }}>
                        <label
                            style={{ fontSize: 12.5, color: "var(--text-3)" }}
                        >
                            ساعت شروع
                        </label>
                        <div className="field" style={{ marginTop: 6 }}>
                            <input
                                aria-label="ساعت شروع"
                                type="time"
                                value={start}
                                onChange={(e) => setStart(e.target.value)}
                                dir="ltr"
                            />
                        </div>
                    </div>
                    <div style={{ flex: 1 }}>
                        <label
                            style={{ fontSize: 12.5, color: "var(--text-3)" }}
                        >
                            ساعت پایان
                        </label>
                        <div className="field" style={{ marginTop: 6 }}>
                            <input
                                aria-label="ساعت پایان"
                                type="time"
                                value={end}
                                onChange={(e) => setEnd(e.target.value)}
                                dir="ltr"
                            />
                        </div>
                    </div>
                </div>
                <button
                    className="btn primary"
                    style={{ width: "100%" }}
                    disabled={!date || !start || !end || move.isPending}
                    onClick={() => move.mutate()}
                >
                    اعمال تغییرات
                </button>
            </div>
        </Modal>
    );
}

// ─────────────────────────────────────────────────────────────────────────────
// انتقال به لیست رزرو (و بازگشت) — flips is_reserve for a chosen day
// ─────────────────────────────────────────────────────────────────────────────

export function TransferReserveModal({
    appointment: a,
    queryKey,
    onClose,
}: {
    appointment: Appointment;
    queryKey: unknown[];
    onClose: () => void;
}) {
    const qc = useQueryClient();
    const [date, setDate] = useState(a.appointment_date);
    const toReserve = !a.is_reserve;

    // روش نوبت‌دهی از محلِ خودِ نوبت، نه محیط جاری پنل.
    const { bookingMode, services } = useDoctorBookingServices(
        toReserve ? undefined : a.doctor_uuid,
        a.clinic_uuid ?? null,
    );
    const serviceMode = !toReserve && bookingMode === "service";

    // بازگشت از رزرو به لیست نوبت‌ها به زمان واقعی نیاز دارد. پیش از این از
    // appointment_time/end_time خوانده می‌شد که روی یک رزرو هر دو 00:00 اند — نتیجه،
    // نوبتی با مدت صفر در نیمه‌شب بود.
    const [pick, setPick] = useState<ServicePick | null>(null);
    const [start, setStart] = useState("");
    const [end, setEnd] = useState("");

    const initialSelection = useMemo<PickedService[]>(() => {
        if (!a.service_items?.length || services.length === 0) return [];
        return a.service_items.flatMap((s) => {
            const known = services.find((b) => b.uuid === s.uuid);
            return known
                ? [{
                      uuid: known.uuid,
                      name: known.name,
                      section: known.service_section.name,
                      duration: known.duration_minutes ?? 0,
                  }]
                : [];
        });
    }, [a.service_items, services]);

    const canSubmit = !!date && (toReserve
        ? true
        : serviceMode
            ? !!pick?.slot && (pick?.serviceUuids.length ?? 0) > 0
            : !!start && !!end);

    const transfer = useMutation({
        mutationFn: async () => {
            const day = toEpoch(date, "00:00");

            if (toReserve) {
                // reserve entries are day-level: midnight-to-midnight, no slot occupation
                return api.patch(`/api/v1/appointment/${a.uuid}`, {
                    is_reserve: true,
                    slot_start: day,
                    slot_end: day,
                    version: a.version,
                });
            }

            if (serviceMode) {
                // ابتدا زمان‌دار شود (رزرو زمان ندارد و service-reschedule رزرو را رد می‌کند)،
                // سپس مدت و سرویس‌ها با endpoint سرویس‌آگاه تثبیت شوند.
                await api.patch(`/api/v1/appointment/${a.uuid}`, {
                    is_reserve: false,
                    slot_start: pick!.slot!.start,
                    slot_end: pick!.slot!.end,
                    service_item_uuids: pick!.serviceUuids,
                    durations: pick!.durations,
                    version: a.version,
                });
                return api.post(`/api/v1/appointment/${a.uuid}/service-reschedule`, {
                    start: pick!.slot!.start,
                    service_item_uuids: pick!.serviceUuids,
                    durations: pick!.durations,
                });
            }

            return api.patch(`/api/v1/appointment/${a.uuid}`, {
                is_reserve: false,
                slot_start: toEpoch(date, start),
                slot_end: toEpoch(date, end),
                version: a.version,
            });
        },
        onSuccess: () => {
            qc.invalidateQueries({ queryKey });
            toast.success(
                toReserve
                    ? "به لیست رزرو منتقل شد"
                    : "به لیست نوبت‌ها منتقل شد",
            );
            onClose();
        },
        onError: (e: any) => toast.error(e.message || "خطا در انتقال"),
    });

    return (
        <Modal
            open
            title={toReserve ? "انتقال به لیست رزرو" : "انتقال به لیست نوبت‌ها"}
            onClose={onClose}
        >
            <div>
                <div
                    style={{
                        display: "flex",
                        gap: 8,
                        alignItems: "flex-start",
                        background: "var(--warning-bg)",
                        border: "1px solid var(--border)",
                        borderRadius: "var(--r)",
                        padding: "10px 12px",
                        marginBottom: 14,
                        fontSize: 12.5,
                        color: "var(--text-2)",
                    }}
                >
                    <span style={{ color: "var(--warning)", fontWeight: 800 }}>
                        !
                    </span>
                    {toReserve
                        ? "نوبت از لیست نوبت ها حذف شده و به لیست نوبت های رزرو شده منتقل می شود."
                        : "نوبت از لیست رزرو حذف شده و به لیست نوبت ها منتقل می شود."}
                </div>
                <label style={{ fontSize: 12.5, color: "var(--text-3)" }}>
                    انتخاب تاریخ
                </label>
                <div style={{ margin: "6px 0 16px" }}>
                    <PersianDateInput value={date} onChange={setDate} />
                </div>

                {/* بازگشت به لیست نوبت‌ها زمان لازم دارد؛ رزرو زمانی ندارد که ارث ببرد. */}
                {!toReserve && serviceMode && date && (
                    <div style={{ marginBottom: 16 }}>
                        <ServiceSlotPicker
                            doctorUuid={a.doctor_uuid}
                            date={date}
                            services={services}
                            clinicUuidOverride={a.clinic_uuid ?? null}
                            excludeAppointmentUuid={a.uuid}
                            initialSelection={initialSelection}
                            onSelect={setPick}
                        />
                    </div>
                )}

                {!toReserve && !serviceMode && (
                    <div style={{ display: "flex", gap: 10, marginBottom: 16 }}>
                        <div style={{ flex: 1 }}>
                            <label style={{ fontSize: 12.5, color: "var(--text-3)" }}>
                                ساعت شروع
                            </label>
                            <div className="field" style={{ marginTop: 6 }}>
                                <input
                                    aria-label="ساعت شروع"
                                    type="time"
                                    value={start}
                                    onChange={(e) => setStart(e.target.value)}
                                    dir="ltr"
                                />
                            </div>
                        </div>
                        <div style={{ flex: 1 }}>
                            <label style={{ fontSize: 12.5, color: "var(--text-3)" }}>
                                ساعت پایان
                            </label>
                            <div className="field" style={{ marginTop: 6 }}>
                                <input
                                    aria-label="ساعت پایان"
                                    type="time"
                                    value={end}
                                    onChange={(e) => setEnd(e.target.value)}
                                    dir="ltr"
                                />
                            </div>
                        </div>
                    </div>
                )}

                <div style={{ display: "flex", gap: 8 }}>
                    <button
                        className="btn primary"
                        style={{ flex: 1 }}
                        disabled={!canSubmit || transfer.isPending}
                        onClick={() => transfer.mutate()}
                    >
                        انتقال و حذف از لیست
                    </button>
                    <button
                        className="btn"
                        style={{ flex: 1 }}
                        onClick={onClose}
                    >
                        انصراف
                    </button>
                </div>
            </div>
        </Modal>
    );
}

// ─────────────────────────────────────────────────────────────────────────────
// جایگزینی نوبت — put a different patient into the same slot
// (appointments-replace.pdf: patient search-or-new, بخش/سرویس, deposit,
//  locked date/time, پرسنل, وضعیت, توضیحات)
// ─────────────────────────────────────────────────────────────────────────────

interface PickerOption {
    uuid: string;
    name?: string;
    full_name?: string;
}
interface PickedPatient {
    uuid: string;
    user_name?: string;
    user_mobile?: string;
}

export function ReplaceAppointmentModal({
    appointment: a,
    queryKey,
    onClose,
}: {
    appointment: Appointment;
    queryKey: unknown[];
    onClose: () => void;
}) {
    const qc = useQueryClient();

    // patient: search an existing record or enter a new person
    const [patientSearch, setPatientSearch] = useState("");
    const [picked, setPicked] = useState<PickedPatient | null>(null);
    const [name, setName] = useState("");
    const [mobile, setMobile] = useState("");
    const patientsQ = useQuery<ApiResponse<PickedPatient[]>>({
        queryKey: ["replace-patients", patientSearch],
        queryFn: () =>
            api.get(
                `/api/v1/patients?search=${encodeURIComponent(patientSearch)}&limit=10`,
            ),
        enabled: patientSearch.trim().length >= 2,
    });

    // service specs + staff + status
    const [sectionUuid, setSectionUuid] = useState(
        a.service_section?.uuid ?? "",
    );
    const [itemUuid, setItemUuid] = useState(a.service_item?.uuid ?? "");
    const [staffUuid, setStaffUuid] = useState(a.staff?.uuid ?? "");
    const [status, setStatus] = useState(a.status);
    const sectionsQ = useQuery<ApiResponse<PickerOption[]>>({
        queryKey: ["service-sections"],
        queryFn: () => api.get("/api/v1/service-sections"),
    });
    const itemsQ = useQuery<ApiResponse<PickerOption[]>>({
        queryKey: ["service-items", sectionUuid],
        queryFn: () => api.get(`/api/v1/service-items/${sectionUuid}`),
        enabled: !!sectionUuid,
    });
    const staffQ = useQuery<ApiResponse<PickerOption[]>>({
        queryKey: ["staff-list"],
        queryFn: () => api.get("/api/v1/staff"),
    });

    // deposit
    const [depositRequired, setDepositRequired] = useState(
        !!a.deposit_required,
    );
    const [depositToman, setDepositToman] = useState(
        rialToToman(a.deposit_amount_rials ?? 0),
    );
    const [note, setNote] = useState("");

    const effectiveName = picked?.user_name || name.trim();
    const effectiveMobile = picked?.user_mobile || mobile.trim();

    const replace = useMutation({
        mutationFn: () =>
            api.patch(`/api/v1/appointment/${a.uuid}`, {
                patient_name: effectiveName,
                patient_mobile: effectiveMobile,
                service_section_uuid: sectionUuid,
                service_item_uuid: itemUuid,
                staff_uuid: staffUuid,
                deposit_required: depositRequired,
                deposit_amount_rials: depositRequired ? tomanToRial(depositToman) : null,
                ...(note.trim() ? { note: note.trim() } : {}),
                ...(status !== a.status ? { status } : {}),
                version: a.version,
            }),
        onSuccess: () => {
            qc.invalidateQueries({ queryKey });
            toast.success("نوبت جایگزین شد");
            onClose();
        },
        onError: (e: any) => toast.error(e.message || "خطا در جایگزینی نوبت"),
    });

    const label = { fontSize: 12.5, color: "var(--text-3)" } as const;
    const lockedField = { margin: "6px 0 12px", opacity: 0.6 } as const;
    const patients = patientsQ.data?.data ?? [];

    const statusOptions: [string, string][] = [
        ["pending", "ثبت شده"],
        ["confirmed", "قطعی شده"],
        ["following_up", "در حال پیگیری"],
        ["salon", "سالن"],
        ["completed", "ویزیت شده"],
        ["cancelled_by_doctor", "لغو شده"],
    ];

    return (
        <Modal open title="جایگزینی نوبت" onClose={onClose}>
            <div>
                <label style={label}>انتخاب مراجعه کننده</label>
                <div className="field" style={{ margin: "6px 0 8px" }}>
                    <input
                        value={
                            picked
                                ? `${picked.user_name ?? ""} — ${picked.user_mobile ?? ""}`
                                : patientSearch
                        }
                        onChange={(e) => {
                            setPicked(null);
                            setPatientSearch(e.target.value);
                        }}
                        placeholder="جستجوی نام، شماره تماس، شماره پرونده..."
                    />
                </div>
                {!picked && patients.length > 0 && (
                    <div
                        style={{
                            border: "1px solid var(--border)",
                            borderRadius: "var(--r-sm)",
                            marginBottom: 10,
                            overflow: "hidden",
                        }}
                    >
                        {patients.map((p) => (
                            <button
                                key={p.uuid}
                                onClick={() => setPicked(p)}
                                style={{
                                    display: "block",
                                    width: "100%",
                                    padding: "8px 10px",
                                    fontSize: 13,
                                    textAlign: "right",
                                    background: "transparent",
                                    border: "none",
                                    cursor: "pointer",
                                    fontFamily: "inherit",
                                }}
                            >
                                {p.user_name}{" "}
                                <span
                                    style={{
                                        color: "var(--text-3)",
                                        direction: "ltr",
                                    }}
                                >
                                    {p.user_mobile}
                                </span>
                            </button>
                        ))}
                    </div>
                )}
                {picked === null && (
                    <div
                        style={{
                            display: "grid",
                            gridTemplateColumns: "1fr 1fr",
                            gap: 10,
                            marginBottom: 12,
                        }}
                    >
                        <div className="field">
                            <input
                                value={name}
                                onChange={(e) => setName(e.target.value)}
                                placeholder="نام و نام خانوادگی"
                            />
                        </div>
                        <div className="field">
                            <input
                                value={mobile}
                                onChange={(e) => setMobile(e.target.value)}
                                placeholder="شماره تماس"
                                dir="ltr"
                            />
                        </div>
                    </div>
                )}

                <div
                    style={{
                        display: "grid",
                        gridTemplateColumns: "1fr 1fr",
                        gap: 10,
                        marginBottom: 12,
                    }}
                >
                    <div>
                        <label style={label}>بخش</label>
                        <div style={{ marginTop: 6 }}>
                            <SearchableSelect
                                options={(sectionsQ.data?.data ?? []).map((o) => ({ value: o.uuid, label: o.name ?? "" }))}
                                value={sectionUuid || null}
                                onChange={(v) => { setSectionUuid(v ? String(v) : ""); setItemUuid(""); }}
                                placeholder="انتخاب بخش"
                                isLoading={sectionsQ.isLoading}
                                isClearable
                                height={38}
                            />
                        </div>
                    </div>
                    <div>
                        <label style={label}>سرویس</label>
                        <div style={{ marginTop: 6 }}>
                            <SearchableSelect
                                options={(itemsQ.data?.data ?? []).map((o) => ({ value: o.uuid, label: o.name ?? "" }))}
                                value={itemUuid || null}
                                onChange={(v) => setItemUuid(v ? String(v) : "")}
                                placeholder="انتخاب زیر بخش"
                                isDisabled={!sectionUuid}
                                isLoading={itemsQ.isLoading}
                                isClearable
                                height={38}
                            />
                        </div>
                    </div>
                </div>

                <div
                    style={{
                        display: "flex",
                        alignItems: "center",
                        justifyContent: "space-between",
                        gap: 10,
                        flexWrap: "wrap",
                        marginBottom: 12,
                    }}
                >
                    <label
                        style={{
                            display: "inline-flex",
                            alignItems: "center",
                            gap: 8,
                            fontSize: 13,
                            cursor: "pointer",
                        }}
                    >
                        <input
                            type="checkbox"
                            checked={depositRequired}
                            onChange={(e) =>
                                setDepositRequired(e.target.checked)
                            }
                        />
                        بیعانه مورد نیاز است.
                    </label>
                    {depositRequired && (
                        <WalletChargeLink mobile={effectiveMobile} />
                    )}
                </div>
                {depositRequired && (
                    <div style={{ marginBottom: 12 }}>
                        <label style={label}>مبلغ بیعانه (تومان)</label>
                        <div style={{ marginTop: 6 }}>
                            <PriceInput
                                value={depositToman}
                                onChange={setDepositToman}
                            />
                        </div>
                    </div>
                )}

                {/* the replacement keeps the original slot — date/time locked */}
                <div
                    style={{
                        display: "grid",
                        gridTemplateColumns: "1fr 1fr",
                        gap: 10,
                    }}
                >
                    <div>
                        <label style={label}>انتخاب تاریخ</label>
                        <div className="field" style={lockedField}>
                            <input
                                value={a.appointment_date}
                                disabled
                                dir="ltr"
                            />
                        </div>
                    </div>
                    <div>
                        <label style={label}>ساعت شروع</label>
                        <div className="field" style={lockedField}>
                            <input
                                value={a.appointment_time}
                                disabled
                                dir="ltr"
                            />
                        </div>
                    </div>
                </div>

                <label style={label}>انتخاب پرسنل</label>
                <div style={{ margin: "6px 0 12px" }}>
                    <SearchableSelect
                        options={(staffQ.data?.data ?? []).map((o) => ({ value: o.uuid, label: o.full_name ?? "" }))}
                        value={staffUuid || null}
                        onChange={(v) => setStaffUuid(v ? String(v) : "")}
                        placeholder="انتخاب..."
                        isLoading={staffQ.isLoading}
                        isClearable
                        height={38}
                    />
                </div>

                <label style={label}>انتخاب وضعیت</label>
                <div style={{ margin: "6px 0 12px" }}>
                    <SearchableSelect
                        options={statusOptions.map(([v, l]) => ({ value: v, label: l }))}
                        value={status || null}
                        onChange={(v) => setStatus((v ? String(v) : "") as Appointment["status"])}
                        placeholder="انتخاب وضعیت"
                        height={38}
                    />
                </div>

                <label style={label}>توضیحات</label>
                <div
                    className="field"
                    style={{ height: "auto", margin: "6px 0 16px" }}
                >
                    <textarea
                        value={note}
                        onChange={(e) => setNote(e.target.value)}
                        rows={3}
                        placeholder="توضیحات..."
                        style={{
                            width: "100%",
                            border: "none",
                            background: "transparent",
                            fontFamily: "inherit",
                            resize: "vertical",
                        }}
                    />
                </div>

                <button
                    className="btn primary"
                    style={{ width: "100%" }}
                    disabled={
                        effectiveName.length < 2 ||
                        effectiveMobile.length < 10 ||
                        replace.isPending
                    }
                    onClick={() => replace.mutate()}
                >
                    ثبت نوبت
                </button>
            </div>
        </Modal>
    );
}
