import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useDispatch } from 'react-redux';
import { useRouter } from 'next/router';

import { setPageTitle } from '../../../store/themeConfigSlice';
import { coloredToast } from '@/lib/toast';
import {
    DateRange,
    StatsPreset,
    detectPresetFromRange,
    formatRangeLabel,
    getPresetRange,
    getPreviousPeriodRange,
} from '@/lib/abandoned-cart-stats-date';
import {
    defaultJourneyStatsPrefs,
    loadJourneyStatsPrefs,
    saveJourneyStatsPrefs,
} from '@/lib/analytics-stats-prefs';
import type { JourneyCountMode } from '@/lib/journey-count-mode';
import { JourneyCountModeProvider } from '@/components/UserJourney/JourneyCountModeContext';
import StatsDateRangePicker from '@/components/AbandonedCart/StatsDateRangePicker';
import JourneyStatsPanel, { JourneyStats } from '@/components/UserJourney/JourneyStatsPanel';
import JourneyWidgetBody from '@/components/UserJourney/JourneyWidgetBody';
import {
    isSameAcquisitionFilters,
    type AcquisitionActiveFilters,
    type AcquisitionRowClickPayload,
} from '@/components/UserJourney/AcquisitionTable';
import SessionListTable, { JourneySessionRow } from '@/components/UserJourney/SessionListTable';
import SessionDetailDrawer, { JourneySessionDetail } from '@/components/UserJourney/SessionDetailDrawer';
import JourneyRealtimePanel from '@/components/UserJourney/JourneyRealtimePanel';
import StatsCompareBadge from '@/components/AbandonedCart/StatsCompareBadge';
import CompareTrendArrow from '@/components/AbandonedCart/CompareTrendArrow';
import {
    JOURNEY_WIDGET_MAP,
    loadJourneyLayout,
    type JourneyWidgetId,
} from '@/components/UserJourney/widget-registry';

const WIDGET_INCLUDE_MAP: Record<JourneyWidgetId, string[]> = {
    overview: [],
    funnel: [],
    acquisition: ['acquisition'],
    top_pages: ['path'],
    entry_exit: ['path'],
    auth: ['auth'],
    exit_intent: ['exit_intent'],
    commerce: ['commerce'],
    wedding: ['wedding'],
    search: ['search'],
    link_clicks: ['link_clicks'],
    item_cart: ['item_report'],
};

type NavSection = 'dashboard' | 'sessions' | 'realtime' | JourneyWidgetId;

type NavItem = {
    id: NavSection;
    label: string;
    hint?: string;
};

type NavGroup = {
    title: string;
    items: NavItem[];
};

const NAV_GROUPS: NavGroup[] = [
    {
        title: 'Overview',
        items: [
            { id: 'dashboard', label: 'Dashboard' },
            { id: 'acquisition', label: 'User Acquisition' },
            { id: 'link_clicks', label: 'Aurum Linktree' },
        ],
    },
    {
        title: 'Behavior',
        items: [
            { id: 'funnel', label: 'Purchase Journey' },
            { id: 'top_pages', label: 'Landing Pages' },
            { id: 'entry_exit', label: 'Entry & Exit' },
        ],
    },
    {
        title: 'Products',
        items: [
            { id: 'commerce', label: 'Product insights' },
            { id: 'item_cart', label: 'Add to Cart Item' },
            { id: 'search', label: 'Search insights' },
        ],
    },
    {
        title: 'Users',
        items: [
            { id: 'auth', label: 'Authentication' },
            { id: 'exit_intent', label: 'Exit Intent' },
            { id: 'realtime', label: 'Realtime', hint: 'Active users live' },
            { id: 'sessions', label: 'Sessions' },
        ],
    },
];

const HEAVY_INCLUDE_KEYS = new Set(['path', 'auth', 'exit_intent', 'commerce', 'wedding', 'search', 'popup', 'item_report']);
/** Token aman agar API tidak fallback ke include=all saat tidak ada widget berat/light khusus */
const STATS_INCLUDE_FALLBACK = 'overview';

function collectIncludes(section: NavSection) {
    const lightKeys = new Set<string>();
    const heavyKeys = new Set<string>();

    const addWidget = (id: JourneyWidgetId) => {
        (WIDGET_INCLUDE_MAP[id] || []).forEach((key) => {
            if (HEAVY_INCLUDE_KEYS.has(key)) heavyKeys.add(key);
            else lightKeys.add(key);
        });
    };

    let wantsCompare = false;

    if (section === 'dashboard') {
        const layout = loadJourneyLayout();
        layout.items.forEach((item) => addWidget(item.id));
        wantsCompare = layout.items.some((item) => item.id === 'overview');
    } else if (section !== 'sessions' && section !== 'realtime') {
        addWidget(section);
    }

    return {
        lightInclude: [...lightKeys].join(',') || STATS_INCLUDE_FALLBACK,
        heavyInclude: [...heavyKeys].join(','),
        wantsCompare,
    };
}

const PAGE_SIZE = 20;
const UTM_SEARCH_DEBOUNCE_MS = 350;

function JourneyLoadingPanel({ label = 'Memuat data...' }: { label?: string }) {
    return (
        <div className="panel flex min-h-[280px] flex-col items-center justify-center gap-3">
            <span className="inline-block h-10 w-10 animate-spin rounded-full border-4 border-primary border-l-transparent" />
            <p className="text-sm text-gray-500">{label}</p>
        </div>
    );
}

function JourneyLoadingOverlay({ label = 'Memuat data...' }: { label?: string }) {
    return (
        <div className="absolute inset-0 z-20 flex items-center justify-center rounded-md bg-white/70 dark:bg-black/40 backdrop-blur-[1px]">
            <div className="flex flex-col items-center gap-3">
                <span className="inline-block h-10 w-10 animate-spin rounded-full border-4 border-primary border-l-transparent" />
                <p className="text-sm text-gray-500">{label}</p>
            </div>
        </div>
    );
}

const UserJourneyPage = () => {
    const dispatch = useDispatch();
    const router = useRouter();
    const initialPrefs =
        typeof window !== 'undefined' ? loadJourneyStatsPrefs() : defaultJourneyStatsPrefs();
    const [activeSection, setActiveSection] = useState<NavSection>('dashboard');
    const [isLoading, setIsLoading] = useState(false);
    const [isRefreshing, setIsRefreshing] = useState(false);

    const [appliedStatsRange, setAppliedStatsRange] = useState<DateRange>(() => initialPrefs.range);
    const [appliedPreset, setAppliedPreset] = useState<StatsPreset>(() => initialPrefs.preset);
    const [isStatsPickerOpen, setIsStatsPickerOpen] = useState(false);
    const [statsData, setStatsData] = useState<JourneyStats | null>(null);
    const [compareBySection, setCompareBySection] = useState<Record<string, boolean>>(
        () => initialPrefs.compareBySection
    );
    const [compareRange, setCompareRange] = useState<DateRange | null>(() => initialPrefs.compareRange);
    const [compareStatsData, setCompareStatsData] = useState<JourneyStats | null>(null);
    const [compareTotalRecords, setCompareTotalRecords] = useState<number | null>(null);
    const [prefsHydrated, setPrefsHydrated] = useState(false);
    const [countMode, setCountMode] = useState<JourneyCountMode>(() => initialPrefs.countMode);

    const [sessions, setSessions] = useState<JourneySessionRow[]>([]);
    const [page, setPage] = useState(1);
    const [totalRecords, setTotalRecords] = useState(0);
    const [sessionSearchInput, setSessionSearchInput] = useState('');
    const [sessionSearchQ, setSessionSearchQ] = useState('');
    const [sessionFlag, setSessionFlag] = useState<
        'all' | 'atc' | 'checkout' | 'purchase' | 'auth' | 'wedding' | 'exit_modal'
    >('all');
    const [sessionQuality, setSessionQuality] = useState<'all' | 'engaged' | 'not_engaged' | 'bot'>('all');

    // Acquisition filters (stats / dashboard widgets)
    const [channelGroupFilter, setChannelGroupFilter] = useState<string>('');
    const [utmSourceInput, setUtmSourceInput] = useState<string>('');
    const [utmSourceFilter, setUtmSourceFilter] = useState<string>('');
    const [utmMediumFilter, setUtmMediumFilter] = useState<string>('');
    const [utmCampaignInput, setUtmCampaignInput] = useState<string>('');
    const [utmCampaignFilter, setUtmCampaignFilter] = useState<string>('');

    const [itemChannelFilter, setItemChannelFilter] = useState('');
    const [itemUtmSourceFilter, setItemUtmSourceFilter] = useState('');
    const [itemUtmMediumFilter, setItemUtmMediumFilter] = useState('');
    const [itemUtmCampaignFilter, setItemUtmCampaignFilter] = useState('');

    // Sessions tab filters (terpisah — reset di Sessions tidak mempengaruhi stats)
    const [sessionChannelFilter, setSessionChannelFilter] = useState<string>('');
    const [sessionUtmSourceInput, setSessionUtmSourceInput] = useState<string>('');
    const [sessionUtmSourceFilter, setSessionUtmSourceFilter] = useState<string>('');
    const [sessionUtmMediumInput, setSessionUtmMediumInput] = useState<string>('');
    const [sessionUtmMediumFilter, setSessionUtmMediumFilter] = useState<string>('');
    const [sessionUtmCampaignInput, setSessionUtmCampaignInput] = useState<string>('');
    const [sessionUtmCampaignFilter, setSessionUtmCampaignFilter] = useState<string>('');

    const [detailOpen, setDetailOpen] = useState(false);
    const [detailLoading, setDetailLoading] = useState(false);
    const [detail, setDetail] = useState<JourneySessionDetail | null>(null);

    useEffect(() => {
        dispatch(setPageTitle('User Journey'));
    }, [dispatch]);

    useEffect(() => {
        const saved = loadJourneyStatsPrefs();
        setAppliedStatsRange(saved.range);
        setAppliedPreset(saved.preset);
        setCompareRange(saved.compareRange);
        setCompareBySection(saved.compareBySection);
        setCountMode(saved.countMode);
        setPrefsHydrated(true);
    }, []);

    useEffect(() => {
        if (!prefsHydrated) return;
        saveJourneyStatsPrefs({
            range: appliedStatsRange,
            preset: appliedPreset,
            compareRange,
            compareBySection,
            countMode,
        });
    }, [prefsHydrated, appliedStatsRange, appliedPreset, compareRange, compareBySection, countMode]);

    useEffect(() => {
        const timer = window.setTimeout(() => {
            const next = sessionSearchInput.trim();
            setSessionSearchQ((prev) => {
                if (prev !== next) setPage(1);
                return next;
            });
        }, 350);
        return () => window.clearTimeout(timer);
    }, [sessionSearchInput]);

    useEffect(() => {
        const timer = window.setTimeout(() => {
            const next = sessionUtmSourceInput.trim();
            setSessionUtmSourceFilter((prev) => {
                if (prev !== next) setPage(1);
                return next;
            });
        }, UTM_SEARCH_DEBOUNCE_MS);
        return () => window.clearTimeout(timer);
    }, [sessionUtmSourceInput]);

    useEffect(() => {
        const timer = window.setTimeout(() => {
            const next = sessionUtmMediumInput.trim();
            setSessionUtmMediumFilter((prev) => {
                if (prev !== next) setPage(1);
                return next;
            });
        }, UTM_SEARCH_DEBOUNCE_MS);
        return () => window.clearTimeout(timer);
    }, [sessionUtmMediumInput]);

    useEffect(() => {
        const timer = window.setTimeout(() => {
            const next = sessionUtmCampaignInput.trim();
            setSessionUtmCampaignFilter((prev) => {
                if (prev !== next) setPage(1);
                return next;
            });
        }, UTM_SEARCH_DEBOUNCE_MS);
        return () => window.clearTimeout(timer);
    }, [sessionUtmCampaignInput]);

    useEffect(() => {
        const timer = window.setTimeout(() => {
            const next = utmSourceInput.trim();
            setUtmSourceFilter(next);
        }, UTM_SEARCH_DEBOUNCE_MS);
        return () => window.clearTimeout(timer);
    }, [utmSourceInput]);

    useEffect(() => {
        const timer = window.setTimeout(() => {
            const next = utmCampaignInput.trim();
            setUtmCampaignFilter(next);
        }, UTM_SEARCH_DEBOUNCE_MS);
        return () => window.clearTimeout(timer);
    }, [utmCampaignInput]);

    const sessionsFetchSeq = useRef(0);

    const { lightInclude, heavyInclude, wantsCompare } = useMemo(
        () => collectIncludes(activeSection),
        [activeSection]
    );

    const sectionCompareEnabled =
        activeSection !== 'realtime' &&
        (activeSection === 'dashboard'
            ? compareBySection.dashboard !== false
            : Boolean(compareBySection[activeSection]));

    const buildFilterParams = (range: DateRange, include: string) => {
        const params = new URLSearchParams({
            date_from: range.from,
            date_to: range.to,
            exclude_bots: '1',
            include,
        });
        if (wantsCompare || sectionCompareEnabled || include.includes('snapshot')) {
            params.set('compare', '1');
        }
        if (activeSection === 'item_cart') {
            if (itemChannelFilter.trim()) params.set('channel_group', itemChannelFilter.trim());
            if (itemUtmSourceFilter.trim()) params.set('utm_source', itemUtmSourceFilter.trim().toLowerCase());
            if (itemUtmMediumFilter.trim()) params.set('utm_medium', itemUtmMediumFilter.trim().toLowerCase());
            if (itemUtmCampaignFilter.trim()) params.set('utm_campaign', itemUtmCampaignFilter.trim().toLowerCase());
        } else {
            if (channelGroupFilter.trim()) params.set('channel_group', channelGroupFilter.trim());
            if (utmSourceFilter.trim()) params.set('utm_source', utmSourceFilter.trim().toLowerCase());
            if (utmMediumFilter.trim()) params.set('utm_medium', utmMediumFilter.trim().toLowerCase());
            if (utmCampaignFilter.trim()) params.set('utm_campaign', utmCampaignFilter.trim().toLowerCase());
        }
        return params;
    };

    const fetchJourneyStats = async (range: DateRange): Promise<JourneyStats> => {
        const api_url = process.env.API_URL;

        // Fase 1: fetch ringan (overview + funnel + acquisition) — cepat
        const lightParams = buildFilterParams(range, lightInclude);
        const lightRes = await fetch(`${api_url}api/journey/stats?${lightParams}`, {
            method: 'GET',
            headers: { 'Content-Type': 'application/json' },
            credentials: 'include',
        });
        const lightData = await lightRes.json();
        if (!lightRes.ok) {
            throw new Error(lightData?.message || 'Gagal memuat statistik journey');
        }
        if (typeof lightData?.overview?.total_sessions !== 'number') {
            throw new Error(lightData?.message || 'Format statistik tidak valid');
        }

        // Fase 2: fetch berat (commerce, search, path, auth, dll)
        if (heavyInclude) {
            try {
                const heavyParams = buildFilterParams(range, heavyInclude);
                const heavyRes = await fetch(`${api_url}api/journey/stats?${heavyParams}`, {
                    method: 'GET',
                    headers: { 'Content-Type': 'application/json' },
                    credentials: 'include',
                });
                const heavyData = await heavyRes.json();
                if (heavyRes.ok && heavyData && typeof heavyData === 'object') {
                    return {
                        ...lightData,
                        ...heavyData,
                        overview: lightData.overview,
                        funnel: lightData.funnel,
                        acquisition: lightData.acquisition,
                    };
                }
            } catch {
                // Tetap tampilkan data light jika fetch berat gagal
            }
        }

        return lightData;
    };

    const fetchSessions = useCallback(async () => {
        const fetchId = ++sessionsFetchSeq.current;
        setIsLoading(true);
        try {
            const api_url = process.env.API_URL;
            const params = new URLSearchParams({
                date_from: appliedStatsRange.from,
                date_to: appliedStatsRange.to,
                page: String(page),
                per_page: String(PAGE_SIZE),
                exclude_bots: sessionQuality === 'bot' ? '0' : '1',
                group_by: 'visitor',
                quality: sessionQuality,
            });
            if (sessionSearchQ) params.set('q', sessionSearchQ);
            if (sessionFlag === 'atc') params.set('has_add_to_cart', '1');
            if (sessionFlag === 'checkout') params.set('reached_checkout', '1');
            if (sessionFlag === 'purchase') params.set('has_purchase', '1');
            if (sessionFlag === 'auth') params.set('has_auth', '1');
            if (sessionFlag === 'wedding') params.set('has_wedding', '1');
            if (sessionFlag === 'exit_modal') params.set('exit_modal_shown', '1');
            if (sessionChannelFilter.trim()) params.set('channel_group', sessionChannelFilter.trim());
            if (sessionUtmSourceFilter.trim()) {
                params.set('utm_source', sessionUtmSourceFilter.trim().toLowerCase());
            }
            if (sessionUtmMediumFilter.trim()) {
                params.set('utm_medium', sessionUtmMediumFilter.trim().toLowerCase());
            }
            if (sessionUtmCampaignFilter.trim()) {
                params.set('utm_campaign', sessionUtmCampaignFilter.trim().toLowerCase());
            }

            const response = await fetch(`${api_url}api/journey/sessions?${params}`, {
                method: 'GET',
                headers: { 'Content-Type': 'application/json' },
                credentials: 'include',
            });
            const data = await response.json();
            if (fetchId !== sessionsFetchSeq.current) return;
            if (!response.ok) {
                throw new Error(data?.message || 'Gagal memuat sessions');
            }
            setSessions(Array.isArray(data?.data) ? data.data : []);
            setTotalRecords(Number(data?.pagination?.total) || 0);

            if (sectionCompareEnabled) {
                const nextCompareRange = compareRange || getPreviousPeriodRange(appliedStatsRange);
                const prevParams = new URLSearchParams(params);
                prevParams.set('date_from', nextCompareRange.from);
                prevParams.set('date_to', nextCompareRange.to);
                prevParams.set('page', '1');
                prevParams.set('per_page', '1');
                const prevRes = await fetch(`${api_url}api/journey/sessions?${prevParams}`, {
                    method: 'GET',
                    headers: { 'Content-Type': 'application/json' },
                    credentials: 'include',
                });
                const prevData = await prevRes.json();
                if (fetchId !== sessionsFetchSeq.current) return;
                setCompareTotalRecords(prevRes.ok ? Number(prevData?.pagination?.total) || 0 : null);
            } else {
                setCompareTotalRecords(null);
            }
        } catch (error: any) {
            if (fetchId !== sessionsFetchSeq.current) return;
            coloredToast('danger', error?.message || 'Gagal memuat sessions');
            setSessions([]);
            setTotalRecords(0);
        } finally {
            if (fetchId === sessionsFetchSeq.current) {
                setIsLoading(false);
            }
        }
    }, [
        appliedStatsRange,
        page,
        sessionSearchQ,
        sessionFlag,
        sessionQuality,
        sessionChannelFilter,
        sessionUtmSourceFilter,
        sessionUtmMediumFilter,
        sessionUtmCampaignFilter,
        sectionCompareEnabled,
        compareRange,
    ]);

    const statsDataRef = useRef<JourneyStats | null>(null);
    statsDataRef.current = statsData;

    const fetchStatsTab = useCallback(async () => {
        const hasExistingData = Boolean(statsDataRef.current);
        if (hasExistingData) setIsRefreshing(true);
        else setIsLoading(true);
        try {
            if (sectionCompareEnabled) {
                const nextCompareRange = compareRange || getPreviousPeriodRange(appliedStatsRange);
                const [current, previous] = await Promise.all([
                    fetchJourneyStats(appliedStatsRange),
                    fetchJourneyStats(nextCompareRange),
                ]);
                setStatsData(current);
                setCompareStatsData(previous);
            } else {
                setCompareStatsData(null);
                const current = await fetchJourneyStats(appliedStatsRange);
                setStatsData(current);
            }
        } catch (error: any) {
            coloredToast('danger', error?.message || 'Gagal memuat statistik');
            setStatsData(null);
            setCompareStatsData(null);
        } finally {
            setIsLoading(false);
            setIsRefreshing(false);
        }
    }, [appliedStatsRange, sectionCompareEnabled, compareRange, activeSection, channelGroupFilter, utmSourceFilter, utmMediumFilter, utmCampaignFilter, itemChannelFilter, itemUtmSourceFilter, itemUtmMediumFilter, itemUtmCampaignFilter, lightInclude, heavyInclude, wantsCompare]);

    useEffect(() => {
        if (!prefsHydrated) return;
        if (activeSection === 'sessions') {
            fetchSessions();
        } else if (activeSection !== 'realtime') {
            fetchStatsTab();
        }
    }, [prefsHydrated, activeSection, fetchSessions, fetchStatsTab]);

    const openSessionDetail = async (
        row: JourneySessionRow | Pick<JourneySessionRow, 'id' | 'visitor_id' | 'session_id'>,
        opts?: { fromRealtime?: boolean; sessionRef?: string }
    ) => {
        if (!row?.visitor_id && !row?.id) {
            coloredToast('danger', 'Data visitor tidak valid');
            return;
        }
        setDetailOpen(true);
        setDetailLoading(true);
        setDetail(null);
        try {
            const api_url = process.env.API_URL;
            const detailId = row.id || row.visitor_id;
            const range = opts?.fromRealtime ? getPresetRange('today') : appliedStatsRange;
            const sessionRef = String(opts?.sessionRef || '').trim();
            const params = new URLSearchParams({
                date_from: range.from,
                date_to: range.to,
                grouped: '1',
            });
            if (sessionRef) {
                params.set('session_id', sessionRef);
            }
            const response = await fetch(
                `${api_url}api/journey/sessions/${encodeURIComponent(detailId)}?${params}`,
                {
                    method: 'GET',
                    headers: { 'Content-Type': 'application/json' },
                    credentials: 'include',
                }
            );
            const data = await response.json();
            if (!response.ok) {
                throw new Error(data?.message || 'Gagal memuat detail session');
            }
            setDetail(data);
        } catch (error: any) {
            coloredToast('danger', error?.message || 'Gagal memuat detail session');
            setDetailOpen(false);
        } finally {
            setDetailLoading(false);
        }
    };

    const openedVisitorRef = useRef('');
    useEffect(() => {
        if (!router.isReady || !prefsHydrated) return;
        const visitorId = String(router.query.visitor_id || '').trim();
        if (!visitorId) return;
        setActiveSection('sessions');
        setSessionSearchInput(visitorId);
        setSessionSearchQ(visitorId);
        if (openedVisitorRef.current === visitorId) return;
        openedVisitorRef.current = visitorId;
        openSessionDetail({ id: visitorId, visitor_id: visitorId, session_id: '' });
    }, [router.isReady, router.query.visitor_id, prefsHydrated]);

    const acquisitionFilters = useMemo<AcquisitionActiveFilters>(
        () => ({
            channel_group: channelGroupFilter.trim(),
            utm_source: utmSourceFilter.trim(),
            utm_medium: utmMediumFilter.trim(),
            utm_campaign: utmCampaignFilter.trim(),
        }),
        [channelGroupFilter, utmSourceFilter, utmMediumFilter, utmCampaignFilter]
    );

    const hasAcquisitionFilters = Boolean(
        acquisitionFilters.channel_group ||
        acquisitionFilters.utm_source ||
        acquisitionFilters.utm_medium ||
        acquisitionFilters.utm_campaign
    );

    const clearAcquisitionFilters = useCallback(() => {
        setChannelGroupFilter('');
        setUtmSourceInput('');
        setUtmSourceFilter('');
        setUtmMediumFilter('');
        setUtmCampaignInput('');
        setUtmCampaignFilter('');
    }, []);

    const clearSessionFilters = useCallback(() => {
        setSessionChannelFilter('');
        setSessionUtmSourceInput('');
        setSessionUtmSourceFilter('');
        setSessionUtmMediumInput('');
        setSessionUtmMediumFilter('');
        setSessionUtmCampaignInput('');
        setSessionUtmCampaignFilter('');
        setSessionSearchInput('');
        setSessionSearchQ('');
        setSessionFlag('all');
        setSessionQuality('all');
        setPage(1);
    }, []);

    const handleItemAttributionFiltersChange = useCallback(
        (next: { channel_group: string; utm_source: string; utm_medium: string; utm_campaign: string }) => {
            setItemChannelFilter(next.channel_group);
            setItemUtmSourceFilter(next.utm_source);
            setItemUtmMediumFilter(next.utm_medium);
            setItemUtmCampaignFilter(next.utm_campaign);
        },
        []
    );

    const applyAcquisitionFilters = useCallback((filters: AcquisitionActiveFilters) => {
        setChannelGroupFilter(filters.channel_group);
        setUtmSourceInput(filters.utm_source);
        setUtmSourceFilter(filters.utm_source);
        setUtmMediumFilter(filters.utm_medium || '');
        setUtmCampaignInput(filters.utm_campaign);
        setUtmCampaignFilter(filters.utm_campaign);
        setSessionChannelFilter(filters.channel_group);
        setSessionUtmSourceInput(filters.utm_source);
        setSessionUtmSourceFilter(filters.utm_source);
        setSessionUtmMediumInput(filters.utm_medium || '');
        setSessionUtmMediumFilter(filters.utm_medium || '');
        setSessionUtmCampaignInput(filters.utm_campaign);
        setSessionUtmCampaignFilter(filters.utm_campaign);
        setPage(1);
    }, []);

    const hasSessionFilters = Boolean(
        sessionChannelFilter.trim() ||
        sessionUtmSourceFilter.trim() ||
        sessionUtmMediumFilter.trim() ||
        sessionUtmCampaignFilter.trim() ||
        sessionSearchQ ||
        sessionFlag !== 'all' ||
        sessionQuality !== 'all'
    );

    const handleAcquisitionRowClick = useCallback(
        (payload: AcquisitionRowClickPayload) => {
            const { filters } = payload;
            if (isSameAcquisitionFilters(filters, acquisitionFilters)) {
                clearAcquisitionFilters();
                clearSessionFilters();
                return;
            }
            applyAcquisitionFilters(filters);
        },
        [acquisitionFilters, applyAcquisitionFilters, clearAcquisitionFilters, clearSessionFilters]
    );

    const handleNavigateSection = useCallback((section: 'acquisition' | 'sessions' | 'realtime') => {
        setActiveSection(section);
    }, []);

    return (
        <div>
            <div className="panel mb-5">
                <div className="flex flex-wrap items-center justify-between gap-3">
                    <div>
                        <h2 className="text-xl font-bold">Analytics</h2>

                    </div>
                    <div className="flex flex-wrap items-center gap-2">
                        {activeSection !== 'realtime' && activeSection !== 'sessions' ? (
                            <select
                                className="form-select w-auto"
                                value={countMode}
                                onChange={(e) => setCountMode(e.target.value as JourneyCountMode)}
                                title="Satuan angka journey"
                            >
                                <option value="users">Users</option>
                                <option value="sessions">Sessions</option>
                            </select>
                        ) : null}
                        <button type="button" className="btn btn-sm btn-outline-primary" onClick={() => setIsStatsPickerOpen(true)}>
                            {formatRangeLabel(appliedStatsRange)}
                            {sectionCompareEnabled && compareRange ? (
                                <span className="ml-1 font-normal text-primary">vs {formatRangeLabel(compareRange)}</span>
                            ) : null}
                        </button>
                    </div>
                </div>
            </div>

            <div className="flex flex-col lg:flex-row gap-4 items-start">
                <aside className="panel w-1/2 lg:w-56 xl:w-60 shrink-0 lg:sticky lg:top-20 p-3">
                    <p className="px-2 mb-2 text-[11px] font-semibold uppercase tracking-wide text-gray-400">
                        Menu
                    </p>
                    <nav className="space-y-3">
                        {NAV_GROUPS.map((group) => (
                            <div key={group.title}>
                                <p className="px-2 mb-1 text-[11px] font-semibold text-gray-400">{group.title}</p>
                                <ul className="space-y-0.5">
                                    {group.items.map((item) => {
                                        const active = activeSection === item.id;
                                        return (
                                            <li key={item.id}>
                                                <button
                                                    type="button"
                                                    className={`w-full rounded-md px-2.5 py-1.5 text-left transition ${active
                                                            ? 'bg-primary/10 text-primary font-semibold'
                                                            : 'text-gray-600 hover:bg-gray-50 dark:text-gray-300 dark:hover:bg-white/5'
                                                        }`}
                                                    onClick={() => {
                                                        setActiveSection(item.id);
                                                        if (item.id === 'sessions') setPage(1);
                                                    }}
                                                >
                                                    <span className="block text-sm leading-tight">{item.label}</span>
                                                    {item.hint ? (
                                                        <span className={`block text-[11px] font-normal ${active ? 'text-primary/70' : 'text-gray-400'}`}>
                                                            {item.hint}
                                                        </span>
                                                    ) : null}
                                                </button>
                                            </li>
                                        );
                                    })}
                                </ul>
                            </div>
                        ))}
                    </nav>
                </aside>

                <div className="min-w-0 flex-1">
                    {activeSection === 'realtime' ? (
                        <JourneyRealtimePanel
                            onUserClick={(row, meta) =>
                                openSessionDetail(row, {
                                    fromRealtime: true,
                                    sessionRef: meta?.sessionRef,
                                })
                            }
                        />
                    ) : activeSection === 'sessions' ? (
                        <div className="relative">
                            {isLoading ? <JourneyLoadingOverlay label="Memuat sessions..." /> : null}
                            <div className="panel">
                                <div className="mb-5 flex flex-col gap-3">
                                    <div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
                                        <div>
                                            <h3 className="text-lg font-semibold">Sessions</h3>
                                            {sectionCompareEnabled && compareTotalRecords != null ? (
                                                <div className="mt-1 flex flex-wrap items-center gap-2">
                                                    <span className="text-2xl font-bold">{totalRecords.toLocaleString('id-ID')}</span>
                                                    <CompareTrendArrow current={totalRecords} previous={compareTotalRecords} />
                                                    <StatsCompareBadge
                                                        current={totalRecords}
                                                        previous={compareTotalRecords}
                                                        compareEnabled
                                                    />
                                                </div>
                                            ) : null}
                                        </div>
                                        <div className="flex flex-wrap items-center gap-2">
                                            <input
                                                id='visitorNameInput'
                                                className="form-input w-48"
                                                placeholder="Cari visitor / user / path"
                                                value={sessionSearchInput}
                                                onChange={(e) => setSessionSearchInput(e.target.value)}
                                                
                                            />
                                            <select
                                                id='sessionQualitySelect'
                                                className="form-select w-48"
                                                value={sessionQuality}
                                                onChange={(e) => {
                                                    setSessionQuality(e.target.value as typeof sessionQuality);
                                                    setPage(1);
                                                }}
                                            >
                                                <option value="all">Semua (kecuali bot)</option>
                                                <option value="engaged">Engaged</option>
                                                <option value="not_engaged">Tidak engaged</option>
                                                <option value="bot">Bot saja</option>
                                            </select>
                                            <select
                                                id='sessionFlagSelect'
                                                className="form-select w-48"
                                                value={sessionFlag}
                                                onChange={(e) => {
                                                    setSessionFlag(e.target.value as typeof sessionFlag);
                                                    setPage(1);
                                                }}
                                            >
                                                <option value="all">Semua flag</option>
                                                <option value="atc">ATC</option>
                                                <option value="checkout">Checkout</option>
                                                <option value="purchase">Purchase</option>
                                                <option value="auth">Auth</option>
                                                <option value="wedding">Wedding</option>
                                                <option value="exit_modal">Exit modal</option>
                                            </select>
                                            <select
                                                id='sessionChannelSelect'
                                                className="form-select w-[160px]"
                                                value={sessionChannelFilter}
                                                onChange={(e) => {
                                                    setSessionChannelFilter(e.target.value);
                                                    setPage(1);
                                                }}
                                            >
                                                <option value="">Semua channel</option>
                                                <option value="Direct">Direct</option>
                                                <option value="Paid Social">Paid Social</option>
                                                <option value="Paid Search">Paid Search</option>
                                                <option value="Organic Search">Organic Search</option>
                                                <option value="Organic Social">Organic Social</option>
                                                <option value="Referral">Referral</option>
                                                <option value="Email">Email</option>
                                                <option value="Display">Display</option>
                                                <option value="Affiliate">Affiliate</option>
                                                <option value="Other">Other</option>
                                                <option value="Unassigned">Unassigned</option>
                                            </select>
                                            <input
                                                id='sessionUtmSourceInput'
                                                className="form-input w-40"
                                                placeholder="UTM Source"
                                                value={sessionUtmSourceInput}
                                                onChange={(e) => setSessionUtmSourceInput(e.target.value)}
                                            />
                                            <input
                                                id='sessionUtmMediumInput'
                                                className="form-input w-40"
                                                placeholder="UTM Medium"
                                                value={sessionUtmMediumInput}
                                                onChange={(e) => setSessionUtmMediumInput(e.target.value)}
                                            />
                                            <input
                                                id='sessionUtmCampaignInput'
                                                className="form-input w-56"
                                                placeholder="UTM Campaign"
                                                value={sessionUtmCampaignInput}
                                                onChange={(e) => setSessionUtmCampaignInput(e.target.value)}
                                            />
                                            {hasSessionFilters ? (
                                                <button
                                                    type="button"
                                                    id='clearSessionFiltersButton'
                                                    className="btn btn-sm btn-outline-danger"
                                                    onClick={clearSessionFilters}
                                                >
                                                    Reset filter
                                                </button>
                                            ) : null}
                                        </div>
                                    </div>
                                    {hasSessionFilters ? (
                                        <div className="flex flex-wrap items-center gap-2 rounded-md border border-primary/20 bg-primary/5 px-3 py-2 text-xs">
                                            <span className="font-semibold text-primary">Filter aktif:</span>
                                            {sessionSearchQ ? (
                                                <span className="badge dark:bg-black text-black">Cari: {sessionSearchQ}</span>
                                            ) : null}
                                            {sessionChannelFilter ? (
                                                <span className="badge dark:bg-black text-black">Channel: {sessionChannelFilter}</span>
                                            ) : null}
                                            {sessionUtmSourceFilter ? (
                                                <span className="badge dark:bg-black text-black">Source: {sessionUtmSourceFilter}</span>
                                            ) : null}
                                            {sessionUtmMediumFilter ? (
                                                <span className="badge dark:bg-black text-black">Medium: {sessionUtmMediumFilter}</span>
                                            ) : null}
                                            {sessionUtmCampaignFilter ? (
                                                <span className="badge dark:bg-black text-black">Campaign: {sessionUtmCampaignFilter}</span>
                                            ) : null}
                                            {sessionFlag !== 'all' ? (
                                                <span className="badge dark:bg-black text-black">Flag: {sessionFlag}</span>
                                            ) : null}
                                            {sessionQuality !== 'all' ? (
                                                <span className="badge dark:bg-black text-black">Quality: {sessionQuality}</span>
                                            ) : null}
                                        </div>
                                    ) : null}
                                </div>

                                <SessionListTable
                                    records={sessions}
                                    page={page}
                                    pageSize={PAGE_SIZE}
                                    totalRecords={totalRecords}
                                    isLoading={isLoading}
                                    onPageChange={setPage}
                                    onRowClick={openSessionDetail}
                                />
                            </div>
                        </div>
                    ) : (
                        <JourneyCountModeProvider value={countMode}>
                            <div className="relative min-h-[280px]">
                                {isRefreshing ? (
                                    <JourneyLoadingOverlay label="Memuat statistik..." />
                                ) : null}
                                {activeSection === 'acquisition' ? (
                                    <div className="panel mb-4">
                                        <div className="flex flex-wrap items-center gap-2">
                                            <div className="text-sm text-gray-500 w-full lg:w-auto">
                                                Filter acquisition:
                                            </div>
                                            <select
                                                className="form-select w-[160px]"
                                                value={channelGroupFilter}
                                                onChange={(e) => setChannelGroupFilter(e.target.value)}
                                            >
                                                <option value="">Semua channel</option>
                                                <option value="Direct">Direct</option>
                                                <option value="Paid Social">Paid Social</option>
                                                <option value="Paid Search">Paid Search</option>
                                                <option value="Organic Search">Organic Search</option>
                                                <option value="Organic Social">Organic Social</option>
                                                <option value="Referral">Referral</option>
                                                <option value="Email">Email</option>
                                                <option value="Display">Display</option>
                                                <option value="Affiliate">Affiliate</option>
                                                <option value="Other">Other</option>
                                                <option value="Unassigned">Unassigned</option>
                                            </select>
                                            <input
                                                className="form-input w-40"
                                                placeholder="UTM Source"
                                                value={utmSourceInput}
                                                onChange={(e) => setUtmSourceInput(e.target.value)}
                                            />
                                            <input
                                                className="form-input w-56"
                                                placeholder="UTM Campaign"
                                                value={utmCampaignInput}
                                                onChange={(e) => setUtmCampaignInput(e.target.value)}
                                            />
                                            {hasAcquisitionFilters ? (
                                                <button
                                                    type="button"
                                                    className="btn btn-sm btn-outline-danger"
                                                    onClick={clearAcquisitionFilters}
                                                >
                                                    Hapus filter
                                                </button>
                                            ) : null}
                                        </div>
                                    </div>
                                ) : null}
                                {isLoading && !statsData ? (
                                    <JourneyLoadingPanel />
                                ) : statsData ? (
                                    activeSection === 'dashboard' ? (
                                        <JourneyStatsPanel
                                            statsData={statsData}
                                            appliedStatsRange={appliedStatsRange}
                                            onOpenPicker={() => setIsStatsPickerOpen(true)}
                                            acquisitionFilters={acquisitionFilters}
                                            onAcquisitionRowClick={handleAcquisitionRowClick}
                                            onAcquisitionFiltersChange={applyAcquisitionFilters}
                                            onClearAcquisitionFilters={clearAcquisitionFilters}
                                            onNavigateSection={handleNavigateSection}
                                            isRefreshing={isRefreshing}
                                            compareEnabled={sectionCompareEnabled}
                                            compareStatsData={compareStatsData}
                                            compareRange={compareRange}
                                        />
                                    ) : (
                                        <div className="panel">
                                            <div className="mb-4">
                                                <h3 className="text-lg font-semibold">
                                                    {JOURNEY_WIDGET_MAP[activeSection]?.title || activeSection}
                                                </h3>
                                                {JOURNEY_WIDGET_MAP[activeSection]?.description ? (
                                                    <p className="text-sm text-gray-500">
                                                        {JOURNEY_WIDGET_MAP[activeSection].description}
                                                    </p>
                                                ) : null}
                                            </div>
                                            <JourneyWidgetBody
                                                id={activeSection}
                                                statsData={statsData}
                                                acquisitionFilters={acquisitionFilters}
                                                onAcquisitionRowClick={handleAcquisitionRowClick}
                                                onAcquisitionFiltersChange={applyAcquisitionFilters}
                                                onClearAcquisitionFilters={clearAcquisitionFilters}
                                                onNavigateSection={handleNavigateSection}
                                                isRefreshing={isRefreshing}
                                                isLoading={isLoading}
                                                compareEnabled={sectionCompareEnabled}
                                                compareStatsData={compareStatsData}
                                                dateRange={appliedStatsRange}
                                                compareRange={compareRange}
                                                itemAttributionFilters={{
                                                    channel_group: itemChannelFilter,
                                                    utm_source: itemUtmSourceFilter,
                                                    utm_medium: itemUtmMediumFilter,
                                                    utm_campaign: itemUtmCampaignFilter,
                                                }}
                                                onItemAttributionFiltersChange={handleItemAttributionFiltersChange}
                                            />
                                        </div>
                                    )
                                ) : (
                                    <div className="panel">Belum ada data statistik.</div>
                                )}
                            </div>
                        </JourneyCountModeProvider>
                    )}
                </div>
            </div>

            <StatsDateRangePicker
                isOpen={isStatsPickerOpen}
                appliedRange={appliedStatsRange}
                appliedPreset={appliedPreset}
                appliedCompareEnabled={sectionCompareEnabled}
                appliedCompareRange={compareRange}
                allowCustomCompareRange
                onClose={() => setIsStatsPickerOpen(false)}
                onApply={(range, preset, nextCompareEnabled, nextCompareRange) => {
                    const nextPreset = preset === 'custom' ? detectPresetFromRange(range) : preset;
                    const nextRange = nextCompareEnabled
                        ? nextCompareRange || getPreviousPeriodRange(range)
                        : compareRange || getPreviousPeriodRange(range);
                    setAppliedStatsRange(range);
                    setAppliedPreset(nextPreset);
                    setCompareBySection((prev) => ({
                        ...prev,
                        [activeSection]: activeSection === 'realtime' ? false : nextCompareEnabled,
                    }));
                    setCompareRange(nextRange);
                    setIsStatsPickerOpen(false);
                    setPage(1);
                }}
            />

            <SessionDetailDrawer
                open={detailOpen}
                loading={detailLoading}
                detail={detail}
                onClose={() => setDetailOpen(false)}
            />
        </div>
    );
};

export default UserJourneyPage;
