import { Fragment, useEffect, useMemo, useState } from 'react';
import { Dialog, Transition } from '@headlessui/react';
import styles from './journey-stats.module.css';
import type { JourneySessionRow } from './SessionListTable';

export interface JourneyEvent {
    type: string;
    path?: string;
    at?: string;
    meta?: Record<string, unknown>;
}

export interface JourneySessionDetail extends JourneySessionRow {
    auth?: {
        at?: string;
        method?: string;
        from_path?: string;
    } | null;
    user?: {
        id: string;
        name: string;
        email?: string;
        phone?: string;
    } | null;
    user_name?: string;
    session_count?: number;
    events: JourneyEvent[];
}

interface SessionDetailDrawerProps {
    open: boolean;
    loading: boolean;
    detail: JourneySessionDetail | null;
    onClose: () => void;
}

type TimelineNode =
    | { kind: 'boundary'; key: string; index: number; total: number; at?: string }
    | { kind: 'event'; key: string; event: JourneyEvent; sourceIndex: number; productViews?: JourneyEvent[] }
    | { kind: 'page_group'; key: string; events: JourneyEvent[]; startIndex: number; productViews: JourneyEvent[] };

const EVENT_LABELS: Record<string, string> = {
    page_view: 'Page view',
    product_view: 'Lihat produk',
    add_to_cart: 'Add to cart',
    remove_from_cart: 'Remove from cart',
    begin_checkout: 'Mulai checkout',
    purchase: 'Purchase',
    login_start: 'Login start',
    login_success: 'Login success',
    signup_start: 'Signup start',
    signup_success: 'Signup success',
    exit_modal_shown: 'Exit modal',
    exit_intent_unlock: 'Exit unlock',
    wedding_preview_open: 'Wedding preview',
    search: 'Search',
    voucher_apply: 'Voucher',
    session_end: 'Session end',
    popup_shown: 'Popup shown',
    popup_dismissed: 'Popup dismissed',
};

const HIDDEN_META_KEYS = new Set(['session_id', 'session_index', 'session_total', 'merged']);

function formatEventLabel(type: string) {
    return EVENT_LABELS[type] || type;
}

function formatTime(value?: string) {
    if (!value) return '—';
    return new Date(value).toLocaleString('id-ID', {
        day: '2-digit',
        month: 'short',
        hour: '2-digit',
        minute: '2-digit',
        second: '2-digit',
    });
}

function formatTimeRange(start?: string, end?: string) {
    if (!start && !end) return '—';
    if (!end || start === end) return formatTime(start);
    const startLabel = formatTime(start);
    const endLabel = end
        ? new Date(end).toLocaleTimeString('id-ID', {
            hour: '2-digit',
            minute: '2-digit',
            second: '2-digit',
        })
        : '';
    return `${startLabel} – ${endLabel}`;
}

function isBrowseEvent(type?: string) {
    return type === 'page_view' || type === 'product_view';
}

function productPath(event: JourneyEvent) {
    const slug = String(event.meta?.product_slug || '').replace(/^\/+/, '');
    if (event.path) return event.path;
    if (slug) return slug.startsWith('product/') ? `/${slug}` : `/product/${slug}`;
    return '';
}

function pathsMatch(pagePath: string, productEvent: JourneyEvent) {
    const a = (pagePath || '').replace(/\/+$/, '') || '/';
    const b = productPath(productEvent).replace(/\/+$/, '') || '/';
    if (a === b) return true;
    const slug = String(productEvent.meta?.product_slug || '');
    return Boolean(slug) && a.endsWith(`/product/${slug}`);
}

function productLabel(event: JourneyEvent) {
    const slug = String(event.meta?.product_slug || '');
    if (slug) return slug;
    const path = productPath(event);
    const parts = path.split('/').filter(Boolean);
    return parts[parts.length - 1] || 'produk';
}

function getMetaChips(type: string, meta?: Record<string, unknown>) {
    if (!meta || typeof meta !== 'object') return [];
    const chips: string[] = [];

    if (type === 'product_view' || type === 'add_to_cart' || type === 'remove_from_cart') {
        if (meta.product_slug) chips.push(String(meta.product_slug));
        else if (meta.product_id) chips.push(`id: ${meta.product_id}`);
        if (meta.qty != null) chips.push(`qty ${meta.qty}`);
        if (meta.source) chips.push(String(meta.source));
    } else if (type === 'purchase') {
        if (meta.order_id) chips.push(`order ${meta.order_id}`);
        if (meta.subtotal != null) chips.push(`Rp ${Number(meta.subtotal).toLocaleString('id-ID')}`);
    } else if (type === 'search') {
        if (meta.query) chips.push(`“${meta.query}”`);
        if (meta.result_count != null) chips.push(`${meta.result_count} hasil`);
    } else if (type === 'voucher_apply') {
        if (meta.code) chips.push(String(meta.code));
        if (meta.success === true) chips.push('berhasil');
        if (meta.success === false) chips.push(`gagal${meta.reason ? `: ${meta.reason}` : ''}`);
    } else if (type === 'wedding_preview_open') {
        if (meta.ring_type) chips.push(String(meta.ring_type));
        if (meta.font) chips.push(`font ${meta.font}`);
    } else if (type === 'begin_checkout') {
        if (meta.item_count != null) chips.push(`${meta.item_count} item`);
    } else {
        Object.entries(meta).forEach(([key, value]) => {
            if (HIDDEN_META_KEYS.has(key)) return;
            if (value == null || value === '') return;
            if (typeof value === 'object') return;
            chips.push(`${key}: ${value}`);
        });
    }

    return chips.slice(0, 4);
}

function buildTimelineNodes(events: JourneyEvent[]): TimelineNode[] {
    const nodes: TimelineNode[] = [];
    let i = 0;

    while (i < events.length) {
        const event = events[i];

        if (event.type === 'session_start') {
            nodes.push({
                kind: 'boundary',
                key: `boundary-${i}`,
                index: Number(event.meta?.session_index) || nodes.filter((n) => n.kind === 'boundary').length + 1,
                total: Number(event.meta?.session_total) || 1,
                at: event.at,
            });
            i += 1;
            continue;
        }

        if (isBrowseEvent(event.type)) {
            let j = i;
            const run: JourneyEvent[] = [];
            while (j < events.length && isBrowseEvent(events[j].type)) {
                run.push(events[j]);
                j += 1;
            }

            const pageViews = run.filter((e) => e.type === 'page_view');
            const productViews = run.filter((e) => e.type === 'product_view');

            if (pageViews.length >= 2) {
                nodes.push({
                    kind: 'page_group',
                    key: `page-group-${i}`,
                    events: pageViews,
                    startIndex: i,
                    productViews,
                });
            } else if (pageViews.length === 1) {
                nodes.push({
                    kind: 'event',
                    key: `event-${i}`,
                    event: pageViews[0],
                    sourceIndex: i,
                    productViews,
                });
            } else {
                productViews.forEach((pv, idx) => {
                    nodes.push({
                        kind: 'event',
                        key: `event-${i}-pv-${idx}`,
                        event: pv,
                        sourceIndex: i + idx,
                    });
                });
            }
            i = j;
            continue;
        }

        nodes.push({
            kind: 'event',
            key: `event-${i}`,
            event,
            sourceIndex: i,
        });
        i += 1;
    }

    return nodes;
}

function MetaChips({ type, meta }: { type: string; meta?: Record<string, unknown> }) {
    const chips = getMetaChips(type, meta);
    if (chips.length === 0) return null;
    return (
        <div className={styles.metaChips}>
            {chips.map((chip) => (
                <span key={chip} className={styles.metaChip}>
                    {chip}
                </span>
            ))}
        </div>
    );
}

function ProductViewChips({ productViews }: { productViews?: JourneyEvent[] }) {
    if (!productViews?.length) return null;
    const seen = new Set<string>();
    const labels = productViews
        .map((event) => productLabel(event))
        .filter((label) => {
            if (seen.has(label)) return false;
            seen.add(label);
            return true;
        });
    return (
        <div className={styles.metaChips}>
            {labels.map((label) => (
                <span key={label} className={styles.metaChip}>
                    Lihat produk · {label}
                </span>
            ))}
        </div>
    );
}

function EventRow({ event, productViews }: { event: JourneyEvent; productViews?: JourneyEvent[] }) {
    const isPageView = event.type === 'page_view';
    const path = event.path || '';
    const matched = (productViews || []).filter((pv) => pathsMatch(path, pv));

    return (
        <div className={styles.timelineItem}>
            <div className="flex items-start justify-between gap-3 mb-1">
                {isPageView ? (
                    <span className={styles.eventBadge}>{formatEventLabel(event.type)}</span>
                ) : (
                    <div className={styles.eventAction}>{formatEventLabel(event.type)}</div>
                )}
                <span className="text-xs text-gray-400 whitespace-nowrap">{formatTime(event.at)}</span>
            </div>
            {isPageView && path ? <div className={styles.eventPath}>{path}</div> : null}
            {!isPageView && path ? <div className={styles.eventPathSecondary}>{path}</div> : null}
            {isPageView ? <ProductViewChips productViews={matched.length ? matched : productViews} /> : null}
            {!isPageView ? <MetaChips type={event.type} meta={event.meta} /> : null}
        </div>
    );
}

function PageGroupRow({
    node,
    expanded,
    onToggle,
}: {
    node: Extract<TimelineNode, { kind: 'page_group' }>;
    expanded: boolean;
    onToggle: () => void;
}) {
    const count = node.events.length;
    const first = node.events[0];
    const last = node.events[count - 1];
    const productViews = node.productViews || [];

    return (
        <div className={`${styles.timelineItem} ${styles.timelineGroup}`}>
            <button type="button" className={styles.groupToggle} onClick={onToggle}>
                <span className={styles.eventBadge}>Page views</span>
                <span className={styles.groupCount}>+{count} page views</span>
                <span className="text-xs text-gray-400 whitespace-nowrap ml-auto">
                    {formatTimeRange(first.at, last.at)}
                </span>
                <span className={styles.groupChevron}>{expanded ? '▾' : '▸'}</span>
            </button>
            {!expanded ? (
                <>
                    <div className={styles.eventPathSecondary}>
                        {first.path || '/'}
                        {last.path && last.path !== first.path ? ` → ${last.path}` : ''}
                    </div>
                    <ProductViewChips productViews={productViews} />
                </>
            ) : (
                <div className={styles.groupList}>
                    {node.events.map((event, idx) => {
                        const matched = productViews.filter((pv) => pathsMatch(event.path || '', pv));
                        return (
                            <div key={`${node.key}-${idx}`} className={styles.groupListItem}>
                                <div>
                                    <div className={styles.eventPath}>{event.path || '/'}</div>
                                    <ProductViewChips productViews={matched} />
                                </div>
                                <div className="text-xs text-gray-400">{formatTime(event.at)}</div>
                            </div>
                        );
                    })}
                </div>
            )}
        </div>
    );
}

const SessionDetailDrawer = ({ open, loading, detail, onClose }: SessionDetailDrawerProps) => {
    const [expandedGroups, setExpandedGroups] = useState<Record<string, boolean>>({});

    useEffect(() => {
        if (!open) setExpandedGroups({});
    }, [open, detail?.id]);

    const nodes = useMemo(() => buildTimelineNodes(detail?.events || []), [detail?.events]);

    const funnelChips = useMemo(() => {
        if (!detail) return [];
        const chips: { label: string; active: boolean }[] = [
            { label: 'ATC', active: Boolean(detail.has_add_to_cart) },
            { label: 'Checkout', active: Boolean(detail.reached_checkout) },
            { label: 'Purchase', active: Boolean(detail.has_purchase) },
            { label: 'Auth', active: Boolean(detail.has_auth) },
        ];
        return chips;
    }, [detail]);

    return (
        <Transition appear show={open} as={Fragment}>
            <Dialog as="div" open={open} onClose={onClose} className="relative z-50">
                <Transition.Child
                    as={Fragment}
                    enter="ease-out duration-300"
                    enterFrom="opacity-0"
                    enterTo="opacity-100"
                    leave="ease-in duration-200"
                    leaveFrom="opacity-100"
                    leaveTo="opacity-0"
                >
                    <div className="fixed inset-0 bg-[black]/60" />
                </Transition.Child>
                <div className="fixed inset-0 overflow-y-auto">
                    <div className="flex min-h-full items-center justify-end p-0 text-center">
                        <Transition.Child
                            as={Fragment}
                            enter="ease-out duration-300"
                            enterFrom="opacity-0 translate-x-8"
                            enterTo="opacity-100 translate-x-0"
                            leave="ease-in duration-200"
                            leaveFrom="opacity-100 translate-x-0"
                            leaveTo="opacity-0 translate-x-8"
                        >
                            <Dialog.Panel className="w-full max-w-2xl min-h-screen overflow-y-auto bg-white p-6 text-left align-middle shadow-xl dark:bg-[#0e1726]">
                                <div className="flex items-start justify-between gap-3 mb-4">
                                    <div>
                                        <Dialog.Title as="h3" className="text-lg font-semibold">
                                            Visitor timeline
                                        </Dialog.Title>
                                        <p className="text-xs text-gray-500 font-mono mt-1">
                                            {detail?.visitor_id || detail?.session_id || '—'}
                                        </p>
                                        {detail?.session_count && detail.session_count > 1 ? (
                                            <p className="text-xs text-gray-500 mt-1">
                                                Digabung dari {detail.session_count} sessions
                                            </p>
                                        ) : null}
                                    </div>
                                    <button type="button" className="btn btn-outline-dark btn-sm" onClick={onClose}>
                                        Close
                                    </button>
                                </div>

                                {loading ? (
                                    <p className="text-sm text-gray-500">Loading...</p>
                                ) : !detail ? (
                                    <p className="text-sm text-gray-500">Session not found</p>
                                ) : (
                                    <>
                                        <div className="grid grid-cols-2 gap-3 text-sm mb-3">
                                            <div>
                                                <div className="text-gray-500 text-xs mb-1">User</div>
                                                {detail.user_id ? (
                                                    <div>
                                                        <div className="font-semibold">
                                                            {detail.user?.name || detail.user_name || 'User tidak ditemukan'}
                                                        </div>
                                                        <div className="text-xs text-gray-500 font-mono">
                                                            {detail.user_id}
                                                        </div>
                                                    </div>
                                                ) : (
                                                    <div className="text-sm text-gray-400">Guest</div>
                                                )}
                                            </div>
                                            <div>
                                                <div className="text-gray-500 text-xs mb-1">Entry → Exit</div>
                                                <div className="text-sm break-all">{detail.entry_page || '/'}</div>
                                                <div className="text-xs text-gray-500 break-all">→ {detail.exit_page || '/'}</div>
                                                <div className="mt-2">
                                                    <div className="text-gray-500 text-xs mb-1">Attribution</div>
                                                    <div className="text-xs text-gray-700">
                                                        Channel: <span className="font-semibold">{detail.entry_channel_group || '—'}</span>
                                                    </div>
                                                    <div className="text-[11px] text-gray-500 break-all">
                                                        UTM: source={detail.entry_utm_source || '—'} · medium={detail.entry_utm_medium || '—'} · campaign={detail.entry_utm_campaign || '—'}
                                                    </div>
                                                    <div className="text-xs text-gray-700 mt-1">
                                                        Kota: <span className="font-semibold">{detail.entry_city || '—'}</span>
                                                        {detail.entry_region || detail.entry_country ? (
                                                            <span className="text-gray-500">
                                                                {' '}
                                                                ({[detail.entry_region, detail.entry_country].filter(Boolean).join(', ')})
                                                            </span>
                                                        ) : null}
                                                    </div>
                                                </div>
                                            </div>
                                        </div>

                                        <div className={styles.funnelChips}>
                                            {funnelChips.map((chip) => (
                                                <span
                                                    key={chip.label}
                                                    className={`${styles.funnelChip} ${chip.active ? styles.funnelChipActive : styles.funnelChipInactive
                                                        }`}
                                                >
                                                    {chip.label}
                                                </span>
                                            ))}
                                        </div>

                                        <div className={styles.timeline}>
                                            {nodes.map((node) => {
                                                if (node.kind === 'boundary') {
                                                    return (
                                                        <div key={node.key} className={styles.timelineBoundary}>
                                                            <div className={styles.timelineBoundaryLabel}>
                                                                Session {node.index}/{node.total || detail.session_count || 1}
                                                            </div>
                                                            <div className="text-xs text-gray-500">{formatTime(node.at)}</div>
                                                        </div>
                                                    );
                                                }

                                                if (node.kind === 'page_group') {
                                                    return (
                                                        <PageGroupRow
                                                            key={node.key}
                                                            node={node}
                                                            expanded={Boolean(expandedGroups[node.key])}
                                                            onToggle={() =>
                                                                setExpandedGroups((prev) => ({
                                                                    ...prev,
                                                                    [node.key]: !prev[node.key],
                                                                }))
                                                            }
                                                        />
                                                    );
                                                }

                                                return (
                                                    <EventRow
                                                        key={node.key}
                                                        event={node.event}
                                                        productViews={node.productViews}
                                                    />
                                                );
                                            })}
                                            {nodes.length === 0 ? <p className="text-sm text-gray-500">No events</p> : null}
                                        </div>
                                    </>
                                )}
                            </Dialog.Panel>
                        </Transition.Child>
                    </div>
                </div>
            </Dialog>
        </Transition>
    );
};

export default SessionDetailDrawer;
