import { JSX, JSXElement } from "solid-js";
import { Icon } from "./Icons.tsx";

export const BUTTON_COLOR_NEUTRAL = "neutral";
export const BUTTON_COLOR_WHITE = "white";
export const BUTTON_COLOR_LIGHT_NEUTRAL = "light-neutral";
export const BUTTON_COLOR_BLUE = "blue";
export const BUTTON_COLOR_DARK_BLUE = "dark-blue";
export const BUTTON_COLOR_GREEN = "green";
export const BUTTON_COLOR_DARK_GREEN = "dark-green";
export const BUTTON_COLOR_RED = "red";
export const BUTTON_COLOR_DARK_RED = "dark-red";
export const BUTTON_COLOR_YELLOW = "yellow";
export const BUTTON_COLOR_ORANGE = "orange";
export const BUTTON_COLOR_PRIMARY = "primary";

const BASE = "inline-flex items-center justify-center gap-2 cursor-pointer text-sm font-normal rounded-default transition disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-2 focus-visible:outline-current focus-visible:outline-offset-2";

const COLORS: Record<string, string> = {
    // The one button that INVERTS with the theme: dark on a light page, light on a
    // dark one. It cannot be `bg-ink` with `text-white`, because the moment the fill
    // goes pale in dark mode the white label vanishes — the fill and its text have to
    // move together, which is what the three fill-neutral tokens are for.
    "neutral":       "shadow-xs bg-fill-neutral text-on-fill-neutral hover:bg-fill-neutral-hover",
    "white":         "shadow-xs bg-surface text-ink border border-line-strong hover:bg-surface-muted",
    "light-neutral": "shadow-xs bg-surface-muted text-ink border border-line-strong hover:bg-surface-raised",
    "blue":          "shadow-xs bg-sky-700 text-white hover:bg-sky-800",
    "dark-blue":     "shadow-xs bg-sky-900 text-white hover:bg-sky-950",
    "green":         "shadow-xs bg-green-700 text-white hover:bg-green-800",
    "dark-green":    "shadow-xs bg-green-900 text-white hover:bg-green-950",
    "red":           "shadow-xs bg-red-700 text-white hover:bg-red-800",
    "dark-red":      "shadow-xs bg-red-900 text-white hover:bg-red-950",
    "yellow":        "shadow-xs bg-yellow-700 text-white hover:bg-yellow-800",
    "orange":        "shadow-xs bg-orange-600 text-white hover:bg-orange-700",
    "primary":       "shadow-xs bg-primary text-white hover:bg-primary-hover",
    "secondary":     "shadow-none bg-surface-raised text-ink border border-line-strong hover:bg-surface-strong",
    "ghost":         "shadow-none bg-transparent text-ink-soft border-none hover:bg-surface-raised",
};

const OUTLINE_COLORS: Record<string, string> = {
    "neutral":       "text-ink",
    "white":         "text-ink-faint",
    "light-neutral": "text-ink-faint",
    "blue":          "text-sky-700 dark:text-sky-400",
    "dark-blue":     "text-sky-900",
    "green":         "text-green-700 dark:text-green-400",
    "dark-green":    "text-green-900",
    "red":           "text-red-700 dark:text-red-400",
    "dark-red":      "text-red-900",
    "yellow":        "text-yellow-700 dark:text-yellow-400",
    "orange":        "text-orange-600",
    "primary":       "text-primary",
};

const OUTLINE_BASE = "bg-transparent shadow-[inset_0_0_0_1px_currentColor] hover:shadow-[inset_0_0_0_2px_currentColor]";

interface ButtonUIProps extends JSX.ButtonHTMLAttributes<HTMLButtonElement> {
    text?: string;
    icon?: unknown;
    outline?: boolean;
    color?: string;
    small?: boolean;
}

export function ButtonUI(props: ButtonUIProps) {
    const hasText = () => props.text !== undefined ? !!props.text : !props.icon;

    const cls = () => {
        let c = BASE;
        if (props.outline) {
            c += " " + OUTLINE_BASE + " " + (OUTLINE_COLORS[props.color!] || OUTLINE_COLORS["neutral"]);
        } else {
            c += " " + (COLORS[props.color!] || COLORS["neutral"]);
        }
        if (props.small) {
            c += props.icon ? " py-1 px-3" : " py-1 px-4";
        } else if (props.icon && !hasText()) {
            c += " py-2 px-3";
        } else if (props.icon) {
            c += " py-2 px-5";
        } else {
            c += " py-2 px-8";
        }
        return c;
    };

    return (
        <button
            type={props.type || "button"}
            onclick={(e) => typeof props.onclick === "function" && props.onclick(e)}
            onmousedown={(e) => typeof props.onmousedown === "function" && props.onmousedown(e)}
            disabled={props.disabled}
            title={props.title}
            class={cls()}
        >
            {props.children}
        </button>
    );
}

interface ButtonLinkProps {
    onclick?: (e: MouseEvent) => void;
    children?: JSXElement;
}

export function ButtonLink(props: ButtonLinkProps) {
    return (
        <button type="button" onclick={(e: MouseEvent) => typeof props.onclick === "function" && props.onclick(e)} class="cursor-pointer bg-transparent border-none p-0 font-[inherit] text-sky-700 dark:text-sky-400 hover:underline">{props.children}</button>
    );
}

export function ButtonLinkRed(props: ButtonLinkProps) {
    return (
        <button type="button" onclick={(e: MouseEvent) => typeof props.onclick === "function" && props.onclick(e)} class="cursor-pointer bg-transparent border-none p-0 font-[inherit] text-red-600 dark:text-red-400 hover:underline">{props.children}</button>
    );
}

// SegmentedButtons renders a horizontal group of mutually-exclusive button
// options - one is "selected" at any time. Used for "toggle" patterns like
// the events sidebar's date/class switcher. Pill styling: a neutral track
// holds a raised white chip that marks the selected option; the rest sit
// muted. Buttons stretch to fill the track (flex-1).
type Reactive2<T> = T | (() => T);

export interface SegmentedButtonOption {
    value: string;
    label: string;
    icon?: string;
}

interface SegmentedButtonsProps {
    options: Reactive2<SegmentedButtonOption[]>;
    value: Reactive2<string>;
    onchange: (v: string) => void;
    small?: boolean;
    class?: string;
}

export function SegmentedButtons(props: SegmentedButtonsProps) {
    const resolveR = <T,>(v: Reactive2<T>): T => (typeof v === "function" ? (v as () => T)() : v);

    // Concentric corner radii: outer = inner + gap, where the gap is the
    // track's p-0.5 (2px) padding -> 6px = 4px + 2px. Reusing one radius for
    // both makes the chip corners read as too sharp inside the track.
    const innerRadius = "rounded-default"; // chips: 4px
    const outerRadius = "rounded-md";      // track: 4px + 2px = 6px

    const sizeCls = () => props.small ? "py-0.5 px-2 text-xs" : "py-1 px-3 text-sm";
    const baseCls = "inline-flex items-center justify-center gap-1.5 flex-1 cursor-pointer font-medium transition-colors whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed";
    const activeCls = "bg-surface text-ink shadow-sm";
    const inactiveCls = "text-ink-muted hover:text-ink";

    const buttonCls = (v: string) => {
        const selected = resolveR(props.value) === v;
        return baseCls + " " + innerRadius + " " + sizeCls() + " " + (selected ? activeCls : inactiveCls);
    };

    return (
        <div class={"flex items-center gap-0.5 " + outerRadius + " bg-surface-raised p-0.5 " + (props.class || "")}>
            {resolveR(props.options).map((opt) => (
                <button
                    type="button"
                    class={buttonCls(opt.value)}
                    onclick={() => props.onchange(opt.value)}
                    title={opt.label}
                >
                    {opt.icon ? <Icon icon={opt.icon} size={12} /> : ""}
                    <span>{opt.label}</span>
                </button>
            ))}
        </div>
    );
}

interface BackLinkProps {
    href: string;
    text?: string;
    onDark?: boolean;
}

// Bare inline-flex anchor — callers control surrounding spacing so
// the link can sit cleanly inside a flex row without throwing off
// vertical alignment (e.g. inside a page header next to a title).
export function BackLink(props: BackLinkProps) {
    const cls = () => "inline-flex items-center gap-1 text-sm no-underline "
        + (props.onDark
            ? "text-text-on-dark-muted hover:text-text-on-dark"
            : "text-ink-soft hover:text-ink");
    return (
        <a href={props.href} class={cls()}>
            <Icon icon="chevron-left" size={16}/>
            {props.text}
        </a>
    );
}
