import dynamic from 'next/dynamic';
import { Fragment, useEffect, useMemo, useRef, useState } from 'react';
import { useSelector } from 'react-redux';
import type { ApexOptions } from 'apexcharts';

import type { DateRange } from '@/lib/abandoned-cart-stats-date';
import { IRootState } from '@/store';
import { journeyChartGrid } from './journey-chart-options';
import styles from './acquisition-table.module.css';
import KeyboardArrowRightOutlinedIcon from '@mui/icons-material/KeyboardArrowRightOutlined';
import KeyboardArrowDownOutlinedIcon from '@mui/icons-material/KeyboardArrowDownOutlined';

const ReactApexChart = dynamic(() => import('react-apexcharts'), { ssr: false });

export type ItemReportBreakdown = 'channel_group' | 'utm_source' | 'utm_medium' | 'utm_campaign' | 'source_medium';
export type ItemReportDimension = 'item_name' | 'item_category' | 'item_sku';

export type ItemReportRow = {
    item_key: string;
    item_label: string;
    breakdown_value?: string;
    channel?: string;
    utm_source?: string;
    utm_medium?: string;
    utm_campaign?: string;
    items_viewed: number | null;
    view_sessions: number | null;
    engaged_view_sessions: number | null;
    items_added_to_cart: number;
    direct_checkout_qty: number;
    items_purchased: number;
    item_revenue: number;
    engagement_rate_percent: number | null;
    views_by_day?: number[];
};

export type ItemReportDimensionBlock = {
    rows: ItemReportRow[];
    rows_by_breakdown: Record<ItemReportBreakdown, ItemReportRow[]>;
    rows_by_attribution?: ItemReportRow[];
    trend: {
        days: string[];
        series: { name: string; data: number[] }[];
    };
    scatter: { name: string; items_viewed: number; items_added_to_cart: number }[];
};

export type ItemReportPayload = {
    by_dimension: Record<ItemReportDimension, ItemReportDimensionBlock>;
};

const PRIMARY_OPTIONS: { id: ItemReportDimension; label: string }[] = [
    { id: 'item_name', label: 'Item name' },
    { id: 'item_category', label: 'Item category' },
    { id: 'item_sku', label: 'Item ID (SKU)' },
];

const CHANNEL_FILTER_OPTIONS = [
    'Direct',
    'Paid Social',
    'Paid Search',
    'Organic Search',
    'Organic Social',
    'Referral',
    'Email',
    'Display',
    'Affiliate',
    'Other',
    'Unassigned',
];

export type ItemAttributionFilters = {
    channel_group: string;
    utm_source: string;
    utm_medium: string;
    utm_campaign: string;
};

const EMPTY_ITEM_FILTERS: ItemAttributionFilters = {
    channel_group: '',
    utm_source: '',
    utm_medium: '',
    utm_campaign: '',
};

const PAGE_SIZES = [10, 25, 50, 100];
const CHART_COLORS = ['#4285f4', '#1a73e8', '#e37400', '#0d904f', '#ab47bc', '#f9ab00', '#d93025', '#12b5cb', '#9334e6', '#e52592'];

type SortKey =
    | 'item_label'
    | 'channel'
    | 'utm_source'
    | 'utm_medium'
    | 'utm_campaign'
    | 'items_viewed'
    | 'view_sessions'
    | 'items_added_to_cart'
    | 'direct_checkout_qty'
    | 'items_purchased'
    | 'item_revenue'
    | 'engagement_rate_percent';

type MetricKey = Exclude<SortKey, 'item_label' | 'channel' | 'utm_source' | 'utm_medium' | 'utm_campaign'>;

const METRICS: { id: MetricKey; label: string; kind: 'count' | 'money' | 'rate' }[] = [
    { id: 'items_viewed', label: 'Items viewed', kind: 'count' },
    { id: 'view_sessions', label: 'View sessions', kind: 'count' },
    { id: 'items_added_to_cart', label: 'Items added to cart', kind: 'count' },
    { id: 'direct_checkout_qty', label: 'Direct checkout', kind: 'count' },
    { id: 'items_purchased', label: 'Items purchased', kind: 'count' },
    { id: 'item_revenue', label: 'Item revenue', kind: 'money' },
    { id: 'engagement_rate_percent', label: 'Engagement rate', kind: 'rate' },
];

function dimensionLabel(id: ItemReportDimension) {
    return PRIMARY_OPTIONS.find((option) => option.id === id)?.label || 'Item name';
}

function formatInt(value: number) {
    return value.toLocaleString('id-ID');
}

function formatPct(value: number) {
    return `${value.toLocaleString('id-ID', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}%`;
}

function formatRp(value: number) {
    return `Rp${value.toLocaleString('id-ID')}`;
}

function displayItemLabel(label: string, dimension: ItemReportDimension) {
    const text = String(label || '').trim();
    if (!text || dimension === 'item_sku') return text;
    if (/\s/.test(text) || !text.includes('-') || !/^[a-z0-9-]+$/.test(text)) return text;
    const words = text.replace(/-/g, ' ').replace(/\s+/g, ' ').trim();
    return words.charAt(0).toUpperCase() + words.slice(1);
}

function formatDay(iso: string) {
    const date = new Date(`${iso}T00:00:00Z`);
    if (Number.isNaN(date.getTime())) return iso;
    return date.toLocaleDateString('id-ID', { day: 'numeric', month: 'short', timeZone: 'UTC' });
}

function wordCount(label: string) {
    return label.split(/\s+/).filter(Boolean).length;
}

function scatterPointLabel(label: string) {
    return wordCount(label) > 3 ? '' : label;
}

function crowdedScatterIndexes(points: { items_viewed: number; items_added_to_cart: number }[]) {
    const crowded = new Set<number>();
    if (points.length < 2) return crowded;
    const maxX = Math.max(...points.map((point) => point.items_viewed), 1);
    const maxY = Math.max(...points.map((point) => point.items_added_to_cart), 1);
    const norm = points.map((point) => ({
        x: point.items_viewed / maxX,
        y: point.items_added_to_cart / maxY,
    }));
    for (let i = 0; i < norm.length; i += 1) {
        for (let j = i + 1; j < norm.length; j += 1) {
            const dx = norm[i].x - norm[j].x;
            const dy = norm[i].y - norm[j].y;
            if (Math.hypot(dx, dy) < 0.08) {
                crowded.add(i);
                crowded.add(j);
            }
        }
    }
    return crowded;
}

function escapeHtml(value: string) {
    return value
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;');
}

function formatTooltipRange(range?: DateRange | null) {
    if (!range?.from || !range?.to) return '';
    const from = new Date(`${range.from}T00:00:00Z`);
    const to = new Date(`${range.to}T00:00:00Z`);
    if (Number.isNaN(from.getTime()) || Number.isNaN(to.getTime())) return '';
    const monthDay = (date: Date) => date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', timeZone: 'UTC' });
    const full = (date: Date) => date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric', timeZone: 'UTC' });
    if (range.from === range.to) return full(from);
    if (from.getUTCFullYear() === to.getUTCFullYear()) return `${monthDay(from)} - ${full(to)}`;
    return `${full(from)} - ${full(to)}`;
}

function compactNumber(value: number) {
    const abs = Math.abs(value);
    if (abs >= 1_000_000) {
        const scaled = value / 1_000_000;
        const text = scaled >= 10 ? String(Math.round(scaled)) : scaled.toFixed(1).replace(/\.0$/, '');
        return `${text}M`;
    }
    if (abs >= 1000) return `${Math.round(value / 1000)}K`;
    return String(Math.round(value));
}

function numericValue(row: ItemReportRow, key: MetricKey) {
    const value = row[key];
    return value == null ? null : Number(value);
}

type ItemGroup = {
    key: string;
    summary: ItemReportRow;
    details: ItemReportRow[];
};

function summarizeDetails(details: ItemReportRow[]): ItemReportRow {
    const first = details[0];
    const viewsKnown = details.some((row) => row.items_viewed != null);
    const sum = (key: MetricKey) => details.reduce((acc, row) => acc + (numericValue(row, key) || 0), 0);
    const viewSessions = sum('view_sessions');
    const engaged = details.reduce((acc, row) => acc + (Number(row.engaged_view_sessions) || 0), 0);
    return {
        item_key: first.item_key,
        item_label: first.item_label,
        items_viewed: viewsKnown ? sum('items_viewed') : null,
        view_sessions: viewsKnown ? viewSessions : null,
        engaged_view_sessions: viewsKnown ? engaged : null,
        items_added_to_cart: sum('items_added_to_cart'),
        direct_checkout_qty: sum('direct_checkout_qty'),
        items_purchased: sum('items_purchased'),
        item_revenue: sum('item_revenue'),
        engagement_rate_percent: viewSessions ? (engaged / viewSessions) * 100 : null,
        views_by_day: first.views_by_day,
    };
}

function HeaderMenu({
    label,
    options,
    onSelect,
    onRemove,
}: {
    label: string;
    options: { id: string; label: string }[];
    onSelect: (id: string) => void;
    onRemove?: () => void;
}) {
    const [open, setOpen] = useState(false);
    const rootRef = useRef<HTMLDivElement>(null);

    useEffect(() => {
        if (!open) return undefined;
        const onPointer = (event: MouseEvent) => {
            if (!rootRef.current?.contains(event.target as Node)) setOpen(false);
        };
        document.addEventListener('mousedown', onPointer);
        return () => document.removeEventListener('mousedown', onPointer);
    }, [open]);

    return (
        <div className={styles.eventCountHeader} style={{ justifyContent: 'flex-start', width: 'auto' }} ref={rootRef}>
            <button
                type="button"
                className={styles.eventCountHeaderBtn}
                onClick={() => setOpen((current) => !current)}
            >
                <span className="truncate">{label}</span>
                <span className={styles.eventCountChevron}>▼</span>
            </button>
            {onRemove ? (
                <button
                    type="button"
                    className="ml-1 border-0 bg-transparent text-base leading-none text-gray-500"
                    aria-label="Hapus dimensi"
                    onClick={onRemove}
                >
                    ×
                </button>
            ) : null}
            {open ? (
                <div className={styles.eventCountMenu} style={{ left: 0, right: 'auto', zIndex: 5 }}>
                    {options.map((option) => (
                        <button
                            key={option.id}
                            type="button"
                            className={`${styles.eventCountOption} ${option.label === label ? styles.eventCountOptionActive : ''}`}
                            onClick={() => {
                                onSelect(option.id);
                                setOpen(false);
                            }}
                        >
                            {option.label}
                        </button>
                    ))}
                </div>
            ) : null}
        </div>
    );
}

function AttributionDetailRows({
    open,
    details,
    groupKey,
    label,
    totals,
}: {
    open: boolean;
    details: ItemReportRow[];
    groupKey: string;
    label: string;
    totals: Record<MetricKey, number | null>;
}) {
    const [mounted, setMounted] = useState(open);
    const [visible, setVisible] = useState(false);

    useEffect(() => {
        if (open) {
            setMounted(true);
            const frame = requestAnimationFrame(() => {
                requestAnimationFrame(() => setVisible(true));
            });
            return () => cancelAnimationFrame(frame);
        }
        setVisible(false);
        const timer = window.setTimeout(() => setMounted(false), 300);
        return () => window.clearTimeout(timer);
    }, [open]);

    if (!mounted) return null;

    const revealClass = `${styles.detailReveal} ${visible ? styles.detailRevealOpen : styles.detailRevealClosed}`;

    return (
        <>
            {details.map((row) => (
                <tr
                    key={`${groupKey}-${row.channel || ''}-${row.utm_source || ''}-${row.utm_medium || ''}-${row.utm_campaign || ''}`}
                    className={`${styles.tr} ${styles.trDetail}`}
                >
                    {(
                        [
                            '',
                            label || '—',
                            row.channel || row.breakdown_value || '—',
                            row.utm_source || '—',
                            row.utm_medium || '—',
                            row.utm_campaign || '—',
                        ] as const
                    ).map((text, cellIndex) => (
                        <td
                            key={cellIndex}
                            className={
                                cellIndex === 0
                                    ? styles.td
                                    : cellIndex === 1
                                        ? `${styles.td} ${styles.tdDimension} ${styles.tdFrozen}`
                                        : `${styles.td} ${styles.tdDimension} ${styles.tdAttr}`
                            }
                            title={cellIndex === 0 ? undefined : text}
                        >
                            <div className={revealClass}>
                                <div className={`${styles.detailRevealInner} ${cellIndex === 1 ? 'pl-6' : ''}`}>{text}</div>
                            </div>
                        </td>
                    ))}
                    {METRICS.map((metric) => {
                        const value = numericValue(row, metric.id);
                        const total = totals[metric.id];
                        return (
                            <td key={metric.id} className={`${styles.td} ${styles.tdMetric}`}>
                                <div className={revealClass}>
                                    <div className={styles.detailRevealInner}>
                                        {metric.kind === 'rate' ? (
                                            <span className={styles.metricValue}>{value == null ? '—' : formatPct(value)}</span>
                                        ) : (
                                            <CountCell value={value} total={total == null ? 0 : total} money={metric.kind === 'money'} />
                                        )}
                                    </div>
                                </div>
                            </td>
                        );
                    })}
                </tr>
            ))}
        </>
    );
}

function CountCell({ value, total, money = false }: { value: number | null; total: number; money?: boolean }) {
    if (value == null) return <span className={styles.metricValue}>—</span>;
    const share = total > 0 ? (value / total) * 100 : 0;
    return (
        <div className={styles.metricCell}>
            <span className={styles.metricValue}>{money ? formatRp(value) : formatInt(value)}</span>
            <span className={styles.metricPct}>{formatPct(share)}</span>
        </div>
    );
}

const AddToCartItemReport = ({
    report,
    dateRange = null,
    attributionFilters = EMPTY_ITEM_FILTERS,
    onAttributionFiltersChange,
}: {
    report?: ItemReportPayload | null;
    dateRange?: DateRange | null;
    attributionFilters?: ItemAttributionFilters;
    onAttributionFiltersChange?: (filters: ItemAttributionFilters) => void;
}) => {
    const isDark = useSelector(
        (state: IRootState) => state.themeConfig.theme === 'dark' || state.themeConfig.isDarkMode
    );
    const [primary, setPrimary] = useState<ItemReportDimension>('item_name');
    const [search, setSearch] = useState('');
    const [sourceInput, setSourceInput] = useState(attributionFilters.utm_source);
    const [mediumInput, setMediumInput] = useState(attributionFilters.utm_medium);
    const [campaignInput, setCampaignInput] = useState(attributionFilters.utm_campaign);
    const [page, setPage] = useState(1);
    const [pageSize, setPageSize] = useState(10);
    const [goTo, setGoTo] = useState('1');
    const [sortKey, setSortKey] = useState<SortKey>('items_viewed');
    const [sortDir, setSortDir] = useState<'asc' | 'desc'>('desc');
    const [expandedKeys, setExpandedKeys] = useState<Set<string>>(new Set());
    const filtersRef = useRef(attributionFilters);
    filtersRef.current = attributionFilters;

    useEffect(() => {
        setSourceInput(attributionFilters.utm_source);
        setMediumInput(attributionFilters.utm_medium);
        setCampaignInput(attributionFilters.utm_campaign);
    }, [attributionFilters.utm_source, attributionFilters.utm_medium, attributionFilters.utm_campaign]);

    useEffect(() => {
        const timer = window.setTimeout(() => {
            const current = filtersRef.current;
            const nextSource = sourceInput.trim();
            const nextMedium = mediumInput.trim();
            const nextCampaign = campaignInput.trim();
            if (
                nextSource === current.utm_source &&
                nextMedium === current.utm_medium &&
                nextCampaign === current.utm_campaign
            ) {
                return;
            }
            onAttributionFiltersChange?.({
                ...current,
                utm_source: nextSource,
                utm_medium: nextMedium,
                utm_campaign: nextCampaign,
            });
        }, 350);
        return () => window.clearTimeout(timer);
    }, [sourceInput, mediumInput, campaignInput, onAttributionFiltersChange]);

    const block = report?.by_dimension?.[primary];
    const itemRows = block?.rows || [];
    const sourceRows = block?.rows_by_attribution?.length
        ? block.rows_by_attribution
        : block?.rows_by_breakdown?.channel_group?.length
            ? block.rows_by_breakdown.channel_group
            : itemRows;

    const filteredRows = useMemo(() => {
        const needle = search.trim().toLowerCase();
        const rows = needle
            ? sourceRows.filter((row) => {
                const label = displayItemLabel(row.item_label, primary).toLowerCase();
                const raw = String(row.item_label || '').toLowerCase();
                const channel = String(row.channel || row.breakdown_value || '').toLowerCase();
                const source = String(row.utm_source || '').toLowerCase();
                const medium = String(row.utm_medium || '').toLowerCase();
                const campaign = String(row.utm_campaign || '').toLowerCase();
                return label.includes(needle) || raw.includes(needle) || channel.includes(needle) || source.includes(needle) || medium.includes(needle) || campaign.includes(needle);
            })
            : sourceRows.slice();
        const textOf = (row: ItemReportRow) => {
            if (sortKey === 'item_label') return displayItemLabel(row.item_label, primary);
            if (sortKey === 'channel') return String(row.channel || row.breakdown_value || '');
            if (sortKey === 'utm_source' || sortKey === 'utm_medium' || sortKey === 'utm_campaign') {
                return String(row[sortKey] || '');
            }
            return '';
        };
        const metricOf = (row: ItemReportRow) => numericValue(row, sortKey as MetricKey);
        const compareRows = (a: ItemReportRow, b: ItemReportRow) => {
            const dir = sortDir === 'asc' ? 1 : -1;
            if (sortKey === 'item_label' || sortKey === 'channel' || sortKey === 'utm_source' || sortKey === 'utm_medium' || sortKey === 'utm_campaign') {
                const byText = textOf(a).localeCompare(textOf(b));
                if (byText !== 0) return byText * dir;
            } else {
                const av = metricOf(a);
                const bv = metricOf(b);
                if (av == null && bv != null) return 1;
                if (bv == null && av != null) return -1;
                if (av != null && bv != null && av !== bv) return (av - bv) * dir;
            }
            return displayItemLabel(a.item_label, primary).localeCompare(displayItemLabel(b.item_label, primary));
        };
        const groups = new Map<string, ItemReportRow[]>();
        rows.forEach((row) => {
            const key = row.item_key || displayItemLabel(row.item_label, primary);
            const list = groups.get(key);
            if (list) list.push(row);
            else groups.set(key, [row]);
        });
        const groupScore = (list: ItemReportRow[]) => {
            if (sortKey === 'engagement_rate_percent') {
                const sessions = list.reduce((sum, row) => sum + (numericValue(row, 'view_sessions') || 0), 0);
                const engaged = list.reduce((sum, row) => sum + (Number(row.engaged_view_sessions) || 0), 0);
                return sessions ? (engaged / sessions) * 100 : null;
            }
            if (sortKey === 'item_label' || sortKey === 'channel' || sortKey === 'utm_source' || sortKey === 'utm_medium' || sortKey === 'utm_campaign') {
                return list.reduce((sum, row) => sum + (numericValue(row, 'items_viewed') || 0), 0);
            }
            const values = list.map((row) => metricOf(row)).filter((value): value is number => value != null);
            if (!values.length) return null;
            return values.reduce((sum, value) => sum + value, 0);
        };
        const ordered = [...groups.values()];
        ordered.sort((a, b) => {
            const dir = sortDir === 'asc' ? 1 : -1;
            if (sortKey === 'item_label') {
                return displayItemLabel(a[0].item_label, primary).localeCompare(displayItemLabel(b[0].item_label, primary)) * dir;
            }
            const av = groupScore(a);
            const bv = groupScore(b);
            if (av == null && bv != null) return 1;
            if (bv == null && av != null) return -1;
            if (av != null && bv != null && av !== bv) return (av - bv) * dir;
            return displayItemLabel(a[0].item_label, primary).localeCompare(displayItemLabel(b[0].item_label, primary));
        });
        ordered.forEach((list) => list.sort(compareRows));
        return ordered.map((list) => ({
            key: list[0].item_key || displayItemLabel(list[0].item_label, primary),
            summary: summarizeDetails(list),
            details: list,
        }));
    }, [primary, search, sortDir, sortKey, sourceRows]);

    const pageCount = Math.max(1, Math.ceil(filteredRows.length / pageSize));
    const safePage = Math.min(page, pageCount);
    const pageRows = filteredRows.slice((safePage - 1) * pageSize, safePage * pageSize);
    const rangeStart = filteredRows.length ? (safePage - 1) * pageSize + 1 : 0;
    const rangeEnd = Math.min(safePage * pageSize, filteredRows.length);

    const totals = useMemo(() => {
        const sum = (key: MetricKey) =>
            filteredRows.reduce((acc, group) => {
                const value = numericValue(group.summary, key);
                return acc + (value == null ? 0 : value);
            }, 0);
        const viewSessions = sum('view_sessions');
        const engaged = filteredRows.reduce((acc, group) => acc + (Number(group.summary.engaged_view_sessions) || 0), 0);
        const viewsKnown = filteredRows.some((group) => group.summary.items_viewed != null);
        return {
            items_viewed: viewsKnown ? sum('items_viewed') : null,
            view_sessions: viewsKnown ? viewSessions : null,
            items_added_to_cart: sum('items_added_to_cart'),
            direct_checkout_qty: sum('direct_checkout_qty'),
            items_purchased: sum('items_purchased'),
            item_revenue: sum('item_revenue'),
            engagement_rate_percent: viewSessions ? (engaged / viewSessions) * 100 : null,
        };
    }, [filteredRows]);

    useEffect(() => {
        setPage(1);
        setGoTo('1');
    }, [primary, search, pageSize, sortKey, sortDir, attributionFilters.channel_group, attributionFilters.utm_source, attributionFilters.utm_medium, attributionFilters.utm_campaign]);

    const toggleSort = (key: SortKey) => {
        if (sortKey === key) {
            setSortDir((dir) => (dir === 'asc' ? 'desc' : 'asc'));
            return;
        }
        setSortKey(key);
        setSortDir(key === 'item_label' || key === 'channel' || key === 'utm_source' || key === 'utm_medium' || key === 'utm_campaign' ? 'asc' : 'desc');
    };

    const sortMark = (key: SortKey) => (sortKey === key ? (sortDir === 'asc' ? '▲' : '▼') : '');

    const toggleExpanded = (key: string) => {
        setExpandedKeys((current) => {
            const next = new Set(current);
            if (next.has(key)) next.delete(key);
            else next.add(key);
            return next;
        });
    };

    const renderMetrics = (row: ItemReportRow) =>
        METRICS.map((metric) => {
            if (metric.kind === 'rate') {
                const value = numericValue(row, metric.id);
                return (
                    <td key={metric.id} className={`${styles.td} ${styles.tdMetric}`}>
                        <span className={styles.metricValue}>{value == null ? '—' : formatPct(value)}</span>
                    </td>
                );
            }
            const total = totals[metric.id];
            return (
                <td key={metric.id} className={`${styles.td} ${styles.tdMetric}`}>
                    <CountCell value={numericValue(row, metric.id)} total={total == null ? 0 : total} money={metric.kind === 'money'} />
                </td>
            );
        });

    const applyGoTo = () => {
        const next = Number(goTo);
        if (!Number.isFinite(next)) {
            setGoTo(String(safePage));
            return;
        }
        const clamped = Math.min(pageCount, Math.max(1, Math.round(next)));
        setPage(clamped);
        setGoTo(String(clamped));
    };

    const activeDimensionLabel = dimensionLabel(primary);
    const trend = block?.trend;
    const scatter = block?.scatter || [];
    const chartRows = useMemo(() => {
        const needle = search.trim().toLowerCase();
        if (!needle) return itemRows;
        return itemRows.filter((row) => {
            const label = displayItemLabel(row.item_label, primary).toLowerCase();
            const raw = String(row.item_label || '').toLowerCase();
            return label.includes(needle) || raw.includes(needle);
        });
    }, [itemRows, primary, search]);

    const areaSeries = useMemo(() => {
        const withDays = chartRows.filter(
            (row) => row.items_viewed != null && Array.isArray(row.views_by_day) && row.views_by_day.length
        );
        if (!withDays.length) {
            return (trend?.series || []).slice(0, 6).map((series) => ({
                name: series.name === 'Total' ? 'Total' : displayItemLabel(series.name, primary),
                data: series.data || [],
            }));
        }
        const dayCount = withDays[0].views_by_day?.length || 0;
        const total = Array.from({ length: dayCount }, (_, index) =>
            withDays.reduce((sum, row) => sum + (row.views_by_day?.[index] || 0), 0)
        );
        const top = [...withDays]
            .filter((row) => (row.items_viewed || 0) > 0)
            .sort((a, b) => {
                const delta = (b.items_viewed || 0) - (a.items_viewed || 0);
                if (delta !== 0) return delta;
                return displayItemLabel(a.item_label, primary).localeCompare(displayItemLabel(b.item_label, primary));
            })
            .slice(0, 5);
        const used = new Set<string>(['Total']);
        return [
            { name: 'Total', data: total },
            ...top.map((row) => {
                const base = displayItemLabel(row.item_label, primary) || '—';
                let name = base;
                let suffix = 2;
                while (used.has(name)) {
                    name = `${base} (${suffix})`;
                    suffix += 1;
                }
                used.add(name);
                return { name, data: row.views_by_day || [] };
            }),
        ];
    }, [chartRows, primary, trend]);
    const categories = useMemo(() => (trend?.days || []).map(formatDay), [trend]);

    const areaOptions = useMemo<ApexOptions>(() => ({
        chart: {
            type: 'area',
            fontFamily: 'Nunito, sans-serif',
            toolbar: { show: false },
            zoom: { enabled: false },
        },
        colors: CHART_COLORS,
        dataLabels: { enabled: false },
        stroke: { curve: 'smooth', width: 2 },
        fill: {
            type: 'solid',
            opacity: areaSeries.map((_, index) => (index === 0 ? 0.28 : 0)),
        },
        xaxis: {
            categories,
            labels: { style: { fontSize: '11px' }, rotate: 0 },
            tooltip: { enabled: false },
        },
        yaxis: {
            labels: {
                style: { fontSize: '11px' },
                formatter: (value) => compactNumber(Number(value) || 0),
            },
        },
        grid: journeyChartGrid(isDark),
        legend: { position: 'bottom', fontSize: '12px' },
        tooltip: {
            shared: true,
            y: {
                formatter: (value) => formatInt(Number(value) || 0),
            },
        },
    }), [areaSeries, categories, isDark]);

    const crowdedPoints = useMemo(() => crowdedScatterIndexes(scatter), [scatter]);

    const scatterOptions = useMemo<ApexOptions>(() => ({
        chart: {
            type: 'scatter',
            fontFamily: 'Nunito, sans-serif',
            toolbar: { show: false },
            zoom: { enabled: false },
        },
        colors: ['#1a73e8'],
        markers: { size: 7 },
        dataLabels: {
            enabled: true,
            textAnchor: 'start',
            offsetX: 10,
            offsetY: 0,
            background: { enabled: false },
            dropShadow: { enabled: false },
            style: { fontSize: '11px', colors: [isDark ? '#e2e8f0' : '#5f6368'] },
            formatter: (_value, opts) => {
                const index = opts?.dataPointIndex ?? 0;
                if (crowdedPoints.has(index)) return '';
                const name = displayItemLabel(scatter[index]?.name || '', primary);
                return scatterPointLabel(name);
            },
        },
        xaxis: {
            title: { text: 'ITEMS VIEWED', style: { fontSize: '11px', fontWeight: 600 } },
            tickAmount: 4,
            labels: {
                formatter: (value) => compactNumber(Number(value) || 0),
                style: { fontSize: '11px' },
            },
            tooltip: { enabled: false },
        },
        yaxis: {
            title: { text: 'ITEMS ADDED TO CART', style: { fontSize: '11px', fontWeight: 600 } },
            labels: {
                formatter: (value) => compactNumber(Number(value) || 0),
                style: { fontSize: '11px' },
            },
        },
        grid: journeyChartGrid(isDark),
        legend: { show: false },
        tooltip: {
            custom: ({ dataPointIndex }) => {
                const point = scatter[dataPointIndex];
                if (!point) return '';
                const group = scatter
                    .filter((other) => other.items_viewed === point.items_viewed)
                    .sort((a, b) => b.items_added_to_cart - a.items_added_to_cart);
                const rangeLabel = formatTooltipRange(dateRange);
                const bg = isDark ? '#0e1726' : '#fff';
                const text = isDark ? '#e2e8f0' : '#202124';
                const muted = isDark ? '#94a3b8' : '#5f6368';
                const border = isDark ? '#334155' : '#dadce0';
                const itemCards = group
                    .map((other) => {
                        const name = displayItemLabel(other.name, primary) || '—';
                        return `
                            <div style="padding:6px 0;border-top:1px solid ${border};">
                                <div style="font-weight:700;">${escapeHtml(name)}</div>
                                <div style="display:flex;justify-content:space-between;gap:16px;margin-top:2px;">
                                    <span>Items added to cart</span>
                                    <strong>${formatInt(other.items_added_to_cart)}</strong>
                                </div>
                            </div>
                        `;
                    })
                    .join('');
                const listStyle =
                    group.length > 3
                        ? 'max-height:132px;margin-top:8px;overflow-y:auto;padding-right:4px;'
                        : 'margin-top:8px;';
                return `
                    <div style="min-width:220px;max-width:280px;padding:10px 12px;background:${bg};color:${text};border:1px solid ${border};border-radius:8px;box-shadow:0 4px 16px rgb(60 64 67 / 18%);font-size:12px;line-height:1.4;">
                        ${rangeLabel ? `<div style="margin-bottom:6px;color:${muted};">${escapeHtml(rangeLabel)}</div>` : ''}
                        <div style="display:flex;justify-content:space-between;gap:16px;">
                            <span>Items viewed</span>
                            <strong>${formatInt(point.items_viewed)}</strong>
                        </div>
                        <div style="${listStyle}">${itemCards}</div>
                    </div>
                `;
            },
        },
    }), [crowdedPoints, dateRange, isDark, primary, scatter]);

    const scatterSeries = [
        {
            name: 'Items',
            data: scatter.map((point) => ({ x: point.items_viewed, y: point.items_added_to_cart })),
        },
    ];

    return (
        <div className="space-y-4">
            <div className="grid grid-cols-1 gap-4 xl:grid-cols-2">
                <div className="min-w-0">
                    <h4 className="mb-2 text-sm font-semibold text-[#202124] dark:text-white">
                        Items viewed by {activeDimensionLabel} over time
                    </h4>
                    {areaSeries.length ? (
                        <ReactApexChart options={areaOptions} series={areaSeries} type="area" height={320} />
                    ) : (
                        <p className="py-16 text-center text-sm text-gray-400">Belum ada items viewed pada rentang ini.</p>
                    )}
                </div>
                <div className="min-w-0">
                    <h4 className="mb-2 text-sm font-semibold text-[#202124] dark:text-white">
                        Items viewed and Items added to cart by {activeDimensionLabel}
                    </h4>
                    {scatter.length ? (
                        <ReactApexChart options={scatterOptions} series={scatterSeries} type="scatter" height={320} />
                    ) : (
                        <p className="py-16 text-center text-sm text-gray-400">Belum ada titik untuk scatter.</p>
                    )}
                </div>
            </div>

            <div
                className={styles.wrapper}
                style={{
                    ['--acq-dimension-width' as string]: '220px',
                    ['--acq-metric-width' as string]: '118px',
                }}
            >
                <div className={styles.toolbar}>
                    <div className={styles.toolbarLeft}>
                        <input
                            className={styles.search}
                            placeholder="Search..."
                            value={search}
                            onChange={(event) => setSearch(event.target.value)}
                        />
                        {onAttributionFiltersChange ? (
                            <>
                                <select
                                    className={styles.select}
                                    style={{ minWidth: 160 }}
                                    value={attributionFilters.channel_group}
                                    onChange={(event) =>
                                        onAttributionFiltersChange({
                                            channel_group: event.target.value,
                                            utm_source: sourceInput.trim(),
                                            utm_medium: mediumInput.trim(),
                                            utm_campaign: campaignInput.trim(),
                                        })
                                    }
                                >
                                    <option value="">Semua channel</option>
                                    {CHANNEL_FILTER_OPTIONS.map((channel) => (
                                        <option key={channel} value={channel}>
                                            {channel}
                                        </option>
                                    ))}
                                </select>
                                <input
                                    className={styles.search}
                                    style={{ minWidth: 140, width: 140 }}
                                    placeholder="Source"
                                    value={sourceInput}
                                    onChange={(event) => setSourceInput(event.target.value)}
                                />
                                <input
                                    className={styles.search}
                                    style={{ minWidth: 140, width: 140 }}
                                    placeholder="Medium"
                                    value={mediumInput}
                                    onChange={(event) => setMediumInput(event.target.value)}
                                />
                                <input
                                    className={styles.search}
                                    style={{ minWidth: 160, width: 160 }}
                                    placeholder="Campaign"
                                    value={campaignInput}
                                    onChange={(event) => setCampaignInput(event.target.value)}
                                />
                                {attributionFilters.channel_group || sourceInput || mediumInput || campaignInput ? (
                                    <button
                                        type="button"
                                        className={styles.iconBtn}
                                        onClick={() => {
                                            setSourceInput('');
                                            setMediumInput('');
                                            setCampaignInput('');
                                            onAttributionFiltersChange(EMPTY_ITEM_FILTERS);
                                        }}
                                    >
                                        Reset
                                    </button>
                                ) : null}
                            </>
                        ) : null}
                    </div>
                    <div className={styles.toolbarRight}>
                        <span className={styles.fieldLabel}>Rows per page:</span>
                        <select
                            className={styles.select}
                            value={pageSize}
                            onChange={(event) => setPageSize(Number(event.target.value))}
                        >
                            {PAGE_SIZES.map((size) => (
                                <option key={size} value={size}>
                                    {size}
                                </option>
                            ))}
                        </select>
                        <span className={styles.fieldLabel}>Go to:</span>
                        <input
                            className={styles.search}
                            style={{ minWidth: 56, width: 56 }}
                            value={goTo}
                            inputMode="numeric"
                            onChange={(event) => setGoTo(event.target.value)}
                            onBlur={applyGoTo}
                            onKeyDown={(event) => {
                                if (event.key === 'Enter') applyGoTo();
                            }}
                        />
                        <button
                            type="button"
                            className={styles.pageBtn}
                            disabled={safePage <= 1}
                            onClick={() => {
                                const next = Math.max(1, safePage - 1);
                                setPage(next);
                                setGoTo(String(next));
                            }}
                        >
                            ‹
                        </button>
                        <span className={styles.fieldLabel}>
                            {rangeStart}–{rangeEnd} of {filteredRows.length}
                        </span>
                        <button
                            type="button"
                            className={styles.pageBtn}
                            disabled={safePage >= pageCount}
                            onClick={() => {
                                const next = Math.min(pageCount, safePage + 1);
                                setPage(next);
                                setGoTo(String(next));
                            }}
                        >
                            ›
                        </button>
                    </div>
                </div>

                <div className={styles.tableScroll}>
                    <table className={styles.table}>
                        <thead className={styles.thead} style={{ zIndex: 3 }}>
                            <tr>
                                <th className={styles.th} style={{ width: 36 }}>#</th>
                                <th
                                    className={`${styles.th} ${styles.thDimension} ${styles.thFrozen}`}
                                    style={{ overflow: 'visible', zIndex: 4 }}
                                >
                                    <HeaderMenu
                                        label={activeDimensionLabel}
                                        options={PRIMARY_OPTIONS}
                                        onSelect={(id) => setPrimary(id as ItemReportDimension)}
                                    />
                                </th>
                                <th
                                    className={`${styles.th} ${styles.thDimension} ${styles.thAttr}`}
                                    onClick={() => toggleSort('channel')}
                                >
                                    Channel
                                    <span className={styles.sortIcon}>{sortMark('channel')}</span>
                                </th>
                                <th
                                    className={`${styles.th} ${styles.thDimension} ${styles.thAttr}`}
                                    onClick={() => toggleSort('utm_source')}
                                >
                                    Source
                                    <span className={styles.sortIcon}>{sortMark('utm_source')}</span>
                                </th>
                                <th
                                    className={`${styles.th} ${styles.thDimension} ${styles.thAttr}`}
                                    onClick={() => toggleSort('utm_medium')}
                                >
                                    Medium
                                    <span className={styles.sortIcon}>{sortMark('utm_medium')}</span>
                                </th>
                                <th
                                    className={`${styles.th} ${styles.thDimension} ${styles.thAttr}`}
                                    onClick={() => toggleSort('utm_campaign')}
                                >
                                    Campaign
                                    <span className={styles.sortIcon}>{sortMark('utm_campaign')}</span>
                                </th>
                                {METRICS.map((metric) => (
                                    <th
                                        key={metric.id}
                                        className={`${styles.th} ${styles.thMetric}`}
                                        onClick={() => toggleSort(metric.id)}
                                    >
                                        {metric.label}
                                        <span className={styles.sortIcon}>{sortMark(metric.id)}</span>
                                    </th>
                                ))}
                            </tr>
                        </thead>
                        <tbody>
                            <tr className={styles.trTotal}>
                                <td className={styles.td} />
                                <td className={`${styles.td} ${styles.tdDimension} ${styles.tdFrozen}`}>Total</td>
                                <td className={`${styles.td} ${styles.tdDimension} ${styles.tdAttr}`} />
                                <td className={`${styles.td} ${styles.tdDimension} ${styles.tdAttr}`} />
                                <td className={`${styles.td} ${styles.tdDimension} ${styles.tdAttr}`} />
                                <td className={`${styles.td} ${styles.tdDimension} ${styles.tdAttr}`} />
                                {METRICS.map((metric) => {
                                    const value = totals[metric.id];
                                    if (metric.kind === 'rate') {
                                        return (
                                            <td key={metric.id} className={`${styles.td} ${styles.tdMetric}`}>
                                                <div className={styles.metricCell}>
                                                    <span className={styles.metricValue}>
                                                        {value == null ? '—' : formatPct(value)}
                                                    </span>
                                                    <span className={styles.metricPct}>Avg</span>
                                                </div>
                                            </td>
                                        );
                                    }
                                    return (
                                        <td key={metric.id} className={`${styles.td} ${styles.tdMetric}`}>
                                            <div className={styles.metricCell}>
                                                <span className={styles.metricValue}>
                                                    {value == null
                                                        ? '—'
                                                        : metric.kind === 'money'
                                                            ? formatRp(value)
                                                            : formatInt(value)}
                                                </span>
                                                <span className={styles.metricPct}>100% of total</span>
                                            </div>
                                        </td>
                                    );
                                })}
                            </tr>
                            {pageRows.length ? (
                                pageRows.map((group, index) => {
                                    const open = expandedKeys.has(group.key);
                                    const canExpand = group.details.length > 1;
                                    const only = canExpand ? null : group.details[0];
                                    const label = displayItemLabel(group.summary.item_label, primary);
                                    return (
                                        <Fragment key={group.key}>
                                            <tr className={styles.tr}>
                                                <td className={styles.td}>{(safePage - 1) * pageSize + index + 1}</td>
                                                <td className={`${styles.td} ${styles.tdDimension} ${styles.tdFrozen}`} title={label}>
                                                    <span className="inline-flex items-center gap-1">
                                                        {canExpand ? (
                                                            <button
                                                                type="button"
                                                                className={`${styles.iconBtn} ${open ? styles.iconBtnExpandOpen : styles.iconBtnExpandClosed}`}
                                                                style={{ height: 22, width: 22, padding: 0 }}
                                                                aria-expanded={open}
                                                                onClick={() => toggleExpanded(group.key)}
                                                            >
                                                                <KeyboardArrowRightOutlinedIcon />
                                                            </button>
                                                        ) : null}
                                                        {label || '—'}
                                                    </span>
                                                </td>
                                                <td className={`${styles.td} ${styles.tdDimension} ${styles.tdAttr}`} title={only?.channel || only?.breakdown_value}>
                                                    {only ? only.channel || only.breakdown_value || '—' : '—'}
                                                </td>
                                                <td className={`${styles.td} ${styles.tdDimension} ${styles.tdAttr}`} title={only?.utm_source}>
                                                    {only?.utm_source || '—'}
                                                </td>
                                                <td className={`${styles.td} ${styles.tdDimension} ${styles.tdAttr}`} title={only?.utm_medium}>
                                                    {only?.utm_medium || '—'}
                                                </td>
                                                <td className={`${styles.td} ${styles.tdDimension} ${styles.tdAttr}`} title={only?.utm_campaign}>
                                                    {only?.utm_campaign || '—'}
                                                </td>
                                                {renderMetrics(group.summary)}
                                            </tr>
                                            <AttributionDetailRows
                                                open={open}
                                                details={group.details}
                                                groupKey={group.key}
                                                label={label || '—'}
                                                totals={totals}
                                            />
                                        </Fragment>
                                    );
                                })
                            ) : (
                                <tr>
                                    <td className={styles.empty} colSpan={METRICS.length + 6}>
                                        Belum ada item untuk filter ini.
                                    </td>
                                </tr>
                            )}
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    );
};

export default AddToCartItemReport;
