import { useState, useRef } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faPhoneHangup, faCalendarCheck, faCalendarXmark, faCalendarArrowDown, faClipboardCheck, faClockRotateLeft } from '@fortawesome/pro-duotone-svg-icons';
import { Dialog, Modal, ModalOverlay } from '@/components/application/modals/modal';
import { FeaturedIcon } from '@/components/foundations/featured-icon/featured-icon';
import { Badge } from '@/components/base/badges/badges';
import { TextArea } from '@/components/base/textarea/textarea';
import type { FC } from 'react';
import type { CallDisposition } from '@/types/entities';
import { cx } from '@/utils/cx';

export type CallAction = 'APPOINTMENT' | 'RESCHEDULE' | 'CANCEL' | 'FOLLOWUP' | 'ENQUIRY';

// Maps a recorded action to the disposition it implies. The first action in
// the priority list (highest-ranked entry in actionsTaken) becomes the
// primary disposition. When any action is present, all other dispositions
// are locked out — an agent can't mark a call as "Not Interested" after
// they've already booked an appointment.
const ACTION_TO_DISPOSITION: Record<CallAction, CallDisposition> = {
    APPOINTMENT: 'APPOINTMENT_BOOKED',
    RESCHEDULE: 'APPOINTMENT_RESCHEDULED',
    CANCEL: 'APPOINTMENT_CANCELLED',
    FOLLOWUP: 'FOLLOW_UP_SCHEDULED',
    ENQUIRY: 'INFO_PROVIDED',
};

const ACTION_META: Record<CallAction, { label: string; icon: typeof faCalendarCheck; color: 'success' | 'warning' | 'error' | 'brand' | 'blue-light' }> = {
    APPOINTMENT: { label: 'Appointment booked', icon: faCalendarCheck, color: 'success' },
    RESCHEDULE: { label: 'Appointment rescheduled', icon: faCalendarArrowDown, color: 'warning' },
    CANCEL: { label: 'Appointment cancelled', icon: faCalendarXmark, color: 'error' },
    FOLLOWUP: { label: 'Follow-up scheduled', icon: faClockRotateLeft, color: 'brand' },
    ENQUIRY: { label: 'Enquiry logged', icon: faClipboardCheck, color: 'blue-light' },
};

// Priority order — highest-rank action wins when multiple are taken. Booked
// > Rescheduled > Cancelled > Follow-up > Enquiry. A cancel inherently means
// no booking, so it ranks below booking/rescheduling; but above a follow-up
// because cancellation is a definitive outcome on this call.
const ACTION_PRIORITY: CallAction[] = ['APPOINTMENT', 'RESCHEDULE', 'CANCEL', 'FOLLOWUP', 'ENQUIRY'];

const PhoneHangUpIcon: FC<{ className?: string }> = ({ className }) => (
    <FontAwesomeIcon icon={faPhoneHangup} className={className} />
);

const dispositionOptions: Array<{
    value: CallDisposition;
    label: string;
    activeClass: string;
    defaultClass: string;
}> = [
    {
        value: 'APPOINTMENT_BOOKED',
        label: 'Appointment Booked',
        activeClass: 'bg-success-solid text-white border-transparent',
        defaultClass: 'bg-success-primary text-success-primary border-success',
    },
    {
        value: 'APPOINTMENT_RESCHEDULED',
        label: 'Appt Rescheduled',
        activeClass: 'bg-warning-solid text-white border-transparent',
        defaultClass: 'bg-warning-primary text-warning-primary border-warning',
    },
    {
        value: 'APPOINTMENT_CANCELLED',
        label: 'Appt Cancelled',
        activeClass: 'bg-error-solid text-white border-transparent',
        defaultClass: 'bg-error-primary text-error-primary border-error',
    },
    {
        value: 'FOLLOW_UP_SCHEDULED',
        label: 'Follow-up Needed',
        activeClass: 'bg-brand-solid text-white border-transparent',
        defaultClass: 'bg-brand-primary text-brand-secondary border-brand',
    },
    {
        value: 'INFO_PROVIDED',
        label: 'Info Provided',
        activeClass: 'bg-utility-blue-light-600 text-white border-transparent',
        defaultClass: 'bg-utility-blue-light-50 text-utility-blue-light-700 border-utility-blue-light-200',
    },
    {
        value: 'NO_ANSWER',
        label: 'No Answer',
        activeClass: 'bg-warning-solid text-white border-transparent',
        defaultClass: 'bg-warning-primary text-warning-primary border-warning',
    },
    {
        value: 'WRONG_NUMBER',
        label: 'Wrong Number',
        activeClass: 'bg-secondary-solid text-white border-transparent',
        defaultClass: 'bg-secondary text-secondary border-secondary',
    },
    {
        value: 'NOT_INTERESTED',
        label: 'Not Interested',
        activeClass: 'bg-error-solid text-white border-transparent',
        defaultClass: 'bg-error-primary text-error-primary border-error',
    },
    {
        value: 'CALLBACK_REQUESTED',
        label: 'Callback Requested',
        activeClass: 'bg-utility-blue-600 text-white border-transparent',
        defaultClass: 'bg-utility-blue-50 text-utility-blue-700 border-utility-blue-200',
    },
    {
        value: 'CALL_DROPPED',
        label: 'Call Dropped',
        activeClass: 'bg-secondary-solid text-white border-transparent',
        defaultClass: 'bg-secondary text-secondary border-secondary',
    },
];

type DispositionModalProps = {
    isOpen: boolean;
    callerName: string;
    callerDisconnected: boolean;
    // True once the call reached the active (answered) state. When false,
    // the customer never picked up — only no-answer dispositions are
    // valid; conversation-implying ones (Info Provided, Appointment
    // Booked, Follow-up, Not Interested) are disabled. Defaults to
    // true so existing callers don't accidentally lock everything out.
    callAnswered?: boolean;
    // Actions actually performed during the call (appointment booked, enquiry
    // logged, follow-up scheduled). Drives the priority-based disposition
    // lock — when any action is present, the primary disposition is forced
    // and the other options are disabled.
    actionsTaken?: CallAction[];
    onSubmit: (disposition: CallDisposition, notes: string) => void;
    onDismiss?: () => void;
};

// Dispositions that only make sense when the customer actually connected.
// Selecting these on an unanswered call would misrepresent SLA and
// conversation metrics.
const ANSWERED_ONLY_DISPOSITIONS: ReadonlySet<CallDisposition> = new Set([
    'INFO_PROVIDED',
    'APPOINTMENT_BOOKED',
    'APPOINTMENT_RESCHEDULED',
    'APPOINTMENT_CANCELLED',
    'FOLLOW_UP_SCHEDULED',
    'NOT_INTERESTED',
]);

export const DispositionModal = ({ isOpen, callerName, callerDisconnected, callAnswered = true, actionsTaken, onSubmit, onDismiss }: DispositionModalProps) => {
    const [selected, setSelected] = useState<CallDisposition | null>(null);
    const [notes, setNotes] = useState('');
    const appliedLockRef = useRef<CallDisposition | null | undefined>(undefined);

    // Rank actionsTaken to pick the primary (highest-priority) action. When
    // any action is present, that action's disposition becomes locked —
    // the agent cannot override it to a contradictory outcome.
    const primaryAction = actionsTaken && actionsTaken.length > 0
        ? ACTION_PRIORITY.find((a) => actionsTaken.includes(a)) ?? null
        : null;
    const lockedDisposition = primaryAction ? ACTION_TO_DISPOSITION[primaryAction] : null;

    // Apply the lock once per open — agent can still re-select the same
    // option, but switching to another value is prevented in the click handler.
    if (isOpen && lockedDisposition && appliedLockRef.current !== lockedDisposition) {
        appliedLockRef.current = lockedDisposition;
        setSelected(lockedDisposition);
    }

    const handleSubmit = () => {
        if (selected === null) return;
        onSubmit(selected, notes);
        setSelected(null);
        setNotes('');
        appliedLockRef.current = undefined;
    };

    return (
        <ModalOverlay
            isOpen={isOpen}
            // When the caller disconnected on their own, dismissing the
            // modal discards the call without any disposition — no record,
            // no SLA signal. Force a selection in that path. When the
            // agent opened the modal via End Call (callerDisconnected=false),
            // dismissing just returns to the active call, so it's safe.
            isDismissable={!callerDisconnected}
            onOpenChange={(open) => { if (!open && onDismiss) onDismiss(); }}
        >
            <Modal className="sm:max-w-md">
                <Dialog>
                    {() => (
                        <div className="flex w-full flex-col rounded-xl bg-primary shadow-xl ring-1 ring-secondary overflow-hidden">
                            {/* Header */}
                            <div className="flex flex-col items-center gap-3 px-6 pt-6 pb-4">
                                <FeaturedIcon icon={PhoneHangUpIcon} color={callerDisconnected ? 'warning' : 'error'} theme="light" size="md" />
                                <div className="text-center">
                                    <h2 className="text-lg font-semibold text-primary">
                                        {callerDisconnected ? 'Call Disconnected' : 'End Call'}
                                    </h2>
                                    <p className="mt-1 text-sm text-tertiary">
                                        {callerDisconnected
                                            ? `${callerName} disconnected. What was the outcome?`
                                            : `Select a reason to end the call with ${callerName}.`
                                        }
                                    </p>
                                </div>
                            </div>

                            {/* Disposition options */}
                            <div className="px-6 pb-4">
                                {actionsTaken && actionsTaken.length > 0 && (
                                    <div className="mb-3 flex flex-col gap-2 rounded-lg bg-secondary p-3">
                                        <span className="text-xs font-semibold uppercase tracking-wide text-tertiary">
                                            Actions taken on this call
                                        </span>
                                        <div className="flex flex-wrap gap-1.5">
                                            {ACTION_PRIORITY.filter((a) => actionsTaken.includes(a)).map((action) => {
                                                const meta = ACTION_META[action];
                                                return (
                                                    <Badge key={action} size="sm" color={meta.color} type="pill-color">
                                                        <FontAwesomeIcon icon={meta.icon} className="size-3 mr-1" />
                                                        {meta.label}
                                                    </Badge>
                                                );
                                            })}
                                        </div>
                                    </div>
                                )}

                                <div className="grid grid-cols-2 gap-2">
                                    {dispositionOptions.map((option) => {
                                        const isSelected = selected === option.value;
                                        // Two reasons an option can be disabled:
                                        //   (1) action lock — the agent already booked / scheduled
                                        //       something, so only the matching disposition is valid.
                                        //   (2) unanswered call — dispositions that imply the customer
                                        //       actually spoke with the agent (Info Provided, etc.)
                                        //       are disabled to prevent SLA-gaming.
                                        const isLockedOut = lockedDisposition !== null && option.value !== lockedDisposition;
                                        const isAnsweredOnlyBlocked = !callAnswered && ANSWERED_ONLY_DISPOSITIONS.has(option.value);
                                        const isDisabled = isLockedOut || isAnsweredOnlyBlocked;
                                        return (
                                            <button
                                                key={option.value}
                                                type="button"
                                                disabled={isDisabled}
                                                onClick={() => !isDisabled && setSelected(option.value)}
                                                className={cx(
                                                    'rounded-xl border-2 p-3 text-sm font-semibold transition duration-100 ease-linear',
                                                    isDisabled && 'cursor-not-allowed opacity-40',
                                                    !isDisabled && 'cursor-pointer',
                                                    isSelected
                                                        ? cx(option.activeClass, 'ring-2 ring-brand')
                                                        : option.defaultClass,
                                                )}
                                            >
                                                {option.label}
                                            </button>
                                        );
                                    })}
                                </div>

                                <div className="mt-3">
                                    <TextArea
                                        label="Notes (optional)"
                                        placeholder="Add any notes about this call..."
                                        value={notes}
                                        onChange={(value) => setNotes(value)}
                                        rows={2}
                                        textAreaClassName="text-sm"
                                    />
                                </div>
                            </div>

                            {/* Footer */}
                            <div className="border-t border-secondary px-6 py-4">
                                <button
                                    type="button"
                                    onClick={handleSubmit}
                                    disabled={selected === null}
                                    className={cx(
                                        'w-full rounded-xl px-6 py-2.5 text-sm font-semibold transition duration-100 ease-linear',
                                        selected !== null
                                            ? 'cursor-pointer bg-error-solid text-white hover:bg-error-solid_hover'
                                            : 'cursor-not-allowed bg-disabled text-disabled',
                                    )}
                                >
                                    {callerDisconnected
                                        ? (selected ? 'Submit & Close' : 'Select a reason')
                                        : (selected ? 'End Call & Submit' : 'Select a reason to end call')
                                    }
                                </button>
                            </div>
                        </div>
                    )}
                </Dialog>
            </Modal>
        </ModalOverlay>
    );
};
