package dev.photosync.ui;

import lombok.Builder;

/**
 * Every colour and metric the interface uses, in one value.
 *
 * <p>Gathered here rather than spread across the widgets so that a colour has a
 * name and a single definition, and so that a screen cannot quietly invent its
 * own shade of grey. Widgets receive one of these through {@link Chrome}; none
 * of them hold colours of their own.
 *
 * <p>Colours are packed 0xAARRGGBB, matching {@code RenderBridge}.
 */
@Builder(toBuilder = true)
public record Theme(
        int scrim,
        int panel,
        int panelBorder,
        int header,
        int surface,
        int surfaceHover,
        int surfacePressed,
        int surfaceSunken,
        int accent,
        int accentHover,
        int accentText,
        int text,
        int textMuted,
        int textFaint,
        int success,
        int warning,
        int danger,
        int scrollTrack,
        int scrollThumb,
        int scrollThumbHover,
        int tilePlaceholder,
        int overlay,
        int padding,
        int gap,
        int rowHeight,
        int controlHeight,
        int headerHeight,
        int footerHeight,
        int tileGap) {

    /**
     * The one theme PhotoSync ships.
     *
     * <p>Dark regardless of anything else on screen: these panels sit over a
     * rendered world, and a light surface there is a flashbang in a night scene.
     */
    public static Theme dark() {
        return Theme.builder()
                // Not opaque -- the world stays faintly visible behind the panel,
                // which is what makes an in-game screen feel like part of the game.
                .scrim(0xB8000000)
                .panel(0xF01A1A21)
                .panelBorder(0xFF3B3B49)
                .header(0xFF23232D)
                .surface(0xFF272733)
                .surfaceHover(0xFF33333F)
                .surfacePressed(0xFF3E3E4D)
                .surfaceSunken(0xFF15151B)
                .accent(0xFF4C8DFF)
                .accentHover(0xFF6BA1FF)
                .accentText(0xFFFFFFFF)
                .text(0xFFE9E9F1)
                .textMuted(0xFF9C9CAD)
                .textFaint(0xFF63636F)
                .success(0xFF5BC98A)
                .warning(0xFFE3B44A)
                .danger(0xFFE86A6A)
                .scrollTrack(0xFF1E1E26)
                .scrollThumb(0xFF454556)
                .scrollThumbHover(0xFF5C5C71)
                .tilePlaceholder(0xFF2A2A35)
                .overlay(0xA0000000)
                .padding(8)
                .gap(4)
                .rowHeight(30)
                .controlHeight(18)
                .headerHeight(28)
                .footerHeight(18)
                .tileGap(4)
                .build();
    }

    /** The same colour at a different opacity, for hints and disabled states. */
    public int fade(int argb, float alpha) {
        int scaled = Math.round(((argb >>> 24) & 0xFF) * Math.max(0f, Math.min(1f, alpha)));
        return (scaled << 24) | (argb & 0x00FFFFFF);
    }

    /** Picks the right surface shade for a control's current interaction state. */
    public int surfaceFor(boolean hovered, boolean pressed) {
        if (pressed) {
            return surfacePressed;
        }
        return hovered ? surfaceHover : surface;
    }
}
