# target_simulator/utils/config_manager.py

"""
Manages loading and saving of application settings and scenarios to a single JSON file.
"""

import json
import os
import sys
from typing import Dict, Any, Optional, List
from enum import Enum


class EnumEncoder(json.JSONEncoder):
    """A custom JSON encoder to handle Enum objects by encoding them as their values."""

    def default(self, o: Any) -> Any:
        if isinstance(o, Enum):
            return o.value
        return super().default(o)


class ConfigManager:
    def save_connection_settings(self, config: Dict[str, Any]):
        """
        Save both target and lru connection configs in the settings file.
        """
        if "general" not in self._settings:
            self._settings["general"] = {}
        self._settings["general"]["connection"] = config
        self._save_settings()

    def get_connection_settings(self) -> Dict[str, Any]:
        """
        Returns the connection settings from the 'general' section.
        """
        general = self._settings.get("general", {})
        return general.get("connection", {})

    """Handles reading and writing application settings and scenarios from a JSON file."""

    def __init__(self, filename: str = "settings.json"):
        """
        Initializes the ConfigManager.

        Args:
            filename: The name of the settings file. It will be stored in
                      the project root directory.
        """
        if getattr(sys, "frozen", False):
            application_path = os.path.dirname(sys.executable)
        else:
            application_path = os.path.abspath(
                os.path.join(os.path.dirname(__file__), "..", "..")
            )

        self.filepath = os.path.join(application_path, filename)
        self._settings = self._load_or_initialize_settings()

    def _load_or_initialize_settings(self) -> Dict[str, Any]:
        """Loads settings from the JSON file or initializes with a default structure."""
        if not os.path.exists(self.filepath):
            return {"general": {}, "scenarios": {}}
        try:
            with open(self.filepath, "r", encoding="utf-8") as f:
                settings = json.load(f)
                if (
                    not isinstance(settings, dict)
                    or "general" not in settings
                    or "scenarios" not in settings
                ):
                    return {"general": settings, "scenarios": {}}
                return settings
        except (json.JSONDecodeError, IOError):
            return {"general": {}, "scenarios": {}}

    def _save_settings(self):
        """Saves the current settings to the JSON file."""
        try:
            with open(self.filepath, "w", encoding="utf-8") as f:
                json.dump(self._settings, f, indent=4, cls=EnumEncoder)
        except IOError as e:
            print(f"Error saving settings to {self.filepath}: {e}")

    def get_general_settings(self) -> Dict[str, Any]:
        """Returns the general settings."""
        return self._settings.get("general", {})

    def save_general_settings(self, data: Dict[str, Any]):
        """Saves the general settings."""
        self._settings["general"] = data
        self._save_settings()

    def get_scenario_names(self) -> List[str]:
        """Returns a list of all scenario names."""
        return list(self._settings.get("scenarios", {}).keys())

    def get_scenario(self, name: str) -> Optional[Dict[str, Any]]:
        """
        Retrieves a specific scenario by name.

        Args:
            name: The name of the scenario to retrieve.

        Returns:
            A dictionary with the scenario data, or None if not found.
        """
        return self._settings.get("scenarios", {}).get(name)

    def save_scenario(self, name: str, data: Dict[str, Any]):
        """
        Saves or updates a scenario.

        Args:
            name: The name of the scenario to save.
            data: The dictionary of scenario data to save.
        """
        if "scenarios" not in self._settings:
            self._settings["scenarios"] = {}
        self._settings["scenarios"][name] = data
        self._save_settings()

    def delete_scenario(self, name: str):
        """
        Deletes a scenario by name.

        Args:
            name: The name of the scenario to delete.
        """
        if "scenarios" in self._settings and name in self._settings["scenarios"]:
            del self._settings["scenarios"][name]
            self._save_settings()
