pragma Singleton

import QtQuick
import Quickshell
import Quickshell.Io
import "../Helpers/QtObj2JS.js" as QtObj2JS
import qs.Services.Power
import qs.Services.System
import qs.Services.UI

// Centralized shell state management for small cache files
Singleton {
  id: root

  property string stateFile: ""
  property bool isLoaded: false

  // State properties for different services
  readonly property alias data: adapter

  // Signals for state changes
  signal displayStateChanged
  signal notificationsStateChanged
  signal changelogStateChanged
  signal colorSchemesListChanged

  Component.onCompleted: {
    // Setup state file path (needs Settings to be available)
    Qt.callLater(() => {
                   if (typeof Settings !== 'undefined' && Settings.cacheDir) {
                     stateFile = Settings.cacheDir + "shell-state.json";
                     stateFileView.path = stateFile;
                   }
                 });
  }

  // FileView for shell state
  FileView {
    id: stateFileView
    printErrors: false
    watchChanges: false

    adapter: JsonAdapter {
      id: adapter

      // CompositorService: display scales
      property var display: ({})

      // NotificationService: notification state
      property var notificationsState: ({
                                          lastSeenTs: 0
                                        })

      // UpdateService: changelog state
      property var changelogState: ({
                                      lastSeenVersion: ""
                                    })

      // SchemeDownloader: color schemes list
      property var colorSchemesList: ({
                                        schemes: [],
                                        timestamp: 0
                                      })

      // UI state: settings panel, etc.
      property var ui: ({
                          settingsSidebarExpanded: true
                        })

      // Telemetry state
      property var telemetry: ({
                                 instanceId: ""
                               })

      // Launcher app usage counts
      property var launcherUsage: ({})
    }

    onLoaded: {
      root.isLoaded = true;
      Logger.d("ShellState", "Loaded state file");
    }

    onLoadFailed: error => {
      if (error === 2) {
        // File doesn't exist, will be created on first write
        root.isLoaded = true;
        Logger.d("ShellState", "State file doesn't exist, will create on first write");
      } else {
        Logger.e("ShellState", "Failed to load state file:", error);
        root.isLoaded = true;
      }
    }
  }

  // Launcher usage
  function getLauncherUsageCount(key) {
    const m = adapter.launcherUsage;
    if (!m)
      return 0;
    const v = m[key];
    return typeof v === 'number' && isFinite(v) ? v : 0;
  }

  function recordLauncherUsage(key) {
    let counts = Object.assign({}, adapter.launcherUsage || {});
    counts[key] = getLauncherUsageCount(key) + 1;
    adapter.launcherUsage = counts;
    save();
  }

  // Migrate usage from one key to another, merging counts in a single save
  function migrateLauncherUsage(fromKey, toKey) {
    let counts = Object.assign({}, adapter.launcherUsage || {});
    const fromCount = typeof counts[fromKey] === 'number' && isFinite(counts[fromKey]) ? counts[fromKey] : 0;
    const toCount = typeof counts[toKey] === 'number' && isFinite(counts[toKey]) ? counts[toKey] : 0;
    counts[toKey] = toCount + fromCount;
    delete counts[fromKey];
    adapter.launcherUsage = counts;
    save();
  }

  // Debounced save timer
  Timer {
    id: saveTimer
    interval: 500
    onTriggered: performSave()
  }

  property bool saveQueued: false

  function save() {
    saveQueued = true;
    saveTimer.restart();
  }

  function performSave() {
    if (!saveQueued || !stateFile) {
      return;
    }

    saveQueued = false;

    try {
      // Ensure cache directory exists
      Quickshell.execDetached(["mkdir", "-p", Settings.cacheDir]);

      Qt.callLater(() => {
                     try {
                       stateFileView.writeAdapter();
                       Logger.d("ShellState", "Saved state file");
                     } catch (writeError) {
                       Logger.e("ShellState", "Failed to write state file:", writeError);
                     }
                   });
    } catch (error) {
      Logger.e("ShellState", "Failed to save state:", error);
    }
  }

  // Convenience functions for each service

  // Display state (CompositorService)
  function setDisplay(displayData) {
    adapter.display = displayData;
    save();
    displayStateChanged();
  }

  function getDisplay() {
    return adapter.display || {};
  }

  // Notifications state (NotificationService)
  function setNotificationsState(stateData) {
    adapter.notificationsState = stateData;
    save();
    notificationsStateChanged();
  }

  function getNotificationsState() {
    return adapter.notificationsState || {
      lastSeenTs: 0
    };
  }

  // Changelog state (UpdateService)
  function setChangelogState(stateData) {
    adapter.changelogState = stateData;
    save();
    changelogStateChanged();
  }

  function getChangelogState() {
    return adapter.changelogState || {
      lastSeenVersion: ""
    };
  }

  // Color schemes list (SchemeDownloader)
  function setColorSchemesList(listData) {
    adapter.colorSchemesList = listData;
    save();
    colorSchemesListChanged();
  }

  function getColorSchemesList() {
    return adapter.colorSchemesList || {
      schemes: [],
      timestamp: 0
    };
  }

  // UI state
  function setUiState(stateData) {
    adapter.ui = stateData;
    save();
  }

  function getUiState() {
    return adapter.ui || {
      settingsSidebarExpanded: true
    };
  }

  function setSettingsSidebarExpanded(expanded) {
    let uiState = getUiState();
    uiState.settingsSidebarExpanded = expanded;
    setUiState(uiState);
  }

  function getSettingsSidebarExpanded() {
    return getUiState().settingsSidebarExpanded !== false; // default to true
  }

  // Telemetry state
  function setTelemetryState(stateData) {
    adapter.telemetry = stateData;
    save();
  }

  function getTelemetryState() {
    return adapter.telemetry || {
      instanceId: ""
    };
  }

  function getTelemetryInstanceId() {
    return getTelemetryState().instanceId || "";
  }

  function setTelemetryInstanceId(instanceId) {
    let state = getTelemetryState();
    state.instanceId = instanceId;
    setTelemetryState(state);
  }

  // -----------------------------------------------------
  function buildStateSnapshot() {
    try {
      const settingsData = QtObj2JS.qtObjectToPlainObject(Settings.data);
      const shellStateData = ShellState?.data ? QtObj2JS.qtObjectToPlainObject(ShellState.data) || {} : {};

      return {
        settings: settingsData,
        state: {
          doNotDisturb: NotificationService.doNotDisturb,
          noctaliaPerformanceMode: PowerProfileService.noctaliaPerformanceMode,
          barVisible: BarService.isVisible,
          openedPanel: PanelService.openedPanel?.objectName || "",
          lockScreenActive: PanelService.lockScreen?.active || false,
          wallpapers: WallpaperService.getWallpapersEffectiveMap(),
          desktopWidgetsEditMode: DesktopWidgetRegistry.editMode || false,
          // -------------
          display: shellStateData.display || {},
          notificationsState: shellStateData.notificationsState || {},
          changelogState: shellStateData.changelogState || {},
          colorSchemesList: shellStateData.colorSchemesList || {},
          ui: shellStateData.ui || {}
        }
      };
    } catch (error) {
      Logger.e("Settings", "Failed to build state snapshot:", error);
      return null;
    }
  }
}
