import { createSignal, onCleanup, onMount, Show, For, JSXElement } from "solid-js";

interface TabItem {
    title: string;
    badge?: number;
    content?: JSXElement;
}

interface TabGroupProps {
    items: TabItem[];
    storageKey?: string;
    activeIndex?: number;
    onTabChange?: (index: number) => void;
    defaultIndex?: number;
    /** Optional content rendered in the right side of the tab bar (e.g. a PillSelect). */
    actions?: JSXElement;
    /** Extra classes on the root element (e.g. `ui-tabs` for structured panel CSS). */
    class?: string;
    /** When true, tabs fill available height and panels scroll internally (mobile POS). */
    fill?: boolean;
    /** When true, tab buttons share the header row equally below md. Defaults to true when `actions` is omitted. */
    stretch?: boolean;
    /** Tighter spacing for tabs above sibling panel content (use with PageLayout `tabs`). */
    pageTabs?: boolean;
}

const TAB_BASE = "flex items-center gap-1.5 cursor-pointer py-2 px-4 text-sm font-medium bg-transparent border-0 border-b-2 transition-[color,border-color] duration-150";
const TAB_INACTIVE = "text-ink-muted border-line hover:text-ink";
const TAB_ACTIVE = "text-primary border-primary";

function resolveBadge(badge: number | undefined): number | undefined {
    return typeof badge === "function" ? (badge as () => number)() : badge;
}

export function TabGroup(props: TabGroupProps) {
    const getInitialIndex = () => {
        if (props.storageKey) {
            const stored = localStorage.getItem(props.storageKey);
            if (stored !== null) {
                const parsed = parseInt(stored, 10);
                if (!isNaN(parsed) && parsed >= 0 && parsed < props.items.length) {
                    return parsed;
                }
            }
        }
        return props.defaultIndex ?? 0;
    };

    const [_activeIndex, _setActiveIndex] = createSignal(getInitialIndex());

    const activeIndex = (): number => {
        const controlled = props.activeIndex;
        if (controlled != null) {
            return typeof controlled === "function" ? (controlled as () => number)() : controlled;
        }
        return _activeIndex();
    };

    const setActiveIndex = (i: number) => {
        _setActiveIndex(i);
        if (props.storageKey) {
            const v = String(i);
            localStorage.setItem(props.storageKey, v);
            // localStorage writes don't fire `storage` events in the same
            // tab; synthesize one so other components syncing on this key
            // (e.g. an EventsSidebar tracking the active session) update.
            window.dispatchEvent(new StorageEvent("storage", { key: props.storageKey, newValue: v }));
        }
        props.onTabChange && props.onTabChange(i);
    };

    // Sync uncontrolled tabs across components that share a storageKey: when
    // another part of the UI writes to it (and dispatches a synthetic storage
    // event), pick up the new value here too.
    onMount(() => {
        if (!props.storageKey) return;
        const handler = (e: StorageEvent) => {
            if (e.key !== props.storageKey || e.newValue == null) return;
            const n = parseInt(e.newValue, 10);
            if (!isNaN(n) && n >= 0 && n < props.items.length && n !== _activeIndex()) {
                _setActiveIndex(n);
                props.onTabChange && props.onTabChange(n);
            }
        };
        window.addEventListener("storage", handler);
        onCleanup(() => window.removeEventListener("storage", handler));
    });

    const structured = () => props.fill || (props.class || "").includes("ui-tabs");

    const pageTabs = () => props.pageTabs || (props.class || "").includes("page-tabs");

    const rootCls = () => {
        const parts = props.fill
            ? ["ui-tabs flex w-full min-h-0 flex-1 flex-col overflow-hidden"]
            : pageTabs()
                ? ["w-full page-tabs"]
                : ["w-full pb-4"];
        if (props.class) parts.push(props.class);
        return parts.join(" ");
    };

    const headerCls = () => structured()
        ? "header overflow-x-auto flex flex-row w-full shrink-0 text-sm"
        : "overflow-x-auto flex flex-row w-full text-sm";

    const panelCls = (index: number) => {
        const active = index === activeIndex();
        if (!structured()) return active ? "" : "hidden";
        if (!active) return "panel hidden";
        return props.fill
            ? "panel flex min-h-0 flex-1 flex-col overflow-hidden"
            : "panel";
    };

    const stretchTabs = () => {
        if (props.actions != null) return props.stretch === true;
        return props.stretch !== false;
    };

    const stretchCls = () => {
        if (!stretchTabs()) return "";
        return " flex-1 justify-center md:flex-initial md:justify-start";
    };

    const tabBtnCls = (index: number) => () =>
        TAB_BASE
        + stretchCls()
        + " "
        + (index === activeIndex() ? TAB_ACTIVE : TAB_INACTIVE);

    const hasInlinePanels = () => props.items.some((item) => item.content != null);

    const actionsContent = () => {
        if (props.actions == null) return null;
        return typeof props.actions === "function" ? (props.actions as () => JSXElement)() : props.actions;
    };

    return (
        <div class={rootCls()}>
            <div class={headerCls()}>
                <For each={props.items}>{(item, index) => (
                    <button type="button" onclick={() => setActiveIndex(index())} class={tabBtnCls(index())()}>
                        {item.title}
                        <Show when={(() => {
                            const b = resolveBadge(item.badge);
                            return b != null && b > 0;
                        })()}>
                            <span class="inline-flex items-center justify-center min-w-5 h-5 px-1 text-ss font-semibold bg-primary text-white rounded-full">{resolveBadge(item.badge)}</span>
                        </Show>
                    </button>
                )}</For>
                <Show when={props.actions != null && !!actionsContent()}>
                    <div class="tab-actions flex-1 self-end border-b-2 border-line flex items-center justify-end pb-1">
                        <div class="flex items-center min-w-0">
                            {actionsContent()}
                        </div>
                    </div>
                </Show>
            </div>
            <Show when={hasInlinePanels()}>
                <For each={props.items}>{(item, index) => (
                    <Show when={item.content != null}>
                        <div class={panelCls(index())}>
                            {item.content}
                        </div>
                    </Show>
                )}</For>
            </Show>
        </div>
    );
}
