/**
 * Colour is the calendar's only saturated channel and it means one thing: which
 * classroom a lesson belongs to. Status is carried by weight and shape instead, so
 * the two never compete. Text is always drawn with theme tokens, never with these
 * values, which keeps contrast safe in both light and dark.
 */

/**
 * Eight hues 45 degrees apart at the same lightness, so no classroom shouts louder.
 * Same list as `Classroom::COLORS` on the server and `--brand-hue-*` in `app.css`;
 * every value clears 3:1 against both themes' backgrounds.
 */
const fallbackPalette = [
    '#009160',
    '#008da1',
    '#347bc5',
    '#8265be',
    '#ad558f',
    '#bb544c',
    '#a96900',
    '#748200',
];

type Colourable = { id: number; color?: string | null };

/** The classroom's own colour, or a stable one derived from its id. */
export function classroomColor(classroom: Colourable): string {
    if (classroom.color) {
        return classroom.color;
    }

    return fallbackPalette[Math.abs(classroom.id) % fallbackPalette.length];
}

/** The same colour at a given opacity, for tinted fills behind text. */
export function withAlpha(color: string, alpha: number): string {
    const hex = color.trim();

    if (!hex.startsWith('#')) {
        return `color-mix(in oklab, ${hex} ${Math.round(alpha * 100)}%, transparent)`;
    }

    const digits =
        hex.length === 4
            ? hex
                  .slice(1)
                  .split('')
                  .map((digit) => digit + digit)
                  .join('')
            : hex.slice(1, 7);

    if (digits.length !== 6) {
        return hex;
    }

    const value = Number.parseInt(digits, 16);

    if (Number.isNaN(value)) {
        return hex;
    }

    const red = (value >> 16) & 255;
    const green = (value >> 8) & 255;
    const blue = value & 255;

    return `rgba(${red}, ${green}, ${blue}, ${alpha})`;
}
