import type { LucideIcon } from 'lucide-react';
import { Link } from '@inertiajs/react';
import { ArrowDownRight, ArrowUpRight, Minus } from 'lucide-react';
import { cn } from '@/lib/utils';
import { MiniBars, Sparkline } from './sparkline';
import { toneClasses } from './tone';

export type Delta = {
    /** Percentage change, or an absolute count when `unit` says so. */
    value: number;
    label: string;
    /** Up is good by default; false means a rise is bad (stalled jobs). */
    upIsGood?: boolean;
    tone?: string;
};

/**
 * A headline number with its context: what it counts, how it moved, and where
 * to go to act on it. One idea per tile.
 */
export function KpiTile({
    label,
    value,
    hint,
    icon: Icon,
    tone = 'slate',
    href,
    series,
    seriesType = 'line',
    delta,
    footer,
    className,
}: {
    label: string;
    value: React.ReactNode;
    hint?: string | null;
    icon?: LucideIcon;
    tone?: string;
    href?: string | null;
    series?: number[];
    seriesType?: 'line' | 'bars';
    delta?: Delta | null;
    footer?: React.ReactNode;
    className?: string;
}) {
    const classes = toneClasses(tone);

    const body = (
        <div
            className={cn(
                'bg-card shadow-card group relative flex h-full flex-col gap-3 overflow-hidden rounded-xl px-4 py-3.5 ring-1 ring-hairline transition',
                href && 'hover:shadow-raised hover:ring-foreground/15',
                className,
            )}
        >
            {/* A hairline of colour along the top: the tile's identity. */}
            {tone !== 'slate' ? (
                <span
                    aria-hidden
                    className={cn(
                        'absolute inset-x-0 top-0 h-0.5 opacity-70',
                        classes.bar,
                    )}
                />
            ) : null}

            <div className="flex items-start justify-between gap-3">
                <p className="crm-label">{label}</p>
                {Icon ? (
                    <span
                        className={cn(
                            'flex size-7 shrink-0 items-center justify-center rounded-lg',
                            classes.soft,
                        )}
                    >
                        <Icon className="size-3.5" />
                    </span>
                ) : null}
            </div>

            {/* The movement sits next to the figure it describes, not pushed to
                the far edge: a tile wide enough for a trend chart would
                otherwise leave the chip stranded half a screen from the
                number. */}
            <div className="flex items-end gap-2">
                <p
                    className={cn(
                        'crm-num text-2xl leading-none font-semibold tracking-tight',
                    )}
                >
                    {value}
                </p>
                {delta ? <DeltaChip delta={delta} /> : null}
            </div>

            {hint ? (
                // Two lines rather than one: a single clipped line turned
                // "Includes Victorian independent inspections" into an
                // ellipsis on the four and five column layouts this tile is
                // used in elsewhere.
                <p
                    className="text-muted-foreground line-clamp-2 text-xs"
                    title={hint}
                >
                    {hint}
                </p>
            ) : null}

            {series && series.length > 1 ? (
                // Tall enough to stay a chart when the tile is wide: at 28px a
                // half-width tile turned the columns into squat blocks.
                <div className="mt-auto -mb-1">
                    {seriesType === 'bars' ? (
                        <MiniBars data={series} tone={tone} height={44} />
                    ) : (
                        <Sparkline data={series} tone={tone} height={44} />
                    )}
                </div>
            ) : null}

            {footer ? (
                <div className="text-muted-foreground mt-auto text-xs">
                    {footer}
                </div>
            ) : null}
        </div>
    );

    if (href) {
        return (
            <Link href={href} className="block h-full focus-visible:rounded-xl">
                {body}
            </Link>
        );
    }

    return body;
}

function DeltaChip({ delta }: { delta: Delta }) {
    const isFlat = delta.value === 0;
    const isUp = delta.value > 0;
    const isGood = delta.upIsGood === false ? !isUp : isUp;
    const tone = delta.tone ?? (isFlat ? 'slate' : isGood ? 'success' : 'danger');
    const classes = toneClasses(tone);
    const Icon = isFlat ? Minus : isUp ? ArrowUpRight : ArrowDownRight;

    return (
        <span
            title={delta.label}
            className={cn(
                'crm-num inline-flex shrink-0 items-center gap-0.5 rounded-md px-1.5 py-0.5 text-xs font-medium',
                classes.pill,
            )}
        >
            <Icon className="size-3" />
            {`${delta.value}%`}
        </span>
    );
}

/**
 * A compact strip of figures, for the top of a detail page where a row of
 * tiles would be too heavy.
 */
export function StatStrip({
    items,
    className,
}: {
    items: Array<{
        label: string;
        value: React.ReactNode;
        tone?: string;
        icon?: LucideIcon;
    }>;
    className?: string;
}) {
    return (
        <div
            className={cn(
                'bg-card shadow-card divide-hairline grid grid-cols-2 divide-x rounded-xl ring-1 ring-hairline sm:grid-cols-4',
                className,
            )}
        >
            {items.map((item) => {
                const classes = toneClasses(item.tone);

                return (
                    <div
                        key={item.label}
                        className="flex items-center gap-3 px-4 py-3"
                    >
                        {item.icon ? (
                            <span
                                className={cn(
                                    'flex size-8 shrink-0 items-center justify-center rounded-lg',
                                    classes.soft,
                                )}
                            >
                                <item.icon className="size-4" />
                            </span>
                        ) : null}
                        <div className="min-w-0">
                            <p className="crm-label truncate">{item.label}</p>
                            <p className="crm-num mt-0.5 truncate text-sm font-semibold">
                                {item.value}
                            </p>
                        </div>
                    </div>
                );
            })}
        </div>
    );
}
