pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import qs.modules.common.utils

Singleton {
    id: root

    property var keyContent: ({})
    property string keyProjectId: keyContent?.project_id
    property bool keyError: false
    property bool keyReady: false
    property string token: ""
    property date tokenExpiry
    property bool tokenError: false
    property bool tokenReady: false
    readonly property string projectId: keyProjectId

    readonly property bool loaded: keyReady && tokenReady

    readonly property string tokenForKeyScriptPath: Quickshell.shellPath("services/gCloud/token-from-key-venv.sh")

    function load() {
        // Init load will be handled by Component.onCompleted
        if (!tokenReady) return;
        // We just reload if key expired
        if (new Date() >= root.tokenExpiry) {
            root.tokenReady = false;
            root.keyReady = false;
            loadKeyIfPossible();
        }
    }

    function unready() {
        root.keyReady = false;
        root.tokenReady = false;
        root.keyError = false;
        root.tokenError = false;
    }

    function setKeyJson(str: string): bool {
        try {
            var keyData = JSON.parse(str)
            root.unready();
            KeyringStorage.setNestedField(["googleCloud", "serviceAccountKey"], keyData);
            return true;
        } catch(e) {
            return false;
        }
    }

    function getToken() {
        if (root.keyError) {
            root.tokenError = true;
            root.tokenReady = true;
            return;
        }
        tokenProc.runSequence([(() => { // prep token fetcher
                tokenProc.environment.SERVICE_KEY_CONTENT = JSON.stringify(root.keyContent);
                tokenProc.command = [ //
                    "bash", "-c" //
                    , `${tokenForKeyScriptPath} "$SERVICE_KEY_CONTENT"`];
            }), //
            [], // run token fetcher
            ((out) => {
                try {
                    const data = JSON.parse(out)
                    root.token = data.token
                    // Js wants millis instead of seconds
                    root.tokenExpiry = new Date(data.expiry * 1000) 
                    root.tokenError = false;
                } catch(e) {
                    root.tokenError = true;
                    print("[GoogleCloud] Failed to parse token response: " + e + "\n" + out)
                }
                root.tokenReady = true;
            }
            )]);
    }

    function loadKeyIfPossible() {
        if (KeyringStorage.loaded) {
            root.keyContent = KeyringStorage.keyringData?.googleCloud?.serviceAccountKey;
            if (!root.keyContent?.project_id) {
                root.keyError = true;
            } else {
                root.keyError = false;
                root.keyProjectId = root.keyContent.project_id;
            }
            root.keyReady = true;
            root.getToken();
        } else {
            KeyringStorage.fetchKeyringData();
        }
    }

    Component.onCompleted: {
        loadKeyIfPossible();
    }

    Connections {
        target: KeyringStorage
        function onLoadedChanged() {
            root.loadKeyIfPossible();
        }
        function onDataChanged() {
            root.loadKeyIfPossible();
        }
    }

    MultiTurnProcess {
        id: tokenProc
    }
}
