import { useState, useRef, useEffect, useMemo } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import {
    faPhone, faPhoneHangup, faMicrophone, faMicrophoneSlash,
    faPause, faPlay, faCalendarPlus, faPlus, faPenToSquare,
    faPhoneArrowRight, faRecordVinyl, faClipboardQuestion,
} from '@fortawesome/pro-duotone-svg-icons';
import { useData } from '@/providers/data-provider';
import { Button } from '@/components/base/buttons/button';
import { Badge } from '@/components/base/badges/badges';
import { useSetAtom } from 'jotai';
import { sipCallStateAtom, sipCallerNumberAtom, sipCallUcidAtom } from '@/state/sip-state';
import { setOutboundPending } from '@/state/sip-manager';
import { useSip } from '@/providers/sip-provider';
import { DispositionModal } from './disposition-modal';
import type { CallAction } from './disposition-modal';
import { Dialog, Modal, ModalOverlay } from '@/components/application/modals/modal';
import { AppointmentForm } from './appointment-form';
import { TransferDialog } from './transfer-dialog';
import { EnquiryForm } from './enquiry-form';
import { formatPhone, formatShortDate } from '@/lib/format';
import { apiClient } from '@/lib/api-client';
import { useAuth } from '@/providers/auth-provider';
import { useAgentState } from '@/hooks/use-agent-state';
import { cx } from '@/utils/cx';
import { notify } from '@/lib/toast';
import type { Lead, CallDisposition } from '@/types/entities';

interface ActiveCallCardProps {
    lead: Lead | null;
    callerPhone: string;
    missedCallId?: string | null;
    onCallComplete?: () => void;
}

const formatDuration = (seconds: number): string => {
    const m = Math.floor(seconds / 60);
    const s = seconds % 60;
    return `${m}:${s.toString().padStart(2, '0')}`;
};

export const ActiveCallCard = ({ lead, callerPhone, missedCallId, onCallComplete }: ActiveCallCardProps) => {
    const { user } = useAuth();
    const { callState, callDuration, callUcid, isMuted, isOnHold, answer, reject, hangup, toggleMute, toggleHold } = useSip();
    const setCallState = useSetAtom(sipCallStateAtom);
    const setCallerNumber = useSetAtom(sipCallerNumberAtom);
    const setCallUcid = useSetAtom(sipCallUcidAtom);
    const [appointmentOpen, setAppointmentOpen] = useState(false);
    // Which existing appointment is being edited (null = creating a new one).
    // The Book Appt drawer shows pills: [+ New] + one per upcoming appointment.
    // Clicking Edit on a pill sets this; clicking + New clears it.
    const [editingApptId, setEditingApptId] = useState<string | null>(null);
    const [transferOpen, setTransferOpen] = useState(false);
    const [recordingPaused, setRecordingPaused] = useState(false);
    const [enquiryOpen, setEnquiryOpen] = useState(false);
    const [dispositionOpen, setDispositionOpen] = useState(false);
    const [callerDisconnected, setCallerDisconnected] = useState(false);
    // Actions actually recorded during this call. Drives the disposition
    // modal's priority-lock: if the agent booked an appointment and logged
    // an enquiry, both badges render and the primary disposition is
    // locked to APPOINTMENT_BOOKED.
    const [actionsTaken, setActionsTaken] = useState<CallAction[]>([]);
    const addActions = (...newActions: CallAction[]) => {
        setActionsTaken((prev) => {
            const next = new Set(prev);
            for (const a of newActions) next.add(a);
            return Array.from(next);
        });
    };

    // Upcoming appointments for this caller (if returning patient) — drives
    // the pill row above AppointmentForm so the agent can edit existing
    // bookings in addition to creating new ones.
    const { appointments } = useData();
    const leadAppointments = useMemo(() => {
        const patientId = (lead as any)?.patientId;
        if (!patientId) return [];
        const now = Date.now();
        return appointments
            .filter((a) =>
                a.patientId === patientId
                && a.appointmentStatus !== 'CANCELLED'
                && a.appointmentStatus !== 'NO_SHOW'
                && a.appointmentStatus !== 'COMPLETED'
                // Only future appointments make sense as reschedule targets.
                // Past ones can't be edited — they already happened.
                && a.scheduledAt
                && new Date(a.scheduledAt).getTime() >= now,
            )
            .sort((a, b) => new Date(a.scheduledAt ?? '').getTime() - new Date(b.scheduledAt ?? '').getTime());
    }, [appointments, lead]);

    const editingAppt = useMemo(
        () => (editingApptId ? leadAppointments.find((a) => a.id === editingApptId) ?? null : null),
        [leadAppointments, editingApptId],
    );

    // Pending pill click awaiting the reschedule-confirm modal. When the
    // agent clicks a pill, we store the appointment id here + open the modal.
    // Yes → promote to editingApptId in edit mode. No → promote in view mode.
    const [pendingApptId, setPendingApptId] = useState<string | null>(null);
    const [apptMode, setApptMode] = useState<'edit' | 'view'>('edit');

    const agentConfig = localStorage.getItem('helix_agent_config');
    const agentIdForState = agentConfig ? (() => { try { return JSON.parse(agentConfig).ozonetelAgentId; } catch { return null; } })() : null;
    const { supervisorPresence } = useAgentState(agentIdForState);

    const callDirectionRef = useRef(callState === 'ringing-out' ? 'OUTBOUND' : 'INBOUND');
    const wasAnsweredRef = useRef(callState === 'active');

    useEffect(() => {
        console.log(`[ACTIVE-CALL-CARD] Mounted: state=${callState} direction=${callDirectionRef.current} ucid=${callUcid ?? 'none'} lead=${lead?.id ?? 'none'} phone=${callerPhone}`);
    }, []); // eslint-disable-line react-hooks/exhaustive-deps

    // Sync UCID to localStorage so sendBeacon can fire auto-dispose on page refresh.
    // Cleared on disposition submit (handleDisposition below) or when call resets to idle.
    useEffect(() => {
        if (callUcid) {
            localStorage.setItem('helix_active_ucid', callUcid);
        }
        return () => {
            // Don't clear on unmount if disposition hasn't fired — the
            // beforeunload handler in SipProvider needs it
        };
    }, [callUcid]);

    // Detect caller disconnect: call was active and ended without agent pressing End
    useEffect(() => {
        if (wasAnsweredRef.current && !dispositionOpen && (callState === 'ended' || callState === 'failed')) {
            setCallerDisconnected(true);
            setDispositionOpen(true);
        }
    }, [callState, dispositionOpen]);

    const firstName = lead?.contactName?.firstName ?? '';
    const lastName = lead?.contactName?.lastName ?? '';
    const fullName = `${firstName} ${lastName}`.trim();
    const phone = lead?.contactPhone?.[0];
    const phoneDisplay = phone ? formatPhone(phone) : callerPhone || 'Unknown';

    const handleDisposition = async (disposition: CallDisposition, notes: string) => {
        // Hangup if still connected
        if (callState === 'active' || callState === 'ringing-out' || callState === 'ringing-in') {
            hangup();
        }

        // Submit disposition to sidecar
        if (callUcid) {
            const agentCfg = JSON.parse(localStorage.getItem('helix_agent_config') ?? '{}');
            const disposePayload = {
                ucid: callUcid,
                disposition,
                agentId: agentCfg.ozonetelAgentId,
                callerPhone,
                direction: callDirectionRef.current,
                durationSec: callDuration,
                leadId: lead?.id ?? null,
                leadName: fullName || null,
                notes,
                missedCallId: missedCallId ?? undefined,
            };
            console.log('[DISPOSE] Sending disposition:', JSON.stringify(disposePayload));
            apiClient.post('/api/ozonetel/dispose', disposePayload)
                .then((res) => console.log('[DISPOSE] Response:', JSON.stringify(res)))
                .catch((err) => console.error('[DISPOSE] Failed:', err));
        } else {
            console.warn('[DISPOSE] No callUcid — skipping disposition');
        }

        // Follow-ups are created by the enquiry form (where the agent picks
        // the date + context). No second creation here — that was causing
        // duplicate entries on every FOLLOW_UP_SCHEDULED call.

        // Clear persisted UCID — disposition was submitted, no need for sendBeacon fallback
        localStorage.removeItem('helix_active_ucid');

        notify.success('Call Logged', `Disposition: ${disposition.replace(/_/g, ' ').toLowerCase()}`);
        handleReset();
    };

    const handleAppointmentSaved = (outcome: 'BOOKED' | 'RESCHEDULED' | 'CANCELLED') => {
        setAppointmentOpen(false);
        if (outcome === 'RESCHEDULED') {
            addActions('RESCHEDULE');
            notify.success('Appointment Rescheduled');
        } else if (outcome === 'CANCELLED') {
            addActions('CANCEL');
            notify.success('Appointment Cancelled');
        } else {
            addActions('APPOINTMENT');
            notify.success('Appointment Booked', 'Payment link will be sent to the patient');
        }
    };

    const handleReset = () => {
        setDispositionOpen(false);
        setCallerDisconnected(false);
        setActionsTaken([]);
        setCallState('idle');
        setCallerNumber(null);
        setCallUcid(null);
        setOutboundPending(false);
        onCallComplete?.();
    };

    // Outbound ringing
    if (callState === 'ringing-out') {
        return (
            <div className="rounded-xl bg-brand-primary p-4">
                <div className="flex items-center gap-3">
                    <div className="relative">
                        <div className="absolute inset-0 animate-pulse rounded-full bg-brand-solid opacity-20" />
                        <div className="relative flex size-10 items-center justify-center rounded-full bg-brand-solid">
                            <FontAwesomeIcon icon={faPhone} className="size-4 text-white" />
                        </div>
                    </div>
                    <div className="min-w-0 flex-1">
                        <p className="text-xs font-bold uppercase tracking-wider text-brand-secondary">Calling...</p>
                        <p className="text-lg font-bold text-primary">{fullName || phoneDisplay}</p>
                        {fullName && <p className="text-sm text-secondary">{phoneDisplay}</p>}
                    </div>
                </div>
                <div className="mt-3 flex gap-2">
                    <Button size="sm" color="primary-destructive" onClick={() => { hangup(); handleReset(); }}>
                        Cancel
                    </Button>
                </div>
            </div>
        );
    }

    // Inbound ringing
    if (callState === 'ringing-in') {
        return (
            <div className="rounded-xl bg-brand-primary p-4">
                <div className="flex items-center gap-3">
                    <div className="relative">
                        <div className="absolute inset-0 animate-ping rounded-full bg-brand-solid opacity-20" />
                        <div className="relative flex size-10 items-center justify-center rounded-full bg-brand-solid">
                            <FontAwesomeIcon icon={faPhone} className="size-4 text-white animate-bounce" />
                        </div>
                    </div>
                    <div className="min-w-0 flex-1">
                        <p className="text-xs font-bold uppercase tracking-wider text-brand-secondary">Incoming Call</p>
                        <p className="text-lg font-bold text-primary">{fullName || phoneDisplay}</p>
                        {fullName && <p className="text-sm text-secondary">{phoneDisplay}</p>}
                    </div>
                </div>
                <div className="mt-3 flex gap-2">
                    <Button size="sm" color="primary" onClick={answer}>Answer</Button>
                    <Button size="sm" color="tertiary-destructive" onClick={reject}>Decline</Button>
                </div>
            </div>
        );
    }

    // Unanswered call (ringing → ended without ever reaching active)
    if (!wasAnsweredRef.current && (callState === 'ended' || callState === 'failed')) {
        return (
            <div className="rounded-xl border border-secondary bg-primary p-4 text-center">
                <FontAwesomeIcon icon={faPhoneHangup} className="size-6 text-fg-quaternary mb-2" />
                <p className="text-sm font-semibold text-primary">{fullName || 'Missed Call'}</p>
                <p className="text-xs text-tertiary mt-1">{phoneDisplay} — not answered</p>
                <Button size="sm" color="secondary" className="mt-3" onClick={handleReset}>
                    Back to Worklist
                </Button>
            </div>
        );
    }

    // Active call
    if (callState === 'active' || dispositionOpen) {
        wasAnsweredRef.current = true;
        return (
            <>
                <div className={cx('flex flex-col rounded-xl border border-brand bg-primary overflow-hidden', (appointmentOpen || enquiryOpen || transferOpen) && 'flex-1 min-h-0')}>
                    {/* Pinned: caller info + controls */}
                    <div className="shrink-0 p-4">
                        <div className="flex items-center justify-between">
                            <div className="flex items-center gap-3">
                                <div className="flex size-10 items-center justify-center rounded-full bg-success-solid">
                                    <FontAwesomeIcon icon={faPhone} className="size-4 text-white" />
                                </div>
                                <div>
                                    <p className="text-sm font-bold text-primary">{fullName || phoneDisplay}</p>
                                    {fullName && <p className="text-xs text-tertiary">{phoneDisplay}</p>}
                                </div>
                            </div>
                            <div className="flex items-center gap-2">
                                {supervisorPresence === 'whisper' && (
                                    <Badge size="sm" color="blue" type="pill-color">Supervisor coaching</Badge>
                                )}
                                {supervisorPresence === 'barge' && (
                                    <Badge size="sm" color="brand" type="pill-color">Supervisor on call</Badge>
                                )}
                                <Badge size="md" color="success" type="pill-color">{formatDuration(callDuration)}</Badge>
                            </div>
                        </div>

                        {/* Call controls */}
                        <div className="mt-3 flex items-center gap-1.5 flex-wrap">
                            <button
                                onClick={toggleMute}
                                title={isMuted ? 'Unmute' : 'Mute'}
                                className={cx(
                                    'flex size-8 items-center justify-center rounded-lg transition duration-100 ease-linear',
                                    isMuted ? 'bg-error-solid text-white' : 'bg-secondary text-fg-quaternary hover:bg-secondary_hover hover:text-fg-secondary',
                                )}
                            >
                                <FontAwesomeIcon icon={isMuted ? faMicrophoneSlash : faMicrophone} className="size-3.5" />
                            </button>
                            <button
                                onClick={toggleHold}
                                title={isOnHold ? 'Resume' : 'Hold'}
                                className={cx(
                                    'flex size-8 items-center justify-center rounded-lg transition duration-100 ease-linear',
                                    isOnHold ? 'bg-warning-solid text-white' : 'bg-secondary text-fg-quaternary hover:bg-secondary_hover hover:text-fg-secondary',
                                )}
                            >
                                <FontAwesomeIcon icon={isOnHold ? faPlay : faPause} className="size-3.5" />
                            </button>
                            <button
                                onClick={() => {
                                    const action = recordingPaused ? 'unPause' : 'pause';
                                    if (callUcid) apiClient.post('/api/ozonetel/recording', { ucid: callUcid, action }).catch(() => {});
                                    setRecordingPaused(!recordingPaused);
                                }}
                                title={recordingPaused ? 'Resume Recording' : 'Pause Recording'}
                                className={cx(
                                    'flex size-8 items-center justify-center rounded-lg transition duration-100 ease-linear',
                                    recordingPaused ? 'bg-error-solid text-white' : 'bg-secondary text-fg-quaternary hover:bg-secondary_hover hover:text-fg-secondary',
                                )}
                            >
                                <FontAwesomeIcon icon={faRecordVinyl} className="size-3.5" />
                            </button>

                            <div className="w-px h-6 bg-secondary mx-0.5" />

                            <Button size="sm" color={appointmentOpen ? 'primary' : 'secondary'}
                                iconLeading={({ className, ...rest }: any) => <FontAwesomeIcon icon={faCalendarPlus} className={className} {...rest} />}
                                isDisabled={!wasAnsweredRef.current}
                                onClick={() => { setAppointmentOpen(!appointmentOpen); setEnquiryOpen(false); setTransferOpen(false); }}>
                                {leadAppointments.length > 0 ? 'New / Reschedule Appt' : 'New Appt'}
                            </Button>
                            <Button size="sm" color={enquiryOpen ? 'primary' : 'secondary'}
                                iconLeading={({ className, ...rest }: any) => <FontAwesomeIcon icon={faClipboardQuestion} className={className} {...rest} />}
                                isDisabled={!wasAnsweredRef.current}
                                onClick={() => { setEnquiryOpen(!enquiryOpen); setAppointmentOpen(false); setTransferOpen(false); }}>Enquiry</Button>
                            <Button size="sm" color={transferOpen ? 'primary' : 'secondary'}
                                iconLeading={({ className, ...rest }: any) => <FontAwesomeIcon icon={faPhoneArrowRight} className={className} {...rest} />}
                                isDisabled={!wasAnsweredRef.current}
                                onClick={() => { setTransferOpen(!transferOpen); setAppointmentOpen(false); setEnquiryOpen(false); }}>Transfer</Button>

                            <Button size="sm" color="primary-destructive" className="ml-auto"
                                iconLeading={({ className, ...rest }: any) => <FontAwesomeIcon icon={faPhoneHangup} className={className} {...rest} />}
                                onClick={() => setDispositionOpen(true)}>End Call</Button>
                        </div>

                    </div>

                    {/* Scrollable: expanded forms + transfer */}
                    {(appointmentOpen || enquiryOpen || transferOpen) && (
                        <div className="flex flex-col min-h-0 flex-1 border-t border-secondary px-4 pb-4 pt-4">
                        {transferOpen && callUcid && (
                            <TransferDialog
                                ucid={callUcid}
                                currentAgentId={JSON.parse(localStorage.getItem('helix_agent_config') ?? '{}').ozonetelAgentId}
                                onClose={() => setTransferOpen(false)}
                                onTransferred={() => {
                                    setTransferOpen(false);
                                    // A transfer implies the original agent handed the call
                                    // off — treat that as a follow-up action so the
                                    // disposition pre-locks to FOLLOW_UP_SCHEDULED.
                                    addActions('FOLLOWUP');
                                    setDispositionOpen(true);
                                }}
                            />
                        )}
                            {appointmentOpen && leadAppointments.length > 0 && (
                                <div className="flex flex-wrap gap-2 mb-3">
                                    <button
                                        type="button"
                                        onClick={() => setEditingApptId(null)}
                                        className={cx(
                                            'flex items-center gap-1.5 rounded-lg border-2 px-3 py-2 text-xs font-semibold transition duration-100 ease-linear',
                                            !editingApptId
                                                ? 'border-brand bg-brand-primary text-brand-secondary'
                                                : 'border-secondary bg-primary text-secondary hover:bg-primary_hover',
                                        )}
                                    >
                                        <FontAwesomeIcon icon={faPlus} className="size-3" />
                                        New
                                    </button>
                                    {leadAppointments.map((appt) => (
                                        <div
                                            key={appt.id}
                                            className={cx(
                                                'flex items-center gap-2 rounded-lg border-2 px-3 py-2 text-xs',
                                                editingApptId === appt.id
                                                    ? 'border-brand bg-brand-primary'
                                                    : 'border-secondary bg-primary',
                                            )}
                                        >
                                            <div className="flex flex-col">
                                                <span className="font-semibold text-primary">
                                                    {appt.scheduledAt ? formatShortDate(appt.scheduledAt) : 'No date'}
                                                </span>
                                                <span className="text-[11px] text-tertiary">
                                                    {appt.doctorName ?? 'Doctor'}
                                                </span>
                                            </div>
                                            <button
                                                type="button"
                                                onClick={() => setPendingApptId(appt.id)}
                                                className="flex items-center gap-1 rounded-md px-2 py-1 text-[11px] font-semibold text-brand-secondary hover:bg-brand-primary_hover transition duration-100 ease-linear"
                                            >
                                                <FontAwesomeIcon icon={faPenToSquare} className="size-3" />
                                                Edit
                                            </button>
                                        </div>
                                    ))}
                                </div>
                            )}

                            {/* Key forces a full remount when switching between
                                pills (or between edit/view modes) so the form's
                                internal state re-initializes from the new
                                existingAppointment prop instead of staying
                                stuck on the first-mounted values. */}
                            <AppointmentForm
                                key={`${editingApptId ?? 'new'}-${apptMode}`}
                                isOpen={appointmentOpen}
                                onOpenChange={(open) => {
                                    setAppointmentOpen(open);
                                    if (!open) { setEditingApptId(null); setApptMode('edit'); }
                                }}
                                callerNumber={callerPhone}
                                leadName={fullName || null}
                                leadId={lead?.id ?? null}
                                patientId={(lead as any)?.patientId ?? null}
                                readOnly={apptMode === 'view'}
                                existingAppointment={editingAppt ? {
                                    id: editingAppt.id,
                                    scheduledAt: editingAppt.scheduledAt ?? '',
                                    doctorName: editingAppt.doctorName ?? '',
                                    doctorId: editingAppt.doctorId ?? undefined,
                                    department: editingAppt.department ?? '',
                                    clinicId: editingAppt.clinicId ?? undefined,
                                    reasonForVisit: editingAppt.reasonForVisit ?? undefined,
                                    status: editingAppt.appointmentStatus ?? 'SCHEDULED',
                                } : null}
                                onSaved={(outcome) => {
                                    setEditingApptId(null);
                                    setApptMode('edit');
                                    handleAppointmentSaved(outcome);
                                }}
                            />

                            <EnquiryForm
                                isOpen={enquiryOpen}
                                onOpenChange={setEnquiryOpen}
                                callerPhone={callerPhone}
                                leadName={fullName || null}
                                leadId={lead?.id ?? null}
                                patientId={(lead as any)?.patientId ?? null}
                                agentName={user.name}
                                onSaved={(actions) => {
                                    setEnquiryOpen(false);
                                    addActions(...actions);
                                }}
                            />
                        </div>
                    )}
                </div>

                {/* Reschedule confirm modal — fires when the agent clicks Edit
                    on an upcoming-appointment pill. Yes → open the form in
                    edit mode (fields editable, Save button). No → open in
                    view-only mode (fields disabled, Close button). */}
                <ModalOverlay
                    isOpen={pendingApptId !== null}
                    onOpenChange={(open) => { if (!open) setPendingApptId(null); }}
                    isDismissable
                >
                    <Modal className="sm:max-w-md">
                        <Dialog>
                            {() => (
                                <div className="flex flex-col gap-4 rounded-xl bg-primary p-6 shadow-xl ring-1 ring-secondary">
                                    <h2 className="text-lg font-semibold text-primary">Reschedule this appointment?</h2>
                                    <p className="text-sm text-tertiary">
                                        Choose "Yes, reschedule" to change the date, time, or doctor.
                                        Choose "No, just view" to see the details without changing anything.
                                    </p>
                                    <div className="flex items-center gap-2 justify-end">
                                        <Button
                                            size="sm"
                                            color="secondary"
                                            onClick={() => {
                                                if (pendingApptId) {
                                                    setEditingApptId(pendingApptId);
                                                    setApptMode('view');
                                                    setPendingApptId(null);
                                                }
                                            }}
                                        >
                                            No, just view
                                        </Button>
                                        <Button
                                            size="sm"
                                            color="primary"
                                            onClick={() => {
                                                if (pendingApptId) {
                                                    setEditingApptId(pendingApptId);
                                                    setApptMode('edit');
                                                    setPendingApptId(null);
                                                }
                                            }}
                                        >
                                            Yes, reschedule
                                        </Button>
                                    </div>
                                </div>
                            )}
                        </Dialog>
                    </Modal>
                </ModalOverlay>

                {/* Disposition Modal — the ONLY path to end a call */}
                <DispositionModal
                    isOpen={dispositionOpen}
                    callerName={fullName || phoneDisplay}
                    callerDisconnected={callerDisconnected}
                    // wasAnsweredRef only flips true once callState reaches
                    // 'active'. Outbound callbacks that never connect keep
                    // this false, which narrows the disposition options to
                    // no-answer outcomes and prevents SLA-gaming dispositions
                    // like Info Provided on a call the customer never took.
                    callAnswered={wasAnsweredRef.current}
                    actionsTaken={actionsTaken}
                    onSubmit={handleDisposition}
                    onDismiss={() => {
                        // Agent wants to continue the call — close modal, call stays active
                        if (!callerDisconnected) {
                            setDispositionOpen(false);
                        } else {
                            // Caller already disconnected — dismiss goes to worklist
                            handleReset();
                        }
                    }}
                />
            </>
        );
    }

    return null;
};
