pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import QtCore
import Quickshell
import Quickshell.Io
import qs.plugins
import qs.services

Singleton {
    id: root
    property string filePath: Directories.shellConfigPath
    property alias runtime: configOptionsJsonAdapter
    property bool initialized: false
    property int readWriteDelay: 50
    property bool blockWrites: false

    function updateKey(nestedKey, value) {
        let keys = nestedKey.split(".")
        let obj = root.runtime
        if (!obj) {
            console.warn("Config.updateKey: adapter not available for key", nestedKey)
            return
        }

        for (let i = 0; i < keys.length - 1; ++i) {
            let k = keys[i]
            if (obj[k] === undefined || obj[k] === null || typeof obj[k] !== "object") {
                obj[k] = {}  // Use Plain JS for serialization
            }
            obj = obj[k]
            if (!obj) {
                console.warn("Config.updateKey: failed to resolve", k)
                return
            }
        }

        let convertedValue = value
        if (typeof value === "string") {
            let trimmed = value.trim()
            if (trimmed === "true" || trimmed === "false" || (!isNaN(Number(trimmed)) && trimmed !== "")) {
                try {
                    convertedValue = JSON.parse(trimmed)
                } catch (e) {
                    convertedValue = value
                }
            }
        }

        obj[keys[keys.length - 1]] = convertedValue
        configFileView.adapterUpdated()
    }

    function loadPluginConfigs(plugins) {
        console.log("Loading plugins:", plugins)

        if (!root.runtime)
            return

        if (!root.runtime.plugins)
            root.runtime.plugins = {}

        function mergeDefaults(target, defaults) {
            let changed = false

            for (let key in defaults) {
                const defVal = defaults[key]
                const tgtVal = target[key]

                if (tgtVal === undefined) {
                    target[key] = defVal
                    changed = true
                } else if (
                    typeof tgtVal === "object" &&
                    typeof defVal === "object" &&
                    tgtVal !== null &&
                    defVal !== null
                ) {
                    if (mergeDefaults(tgtVal, defVal))
                        changed = true
                }
            }

            return changed
        }

        let anyChange = false

        for (let i = 0; i < plugins.length; i++) {
            const name = plugins[i]
            const path = Directories.shellConfig + "/plugins/" + name + "/PluginConfigData.qml"

            const component = Qt.createComponent(path)
            if (component.status === Component.Error) {
                console.warn("Plugin failed:", path, component.errorString())
                continue
            }

            if (component.status !== Component.Ready)
                continue

            const pluginObj = component.createObject(root)
            if (!pluginObj) {
                console.warn("Failed to create plugin object:", name)
                component.destroy()
                continue
            }

            if (!pluginObj.defaults)
                pluginObj.defaults = { enabled: false }

            if (!root.runtime.plugins[name]) {
                root.runtime.plugins[name] = {}
                anyChange = true
            }

            if (mergeDefaults(root.runtime.plugins[name], pluginObj.defaults))
                anyChange = true

            console.log("Plugin config injected:", name)

            pluginObj.destroy()
            component.destroy()
        }

        if (anyChange) {
            console.log("Plugin defaults merged, writing config")
            configFileView.adapterUpdated()
        } else {
            console.log("Plugin configs already up to date")
        }
    }

    Timer { id: fileReloadTimer; interval: root.readWriteDelay; repeat: false; onTriggered: configFileView.reload() }
    Timer { id: fileWriteTimer; interval: root.readWriteDelay; repeat: false; onTriggered: configFileView.writeAdapter() }

    Timer { // Used to output all log/debug to the terminal
        interval: 1200
        running: true
        repeat: false
        onTriggered: {
            console.log("Injecting plugin configs")
            root.loadPluginConfigs(PluginLoader.plugins)
            console.log("Detected Compositor:", Compositor.detectedCompositor)
        }
    }

    FileView {
        id: configFileView
        path: root.filePath
        watchChanges: true
        blockWrites: root.blockWrites
        onFileChanged: fileReloadTimer.restart()
        onAdapterUpdated: fileWriteTimer.restart()
        onLoaded: { root.initialized = true }
        onLoadFailed: error => {
            if (error == FileViewError.FileNotFound) writeAdapter()
        }

        JsonAdapter {
            id: configOptionsJsonAdapter
            
            property var plugins: ({}) // dynamic plugins config variable
            property var monitors: ({}) // per-monitor configuration for bars and wallpapers

            property JsonObject appearance: JsonObject {
                property string theme: "dark"
                property bool tintIcons: false
                property JsonObject animations: JsonObject { property bool enabled: true; property double durationScale: 1 }
                property JsonObject transparency: JsonObject { property bool enabled: false; property double alpha: 0.2 }
                property JsonObject rounding: JsonObject { property double factor: 1 }
                property JsonObject font: JsonObject { 
                    property double scale: 1 
                    property JsonObject families: JsonObject {
                        property string main: "JetBrains Mono"
                        property string title: "Gabarito"
                        property string materialIcons: "Material Symbols Rounded"
                        property string nerdFonts: "JetBrains Mono NF"
                        property string monospace: "JetBrains Mono NF"
                        property string reading: "Readex Pro"
                        property string expressive: "Space Grotesk"
                    }
                }
                property JsonObject colors: JsonObject {
                    property string scheme: "catppuccin-lavender"
                    property string matugenScheme: "scheme-neutral"
                    property bool autogenerated: true
                    property bool runMatugenUserWide: false
                }
                property JsonObject background: JsonObject {
                    property bool enabled: true 
                    property url defaultPath: Directories.defaultsPath + "/default.jpg"
                    property JsonObject parallax: JsonObject {
                        property bool enabled: true 
                        property bool enableSidebarLeft: true
                        property bool enableSidebarRight: true
                        property real zoom: 1.10
                    }
                    property JsonObject clock: JsonObject {
                        property bool enabled: true 
                        property bool isAnalog: true
                        property bool rotatePolygonBg: false 
                        property int rotationDuration: 18 // lower the faster
                        property int edgeSpacing: 50
                        property int shape: 1
                        property int xPos: 0
                        property int yPos: 0
                        property bool animateHands: false
                    }
                    property JsonObject slideshow: JsonObject {
                        property bool enabled: false
                        property bool includeSubfolders: true
                        property int interval: 5
                        property string folder: ""
                    }
                }
            }

            property JsonObject misc: JsonObject { 
                property url pfp: Quickshell.env("HOME") + "/.face.icon" 
                property JsonObject intelligence: JsonObject {
                    property bool enabled: true
                    property string apiKey: ""
                }
            }
            
            property JsonObject notifications: JsonObject {
                property bool enabled: true 
                property bool doNotDisturb: false
                property string position: "center"
            }
            property JsonObject shell: JsonObject {
                property string version: "0.7.7"
                property string releaseChannel: "stable"
                property string qsVersion: "0.0.0"
            }
            property JsonObject overlays: JsonObject {
                property bool enabled: true 
                property bool volumeOverlayEnabled: true 
                property bool brightnessOverlayEnabled: true
                property string volumeOverlayPosition: "top"
                property string brightnessOverlayPosition: "top"
            }
            property JsonObject launcher: JsonObject {
                property bool fuzzySearchEnabled: true
                property string webSearchEngine: "google"
            }
            property JsonObject bar: JsonObject {
                property string position: "top"
                property bool enabled: true
                property bool merged: false
                property bool floating: false
                property bool gothCorners: true
                property int radius: Appearance.rounding.large
                property int margins: Appearance.margin.normal
                property int density: 50
                property JsonObject modules: JsonObject {
                    property color paddingColor: Appearance.m3colors.m3surfaceContainer
                    property int radius: Appearance.rounding.normal
                    property int height: 34
                    property JsonObject workspaces: JsonObject {
                        property bool enabled: true
                        property int workspaceIndicators: 8
                        property bool showAppIcons: true 
                        property bool showJapaneseNumbers: false
                    }
                    property JsonObject statusIcons: JsonObject {
                        property bool enabled: true
                        property bool networkStatusEnabled: true 
                        property bool bluetoothStatusEnabled: true 
                    }
                    property JsonObject systemUsage: JsonObject {
                        property bool enabled: true
                        property bool cpuStatsEnabled: true 
                        property bool memoryStatsEnabled: true 
                        property bool tempStatsEnabled: true
                    }
                }
            }
        }
    }
}
