import { useCallback, useEffect, useMemo, useState } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faStethoscope, faPlus, faPenToSquare } from '@fortawesome/pro-duotone-svg-icons';
import { Button } from '@/components/base/buttons/button';
import { Badge } from '@/components/base/badges/badges';
import { Table, TableCard } from '@/components/application/table/table';
import { SlideoutMenu } from '@/components/application/slideout-menus/slideout-menu';
import { TopBar } from '@/components/layout/top-bar';
import {
    DoctorForm,
    doctorCoreToGraphQLInput,
    visitSlotInputsFromForm,
    emptyDoctorFormValues,
    type DoctorDepartment,
    type DoctorFormValues,
    type DayOfWeek,
    type DoctorVisitSlotEntry,
} from '@/components/forms/doctor-form';
import { apiClient } from '@/lib/api-client';
import { notify } from '@/lib/toast';
import { markSetupStepComplete } from '@/lib/setup-state';

// /settings/doctors — list + add/edit slideout. Doctors are hospital-
// wide; their multi-clinic visiting schedule is modelled as a list of
// DoctorVisitSlot child records fetched through the reverse relation.
//
// Save flow mirrors clinics.tsx: create/update the core doctor row,
// then delete-all-recreate the visit slots. Slots are recreated in
// parallel (Promise.all). Pre-existing slots from the fetched record
// get their id propagated into form state so edit mode shows the
// current schedule.

type DoctorNode = {
    id: string;
    fullName: { firstName: string | null; lastName: string | null } | null;
    department: DoctorDepartment | null;
    specialty: string | null;
    qualifications: string | null;
    yearsOfExperience: number | null;
    consultationFeeNew: { amountMicros: number | null; currencyCode: string | null } | null;
    consultationFeeFollowUp: { amountMicros: number | null; currencyCode: string | null } | null;
    phone: { primaryPhoneNumber: string | null } | null;
    email: { primaryEmail: string | null } | null;
    registrationNumber: string | null;
    active: boolean | null;
    // Reverse-side relation to DoctorVisitSlot records.
    doctorVisitSlots?: {
        edges: Array<{
            node: {
                id: string;
                clinicId: string | null;
                clinic: { id: string; clinicName: string | null } | null;
                dayOfWeek: DayOfWeek | null;
                startTime: string | null;
                endTime: string | null;
            };
        }>;
    };
};

type ClinicLite = { id: string; clinicName: string | null };

const DOCTORS_QUERY = `{
    doctors(first: 100) {
        edges {
            node {
                id
                fullName { firstName lastName }
                department specialty qualifications yearsOfExperience
                consultationFeeNew { amountMicros currencyCode }
                consultationFeeFollowUp { amountMicros currencyCode }
                phone { primaryPhoneNumber }
                email { primaryEmail }
                registrationNumber
                active
                doctorVisitSlots(first: 50) {
                    edges {
                        node {
                            id
                            clinicId
                            clinic { id clinicName }
                            dayOfWeek
                            startTime
                            endTime
                        }
                    }
                }
            }
        }
    }
    clinics(first: 100) { edges { node { id clinicName } } }
}`;

const departmentLabel: Record<DoctorDepartment, string> = {
    CARDIOLOGY: 'Cardiology',
    GYNECOLOGY: 'Gynecology',
    ORTHOPEDICS: 'Orthopedics',
    GENERAL_MEDICINE: 'General medicine',
    ENT: 'ENT',
    DERMATOLOGY: 'Dermatology',
    PEDIATRICS: 'Pediatrics',
    ONCOLOGY: 'Oncology',
};

const dayLabel: Record<DayOfWeek, string> = {
    MONDAY: 'Mon',
    TUESDAY: 'Tue',
    WEDNESDAY: 'Wed',
    THURSDAY: 'Thu',
    FRIDAY: 'Fri',
    SATURDAY: 'Sat',
    SUNDAY: 'Sun',
};

const toFormValues = (doctor: DoctorNode): DoctorFormValues => ({
    firstName: doctor.fullName?.firstName ?? '',
    lastName: doctor.fullName?.lastName ?? '',
    department: doctor.department ?? '',
    specialty: doctor.specialty ?? '',
    qualifications: doctor.qualifications ?? '',
    yearsOfExperience: doctor.yearsOfExperience != null ? String(doctor.yearsOfExperience) : '',
    consultationFeeNew: doctor.consultationFeeNew?.amountMicros
        ? String(Math.round(doctor.consultationFeeNew.amountMicros / 1_000_000))
        : '',
    consultationFeeFollowUp: doctor.consultationFeeFollowUp?.amountMicros
        ? String(Math.round(doctor.consultationFeeFollowUp.amountMicros / 1_000_000))
        : '',
    phone: doctor.phone?.primaryPhoneNumber ?? '',
    email: doctor.email?.primaryEmail ?? '',
    registrationNumber: doctor.registrationNumber ?? '',
    active: doctor.active ?? true,
    visitSlots:
        doctor.doctorVisitSlots?.edges.map(
            (e): DoctorVisitSlotEntry => ({
                id: e.node.id,
                clinicId: e.node.clinicId ?? e.node.clinicId ?? '',
                dayOfWeek: e.node.dayOfWeek ?? '',
                startTime: e.node.startTime ?? null,
                endTime: e.node.endTime ?? null,
            }),
        ) ?? [],
});

const formatFee = (money: { amountMicros: number | null } | null): string => {
    if (!money?.amountMicros) return '—';
    return `₹${Math.round(money.amountMicros / 1_000_000).toLocaleString('en-IN')}`;
};

// Compact "clinics + days" summary for the list row. Groups by clinic
// so "Koramangala: Mon Wed / Whitefield: Tue Thu Fri" is one string.
const summariseVisitSlots = (
    doctor: DoctorNode,
    clinicNameById: Map<string, string>,
): string => {
    const edges = doctor.doctorVisitSlots?.edges ?? [];
    if (edges.length === 0) return 'No slots';
    const byClinic = new Map<string, DayOfWeek[]>();
    for (const e of edges) {
        const cid = e.node.clinicId ?? e.node.clinicId;
        if (!cid || !e.node.dayOfWeek) continue;
        if (!byClinic.has(cid)) byClinic.set(cid, []);
        byClinic.get(cid)!.push(e.node.dayOfWeek);
    }
    const parts: string[] = [];
    for (const [cid, days] of byClinic.entries()) {
        const name = clinicNameById.get(cid) ?? 'Unknown clinic';
        const dayStr = days.map((d) => dayLabel[d]).join(' ');
        parts.push(`${name}: ${dayStr}`);
    }
    return parts.join(' · ');
};

// -- Mutation helpers --------------------------------------------------------

const createDoctorMutation = (data: Record<string, unknown>) =>
    apiClient.graphql<{ createDoctor: { id: string } }>(
        `mutation CreateDoctor($data: DoctorCreateInput!) {
            createDoctor(data: $data) { id }
        }`,
        { data },
    );

const updateDoctorMutation = (id: string, data: Record<string, unknown>) =>
    apiClient.graphql<{ updateDoctor: { id: string } }>(
        `mutation UpdateDoctor($id: UUID!, $data: DoctorUpdateInput!) {
            updateDoctor(id: $id, data: $data) { id }
        }`,
        { id, data },
    );

const createVisitSlotMutation = (data: Record<string, unknown>) =>
    apiClient.graphql(
        `mutation CreateDoctorVisitSlot($data: DoctorVisitSlotCreateInput!) {
            createDoctorVisitSlot(data: $data) { id }
        }`,
        { data },
    );

const deleteVisitSlotMutation = (id: string) =>
    apiClient.graphql(
        `mutation DeleteDoctorVisitSlot($id: UUID!) {
            deleteDoctorVisitSlot(id: $id) { id }
        }`,
        { id },
    );

// -- Page --------------------------------------------------------------------

export const DoctorsPage = () => {
    const [doctors, setDoctors] = useState<DoctorNode[]>([]);
    const [clinics, setClinics] = useState<ClinicLite[]>([]);
    const [loading, setLoading] = useState(true);
    const [slideoutOpen, setSlideoutOpen] = useState(false);
    const [editTarget, setEditTarget] = useState<DoctorNode | null>(null);
    const [formValues, setFormValues] = useState<DoctorFormValues>(emptyDoctorFormValues);
    const [isSaving, setIsSaving] = useState(false);

    const fetchAll = useCallback(async () => {
        try {
            const data = await apiClient.graphql<{
                doctors: { edges: { node: DoctorNode }[] };
                clinics: { edges: { node: ClinicLite }[] };
            }>(DOCTORS_QUERY);
            setDoctors(data.doctors.edges.map((e) => e.node));
            setClinics(data.clinics.edges.map((e) => e.node));
        } catch {
            // toast already shown by apiClient
        } finally {
            setLoading(false);
        }
    }, []);

    useEffect(() => {
        fetchAll();
    }, [fetchAll]);

    const clinicOptions = useMemo(
        () =>
            clinics.map((c) => ({
                id: c.id,
                label: c.clinicName ?? 'Unnamed clinic',
            })),
        [clinics],
    );

    const clinicNameById = useMemo(() => {
        const map = new Map<string, string>();
        for (const c of clinics) {
            if (c.clinicName) map.set(c.id, c.clinicName);
        }
        return map;
    }, [clinics]);

    const handleAdd = () => {
        setEditTarget(null);
        setFormValues(emptyDoctorFormValues());
        setSlideoutOpen(true);
    };

    const handleEdit = (doctor: DoctorNode) => {
        setEditTarget(doctor);
        setFormValues(toFormValues(doctor));
        setSlideoutOpen(true);
    };

    const handleSave = async (close: () => void) => {
        if (!formValues.firstName.trim() || !formValues.lastName.trim()) {
            notify.error('First and last name are required');
            return;
        }
        setIsSaving(true);
        try {
            const coreInput = doctorCoreToGraphQLInput(formValues);

            // 1. Upsert doctor
            let doctorId: string;
            if (editTarget) {
                await updateDoctorMutation(editTarget.id, coreInput);
                doctorId = editTarget.id;
            } else {
                const res = await createDoctorMutation(coreInput);
                doctorId = res.createDoctor.id;
                notify.success('Doctor added', `Dr. ${formValues.firstName} ${formValues.lastName}`);
                markSetupStepComplete('doctors').catch(() => {});
            }

            // 2. Visit slots — delete-all-recreate, same pattern as
            // clinics.tsx holidays/requiredDocs. Simple, always correct,
            // acceptable overhead at human-edit frequency.
            if (editTarget?.doctorVisitSlots?.edges?.length) {
                await Promise.all(
                    editTarget.doctorVisitSlots.edges.map((e) => deleteVisitSlotMutation(e.node.id)),
                );
            }
            const slotInputs = visitSlotInputsFromForm(formValues, doctorId);
            if (slotInputs.length > 0) {
                await Promise.all(slotInputs.map((data) => createVisitSlotMutation(data)));
            }

            if (editTarget) {
                notify.success('Doctor updated', `Dr. ${formValues.firstName} ${formValues.lastName}`);
            }
            await fetchAll();
            close();
        } catch (err) {
            console.error('[doctors] save failed', err);
        } finally {
            setIsSaving(false);
        }
    };

    const activeCount = useMemo(() => doctors.filter((d) => d.active).length, [doctors]);

    return (
        <div className="flex flex-1 flex-col overflow-hidden">
            <TopBar title="Doctors" subtitle="Manage clinicians and appointment booking" />

            <div className="flex-1 overflow-y-auto p-6">
                <TableCard.Root size="sm">
                    <TableCard.Header
                        title="Clinicians"
                        badge={doctors.length}
                        description={`${activeCount} accepting appointments`}
                        contentTrailing={
                            <Button
                                size="sm"
                                color="primary"
                                iconLeading={({ className }: { className?: string }) => (
                                    <FontAwesomeIcon icon={faPlus} className={className} />
                                )}
                                onClick={handleAdd}
                            >
                                Add doctor
                            </Button>
                        }
                    />
                    {loading ? (
                        <div className="flex items-center justify-center py-12">
                            <p className="text-sm text-tertiary">Loading doctors...</p>
                        </div>
                    ) : doctors.length === 0 ? (
                        <div className="flex flex-col items-center justify-center gap-3 py-16">
                            <div className="flex size-12 items-center justify-center rounded-full bg-brand-secondary">
                                <FontAwesomeIcon icon={faStethoscope} className="size-5 text-fg-brand-primary" />
                            </div>
                            <p className="text-sm font-semibold text-primary">No doctors yet</p>
                            <p className="max-w-xs text-center text-xs text-tertiary">
                                {clinics.length === 0
                                    ? 'Add a clinic first, then add doctors to assign them.'
                                    : 'Add your first doctor to start booking consultations.'}
                            </p>
                            <Button size="sm" color="primary" onClick={handleAdd} isDisabled={clinics.length === 0}>
                                Add doctor
                            </Button>
                        </div>
                    ) : (
                        <Table>
                            <Table.Header>
                                <Table.Head label="DOCTOR" isRowHeader />
                                <Table.Head label="DEPARTMENT" />
                                <Table.Head label="VISITING SCHEDULE" />
                                <Table.Head label="FEE (NEW)" />
                                <Table.Head label="STATUS" />
                                <Table.Head label="" />
                            </Table.Header>
                            <Table.Body items={doctors}>
                                {(doctor) => {
                                    const firstName = doctor.fullName?.firstName ?? '';
                                    const lastName = doctor.fullName?.lastName ?? '';
                                    const name = `Dr. ${firstName} ${lastName}`.trim();
                                    return (
                                        <Table.Row id={doctor.id}>
                                            <Table.Cell>
                                                <div className="flex flex-col">
                                                    <span className="text-sm font-medium text-primary">{name}</span>
                                                    {doctor.specialty && (
                                                        <span className="text-xs text-tertiary">{doctor.specialty}</span>
                                                    )}
                                                </div>
                                            </Table.Cell>
                                            <Table.Cell>
                                                <span className="text-sm text-tertiary">
                                                    {doctor.department ? departmentLabel[doctor.department] : '—'}
                                                </span>
                                            </Table.Cell>
                                            <Table.Cell>
                                                <span className="text-xs text-tertiary">
                                                    {summariseVisitSlots(doctor, clinicNameById)}
                                                </span>
                                            </Table.Cell>
                                            <Table.Cell>
                                                <span className="text-sm text-tertiary">
                                                    {formatFee(doctor.consultationFeeNew)}
                                                </span>
                                            </Table.Cell>
                                            <Table.Cell>
                                                <Badge
                                                    size="sm"
                                                    color={doctor.active ? 'success' : 'gray'}
                                                    type="pill-color"
                                                >
                                                    {doctor.active ? 'Accepting' : 'Inactive'}
                                                </Badge>
                                            </Table.Cell>
                                            <Table.Cell>
                                                <Button
                                                    size="sm"
                                                    color="secondary"
                                                    iconLeading={({ className }: { className?: string }) => (
                                                        <FontAwesomeIcon icon={faPenToSquare} className={className} />
                                                    )}
                                                    onClick={() => handleEdit(doctor)}
                                                >
                                                    Edit
                                                </Button>
                                            </Table.Cell>
                                        </Table.Row>
                                    );
                                }}
                            </Table.Body>
                        </Table>
                    )}
                </TableCard.Root>
            </div>

            <SlideoutMenu isOpen={slideoutOpen} onOpenChange={setSlideoutOpen} isDismissable>
                {({ close }) => (
                    <>
                        <SlideoutMenu.Header onClose={close}>
                            <div className="flex items-center gap-3 pr-8">
                                <div className="flex size-10 items-center justify-center rounded-lg bg-brand-secondary">
                                    <FontAwesomeIcon icon={faStethoscope} className="size-5 text-fg-brand-primary" />
                                </div>
                                <div>
                                    <h2 className="text-lg font-semibold text-primary">
                                        {editTarget ? 'Edit doctor' : 'Add doctor'}
                                    </h2>
                                    <p className="text-sm text-tertiary">
                                        {editTarget
                                            ? 'Update clinician details and visiting schedule'
                                            : 'Add a new clinician to your hospital'}
                                    </p>
                                </div>
                            </div>
                        </SlideoutMenu.Header>

                        <SlideoutMenu.Content>
                            <DoctorForm value={formValues} onChange={setFormValues} clinics={clinicOptions} />
                        </SlideoutMenu.Content>

                        <SlideoutMenu.Footer>
                            <div className="flex items-center justify-end gap-3">
                                <Button size="md" color="secondary" onClick={close}>
                                    Cancel
                                </Button>
                                <Button
                                    size="md"
                                    color="primary"
                                    isLoading={isSaving}
                                    showTextWhileLoading
                                    onClick={() => handleSave(close)}
                                >
                                    {isSaving ? 'Saving...' : editTarget ? 'Save changes' : 'Add doctor'}
                                </Button>
                            </div>
                        </SlideoutMenu.Footer>
                    </>
                )}
            </SlideoutMenu>
        </div>
    );
};
