// The four colors a theme is actually made of.
//
// Primary and Secondary are the two ends of the Prism accent. Background and
// Foreground are the ground and the text, and neither is stored alone: the
// surfaces (bgDark, bgPanel, bgHighlight, bgPopover, gutter) and the two text
// tints (fgDim, fgMuted) are mixed from them, so changing the ground moves the
// whole family with it rather than leaving twelve tokens pointing at the old
// one.
//
// One eyedropper process and one colour wheel are shared by all four wells --
// the target is remembered rather than duplicated four times.

import QtQuick
import QtQuick.Dialogs
import Quickshell
import Quickshell.Io
import qs.config
import qs.services

Grid {
    id: root

    width: parent ? parent.width : 620
    columns: root.width < 520 ? 1 : 2
    spacing: 12

    // Which well the wheel or the eyedropper is currently answering.
    property string target: "primary"
    property string lastError: ""

    readonly property real cellWidth: root.columns > 1
        ? (root.width - root.spacing) / 2 : root.width

    function currentColor(which: string): string {
        if (which === "primary")
            return String(ThemeProfiles.activeProfile.accent);
        if (which === "secondary")
            return String(ThemeProfiles.activeProfile.secondary);
        if (which === "background")
            return String(ThemeProfiles.activePalette.bg);
        return String(ThemeProfiles.activePalette.fg);
    }

    // Every route through this component ends here, so the wheel, the
    // eyedropper and the typed hex cannot drift apart.
    function apply(which: string, hex: string): void {
        const value = String(hex).trim().toLowerCase();
        if (!/^#[0-9a-f]{6}$/.test(value)) {
            root.lastError = "That is not a colour this theme can use.";
            return;
        }
        root.lastError = "";
        if (which === "primary")
            ThemeProfiles.setAccentPair(value, ThemeProfiles.activeProfile.secondary);
        else if (which === "secondary")
            ThemeProfiles.setAccentPair(ThemeProfiles.activeProfile.accent, value);
        else if (which === "background")
            ThemeProfiles.setGroundColors(value, ThemeProfiles.activePalette.fg);
        else
            ThemeProfiles.setGroundColors(ThemeProfiles.activePalette.bg, value);
    }

    function pick(which: string): void {
        if (screenPicker.running)
            return;
        root.target = which;
        root.lastError = "";
        screenPicker.exec(["hyprpicker", "--format=hex", "--lowercase-hex", "--quiet", "--no-fancy"]);
    }

    function openWheel(which: string): void {
        root.target = which;
        wheel.selectedColor = root.currentColor(which);
        wheel.open();
    }

    Repeater {
        model: [
            { key: "primary", role: "Primary" },
            { key: "secondary", role: "Secondary" },
            { key: "background", role: "Background" },
            { key: "foreground", role: "Foreground" },
        ]

        ColorWell {
            required property var modelData

            width: root.cellWidth
            role: modelData.role
            swatchColor: root.currentColor(modelData.key)
            picking: screenPicker.running
            onCommitted: value => root.apply(modelData.key, value)
            onWheelRequested: root.openWheel(modelData.key)
            onPickRequested: root.pick(modelData.key)
        }
    }

    ColorDialog {
        id: wheel
        title: "Choose a colour"
        // Qt hands back a color value, not a string; toString() on it is
        // "#aarrggbb" when there is alpha, so the channels are read directly.
        onAccepted: root.apply(root.target, Qt.rgba(
            wheel.selectedColor.r, wheel.selectedColor.g,
            wheel.selectedColor.b, 1).toString())
    }

    Process {
        id: screenPicker

        stdout: StdioCollector {
            onStreamFinished: root.apply(root.target, this.text)
        }
        onExited: (exitCode, exitStatus) => {
            if (exitCode !== 0)
                root.lastError = "Screen colour picking was cancelled or unavailable.";
        }
    }
}
