import { clsx } from "clsx";
import { HTMLAttributes, TdHTMLAttributes, ThHTMLAttributes } from "react";

/*
 * Below sm the table stops being a table: the head is hidden, each row becomes
 * a bordered card and each cell becomes a label/value pair. That lives here
 * rather than in the six pages that render tables two markup trees per page
 * would drift apart on the first edit, and every one of those trees would mean
 * the same thing.
 *
 * The mobile label uses Th's exact keyed-label idiom (mono, small, widely
 * tracked, dimmed) because a key beside a value on a phone is the same device
 * as a column head above it on a desktop.
 */

export function Table({ className, children, ...props }: HTMLAttributes<HTMLTableElement>) {
    return (
        <div className="overflow-x-auto">
            <table className={clsx("w-full border-collapse text-sm max-sm:block", className)} {...props}>
                {children}
            </table>
        </div>
    );
}

export function Thead({ className, children, ...props }: HTMLAttributes<HTMLTableSectionElement>) {
    return (
        <thead className={clsx("border-b border-border max-sm:hidden", className)} {...props}>
            {children}
        </thead>
    );
}

export function Tbody({ className, children, ...props }: HTMLAttributes<HTMLTableSectionElement>) {
    return (
        <tbody className={clsx("divide-y divide-border", "max-sm:block max-sm:space-y-3 max-sm:divide-y-0 max-sm:p-3", className)} {...props}>
            {children}
        </tbody>
    );
}

export function Tr({ className, children, ...props }: HTMLAttributes<HTMLTableRowElement>) {
    return (
        <tr className={clsx("transition-colors hover:bg-surface-2/50", "max-sm:block max-sm:rounded max-sm:border max-sm:border-border max-sm:bg-surface-2/40 max-sm:p-3", className)} {...props}>
            {children}
        </tr>
    );
}

export function Th({ className, children, ...props }: ThHTMLAttributes<HTMLTableCellElement>) {
    return (
        <th
            className={clsx(
                // site/'s keyed-label idiom: mono, small, widely tracked, dimmed.
                // A column head is a key, not prose.
                // text-secondary, not tertiary: a column head is how you navigate the
                // table, and tertiary lands under 4.5:1 at this size.
                "px-4 py-3 text-left font-mono text-[0.68rem] uppercase tracking-[0.13em] text-text-secondary",
                className,
            )}
            {...props}
        >
            {children}
        </th>
    );
}

interface TdProps extends TdHTMLAttributes<HTMLTableCellElement> {
    /**
     * The column head this cell belongs to, shown beside the value below sm
     * where the real head is hidden. Omit on a trailing action cell an action
     * needs no key, and the button then sits alone on its own row in the card.
     */
    label?: string;
}

export function Td({ className, label, children, ...props }: TdProps) {
    return (
        <td
            className={clsx(
                "px-4 py-3 text-text-primary",
                "max-sm:flex max-sm:items-start max-sm:gap-4 max-sm:px-0 max-sm:py-1.5",
                // Exactly one justify class clsx picks it. Emitting both and relying
                // on string order would not work: Tailwind's output order decides which
                // of two same-property utilities wins, not the order in this array.
                label ? "max-sm:justify-between" : "max-sm:justify-end max-sm:pt-2.5",
                className,
            )}
            {...props}
        >
            {label && <span className="hidden shrink-0 font-mono text-[0.68rem] uppercase leading-5 tracking-[0.13em] text-text-secondary max-sm:inline">{label}</span>}
            {/*
             * Below sm the cell is a flex row, and a flex item's default
             * min-width:auto resolves to its min-content width. A fingerprint or a
             * target URL is a single unbreakable token, so min-content was the whole
             * string: the value refused to shrink and spilled out of the card.
             * min-w-0 lets it shrink, break-words gives the token somewhere to break.
             *
             * Above sm the wrapper is display:contents, so the desktop table renders
             * exactly as it did before. Every other class here is max-sm: scoped on
             * purpose display:contents generates no box, but inherited properties
             * (overflow-wrap among them) would still reach the children.
             */}
            <span className="max-sm:min-w-0 max-sm:break-words sm:contents">{children}</span>
        </td>
    );
}
