import { Fragment, useEffect, useRef, useState, type Ref } from 'react';
import Flatpickr from 'react-flatpickr';
import 'flatpickr/dist/flatpickr.css';
import { Dialog, Transition } from '@headlessui/react';

import {
    DateRange,
    STATS_PRESET_OPTIONS,
    StatsPreset,
    detectPresetFromRange,
    formatRangeLabel,
    getPresetRange,
    getPreviousPeriodRange,
    isValidDateRange,
    dateStringToPickerDate,
    pickerDateToDateString,
} from '@/lib/abandoned-cart-stats-date';

interface StatsDateRangePickerProps {
    isOpen: boolean;
    appliedRange: DateRange;
    appliedPreset: StatsPreset;
    appliedCompareEnabled: boolean;
    appliedCompareRange?: DateRange | null;
    allowCustomCompareRange?: boolean;
    onClose: () => void;
    onApply: (
        range: DateRange,
        preset: StatsPreset,
        compareEnabled: boolean,
        compareRange?: DateRange | null
    ) => void;
}

const InlineRangePicker = ({
    pickerRef,
    range,
    onChange,
}: {
    pickerRef: Ref<any>;
    range: DateRange;
    onChange: (dates: Date[]) => void;
}) => (
    <div className="flex justify-center [&_.flatpickr-input]:hidden [&_.flatpickr-mobile]:hidden">
        <Flatpickr
            ref={pickerRef}
            className="hidden"
            options={{
                mode: 'range',
                inline: true,
                dateFormat: 'Y-m-d',
                defaultDate: [dateStringToPickerDate(range.from), dateStringToPickerDate(range.to)],
            }}
            onChange={onChange}
        />
    </div>
);

const StatsDateRangePicker = ({
    isOpen,
    appliedRange,
    appliedPreset,
    appliedCompareEnabled,
    appliedCompareRange = null,
    allowCustomCompareRange = false,
    onClose,
    onApply,
}: StatsDateRangePickerProps) => {
    const flatpickrRef = useRef<any>(null);
    const compareFlatpickrRef = useRef<any>(null);
    const [draftRange, setDraftRange] = useState<DateRange>(appliedRange);
    const [draftPreset, setDraftPreset] = useState<StatsPreset>(appliedPreset);
    const [draftCompareEnabled, setDraftCompareEnabled] = useState(appliedCompareEnabled);
    const [draftCompareRange, setDraftCompareRange] = useState<DateRange>(
        appliedCompareRange || getPreviousPeriodRange(appliedRange)
    );

    const showCompareCalendar = draftCompareEnabled && allowCustomCompareRange;

    const syncFlatpickr = (range: DateRange) => {
        const instance = flatpickrRef.current?.flatpickr;
        if (!instance) return;
        instance.setDate([dateStringToPickerDate(range.from), dateStringToPickerDate(range.to)], true);
    };

    const syncCompareFlatpickr = (range: DateRange) => {
        const instance = compareFlatpickrRef.current?.flatpickr;
        if (!instance) return;
        instance.setDate([dateStringToPickerDate(range.from), dateStringToPickerDate(range.to)], true);
    };

    useEffect(() => {
        if (!isOpen) return;
        setDraftRange(appliedRange);
        setDraftPreset(appliedPreset);
        setDraftCompareEnabled(appliedCompareEnabled);
        setDraftCompareRange(appliedCompareRange || getPreviousPeriodRange(appliedRange));
    }, [isOpen, appliedRange, appliedPreset, appliedCompareEnabled, appliedCompareRange]);

    useEffect(() => {
        if (!isOpen) return;
        const frame = requestAnimationFrame(() => {
            syncFlatpickr(appliedRange);
        });
        return () => cancelAnimationFrame(frame);
    }, [isOpen, appliedRange]);

    useEffect(() => {
        if (!isOpen || !showCompareCalendar) return;
        const frame = requestAnimationFrame(() => {
            syncCompareFlatpickr(draftCompareRange);
        });
        return () => cancelAnimationFrame(frame);
        // Sync when the compare calendar mounts, not on every date click.
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [isOpen, showCompareCalendar]);

    const autoCompareRange = getPreviousPeriodRange(draftRange);
    const compareRange = draftCompareEnabled
        ? allowCustomCompareRange
            ? draftCompareRange
            : autoCompareRange
        : null;

    const applyMainRange = (nextRange: DateRange) => {
        const oldAuto = getPreviousPeriodRange(draftRange);
        setDraftRange(nextRange);
        const compareWasAuto =
            draftCompareRange.from === oldAuto.from && draftCompareRange.to === oldAuto.to;
        if (!draftCompareRange || compareWasAuto) {
            const nextCompare = getPreviousPeriodRange(nextRange);
            setDraftCompareRange(nextCompare);
            if (showCompareCalendar) syncCompareFlatpickr(nextCompare);
        }
    };

    const handlePresetSelect = (preset: StatsPreset) => {
        setDraftPreset(preset);
        if (preset === 'custom') return;
        const nextRange = getPresetRange(preset);
        applyMainRange(nextRange);
        syncFlatpickr(nextRange);
    };

    const handleFlatpickrChange = (dates: Date[]) => {
        if (!Array.isArray(dates) || dates.length < 2) return;
        const nextRange = {
            from: pickerDateToDateString(dates[0]),
            to: pickerDateToDateString(dates[1]),
        };
        applyMainRange(nextRange);
        setDraftPreset(detectPresetFromRange(nextRange));
    };

    const handleCompareFlatpickrChange = (dates: Date[]) => {
        if (!Array.isArray(dates) || dates.length < 2) return;
        setDraftCompareRange({
            from: pickerDateToDateString(dates[0]),
            to: pickerDateToDateString(dates[1]),
        });
    };

    const handleCompareToggle = (checked: boolean) => {
        setDraftCompareEnabled(checked);
        if (checked) {
            setDraftCompareRange(appliedCompareRange || getPreviousPeriodRange(draftRange));
        }
    };

    const handleResetCompare = () => {
        setDraftCompareRange(autoCompareRange);
        syncCompareFlatpickr(autoCompareRange);
    };

    const handleApply = () => {
        if (!isValidDateRange(draftRange)) return;
        if (draftCompareEnabled && allowCustomCompareRange && !isValidDateRange(draftCompareRange)) return;
        onApply(draftRange, draftPreset, draftCompareEnabled, draftCompareEnabled ? compareRange : null);
    };

    const handleCancel = () => {
        onClose();
    };

    return (
        <Transition appear show={isOpen} as={Fragment}>
            <Dialog as="div" className="relative z-[60]" onClose={handleCancel}>
                <Transition.Child
                    as={Fragment}
                    enter="ease-out duration-200"
                    enterFrom="opacity-0"
                    enterTo="opacity-100"
                    leave="ease-in duration-150"
                    leaveFrom="opacity-100"
                    leaveTo="opacity-0"
                >
                    <div className="fixed inset-0 bg-black/40" />
                </Transition.Child>

                <div className="fixed inset-0 overflow-y-auto">
                    <div className="flex min-h-full items-center justify-center p-4">
                        <Transition.Child
                            as={Fragment}
                            enter="ease-out duration-200"
                            enterFrom="opacity-0 scale-95"
                            enterTo="opacity-100 scale-100"
                            leave="ease-in duration-150"
                            leaveFrom="opacity-100 scale-100"
                            leaveTo="opacity-0 scale-95"
                        >
                            <Dialog.Panel
                                className={`panel overflow-hidden p-0 ${
                                    showCompareCalendar ? 'w-max max-w-[calc(100vw-2rem)]' : 'w-full max-w-4xl'
                                }`}
                            >
                                <div className="flex flex-col md:flex-row">
                                    <div className="border-b border-white-dark/10 md:w-56 md:border-b-0 md:border-r">
                                        <div className="p-4">
                                            <Dialog.Title className="text-base font-semibold">Filter Periode</Dialog.Title>
                                            <p className="mt-1 text-xs text-gray-500">Pilih preset atau custom range</p>
                                        </div>
                                        <div className="max-h-[420px] overflow-y-auto px-2 pb-2">
                                            {STATS_PRESET_OPTIONS.map((option) => (
                                                <button
                                                    key={option.id}
                                                    type="button"
                                                    className={`mb-1 w-full rounded px-3 py-2 text-left text-sm transition ${
                                                        draftPreset === option.id
                                                            ? 'bg-primary/10 font-semibold text-primary'
                                                            : 'hover:bg-white-dark/10'
                                                    }`}
                                                    onClick={() => handlePresetSelect(option.id)}
                                                >
                                                    {option.label}
                                                </button>
                                            ))}
                                        </div>
                                        <div className="border-t border-white-dark/10 p-4">
                                            <label className="flex items-center justify-between gap-3 text-sm font-medium">
                                                <span>Compare</span>
                                                <input
                                                    type="checkbox"
                                                    className="form-checkbox"
                                                    checked={draftCompareEnabled}
                                                    onChange={(e) => handleCompareToggle(e.target.checked)}
                                                />
                                            </label>
                                            <p className="mt-1 text-xs text-gray-500">
                                                {allowCustomCompareRange
                                                    ? 'Bandingkan dengan rentang yang kamu pilih'
                                                    : 'Bandingkan dengan periode sebelumnya'}
                                            </p>
                                        </div>
                                    </div>

                                    <div className={`${showCompareCalendar ? '' : 'flex-1'} p-4`}>
                                        <div className={`grid gap-4 ${showCompareCalendar ? 'lg:grid-cols-2' : ''}`}>
                                            <div>
                                                <p className="mb-2 text-xs font-semibold text-gray-600 dark:text-gray-300">
                                                    Periode aktif
                                                </p>
                                                <InlineRangePicker
                                                    pickerRef={flatpickrRef}
                                                    range={draftRange}
                                                    onChange={handleFlatpickrChange}
                                                />
                                            </div>

                                            {showCompareCalendar ? (
                                                <div>
                                                    <div className="mb-2 flex items-center justify-between gap-2">
                                                        <p className="text-xs font-semibold text-gray-600 dark:text-gray-300">
                                                            Compare period
                                                        </p>
                                                        <button
                                                            type="button"
                                                            className="text-xs text-primary underline"
                                                            onClick={handleResetCompare}
                                                        >
                                                            Reset ke periode sebelumnya
                                                        </button>
                                                    </div>
                                                    <InlineRangePicker
                                                        pickerRef={compareFlatpickrRef}
                                                        range={draftCompareRange}
                                                        onChange={handleCompareFlatpickrChange}
                                                    />
                                                </div>
                                            ) : null}
                                        </div>

                                        <div className="mt-4 space-y-1 text-xs text-gray-500">
                                            <p>
                                                Periode aktif: <strong>{formatRangeLabel(draftRange)}</strong> (WIB)
                                            </p>
                                            {compareRange ? (
                                                <p>
                                                    Compare period: <strong>{formatRangeLabel(compareRange)}</strong>
                                                </p>
                                            ) : null}
                                        </div>

                                        <div className="mt-6 flex items-center justify-end gap-3">
                                            <button type="button" className="btn btn-outline-danger" onClick={handleCancel}>
                                                Cancel
                                            </button>
                                            <button
                                                type="button"
                                                className="btn btn-primary"
                                                onClick={handleApply}
                                                disabled={
                                                    !isValidDateRange(draftRange) ||
                                                    (Boolean(showCompareCalendar) && !isValidDateRange(draftCompareRange))
                                                }
                                            >
                                                Apply
                                            </button>
                                        </div>
                                    </div>
                                </div>
                            </Dialog.Panel>
                        </Transition.Child>
                    </div>
                </div>
            </Dialog>
        </Transition>
    );
};

export default StatsDateRangePicker;
