import { cn } from '@/lib/utils';
import { toneClasses } from './tone';

/**
 * A trend, not a chart. No axes, no tooltips, no library: a shape that tells
 * you whether the last eight weeks went up or down.
 */
export function Sparkline({
    data,
    tone = 'solar',
    className,
    height = 34,
}: {
    data: number[];
    tone?: string;
    className?: string;
    height?: number;
}) {
    const points = data.length > 0 ? data : [0, 0];
    const max = Math.max(...points);
    const min = Math.min(...points);
    const range = max - min || 1;

    const step = points.length > 1 ? 100 / (points.length - 1) : 100;

    const coords = points.map((value, index) => {
        const x = index * step;
        // Leave a little headroom so the peak is not clipped by the stroke.
        const y = 28 - ((value - min) / range) * 24;

        return [x, y] as const;
    });

    const line = coords
        .map(([x, y], index) => `${index === 0 ? 'M' : 'L'}${x.toFixed(2)},${y.toFixed(2)}`)
        .join(' ');

    const area = `${line} L100,32 L0,32 Z`;

    const gradientId = `spark-${tone}-${points.join('-').length}`;

    return (
        <svg
            viewBox="0 0 100 32"
            preserveAspectRatio="none"
            aria-hidden
            className={cn(
                'w-full overflow-visible',
                toneClasses(tone).text,
                className,
            )}
            style={{ height }}
        >
            <defs>
                <linearGradient id={gradientId} x1="0" y1="0" x2="0" y2="1">
                    <stop
                        offset="0%"
                        stopColor="currentColor"
                        stopOpacity="0.22"
                    />
                    <stop
                        offset="100%"
                        stopColor="currentColor"
                        stopOpacity="0"
                    />
                </linearGradient>
            </defs>
            <path d={area} fill={`url(#${gradientId})`} />
            <path
                d={line}
                fill="none"
                stroke="currentColor"
                strokeWidth="1.5"
                strokeLinecap="round"
                strokeLinejoin="round"
                vectorEffect="non-scaling-stroke"
            />
        </svg>
    );
}

/**
 * The same idea for small whole numbers, where discrete columns read better
 * than a line.
 */
export function MiniBars({
    data,
    tone = 'solar',
    className,
    height = 34,
}: {
    data: number[];
    tone?: string;
    className?: string;
    height?: number;
}) {
    const points = data.length > 0 ? data : [0];
    const max = Math.max(...points) || 1;
    const classes = toneClasses(tone);

    return (
        <div
            aria-hidden
            className={cn('flex w-full items-end gap-1', className)}
            style={{ height }}
        >
            {points.map((value, index) => (
                <span
                    key={index}
                    className={cn(
                        'flex-1 rounded-sm opacity-80',
                        value > 0 ? classes.bar : 'bg-muted',
                    )}
                    style={{
                        height: `${Math.max(6, Math.round((value / max) * 100))}%`,
                    }}
                />
            ))}
        </div>
    );
}
