#!/usr/bin/python3

import os
import platform
from typing import Any
from enum import Enum, auto
from ..utils import EnvVar
from ..core import AbstractQObject, AbstractConfig
from PySide6.QtCore import QSettings, QTimer


class Settings(AbstractQObject, QSettings):
    '''
    Config Class
    ----
    class _Line(AbstractConfig):
        def name(self) - str:
            return "Name"

        def group(self) -> str:
            return "User"

        def get(self) -> Callable:
            return Api.fetch("user-line").text

        def set(self) -> Callable:
            return Api.fetch("user-line").setText

        def signal(self) -> Signal:
            return Api.fetch("user-line").textChanged

        def default(self) -> Any:
            ...

        def type(self) -> object:
            ...

    Usage
    -----
    Settings(
        configs=[
            _Line()
        ]
    )

    Output Result
    -------------
    [User]\n
    Name=
    '''

    class System(Enum):
        java = auto()
        linux = auto()
        darwin = auto()
        windows = auto()

        macos = darwin
        posix = linux
        unknow = auto()

    def __init__(self, *args, configs: list[AbstractConfig] = None, **kwargs):
        QSettings.__init__(self, *args)
        super().__init__(**kwargs)

        if not self.allKeys():
            self._init_configs(configs)
        else:
            self._setup_configs(configs)

    def value(self, 
              key: str,
              default: Any = None,
              type: object | None = None,
              group: str = None
              ) -> Any:

        if group is not None:
            self.beginGroup(group)
            value = super().value(key, 
                                  *(value for value in (default, type) 
                                    if value is not None))
            self.endGroup()
            return value

        return super().value(key)

    def get(self, 
              key: str,
              default: Any = None,
              type: object | None = None,
              group: str = None
              ) -> Any:
        return self.value(key, default, type, group)

    def setValue(self, key: str, value: Any, group: str = None) -> None:
        if group is not None:
            self.beginGroup(group)
            super().setValue(key, value)
            return self.endGroup()
        return super().setValue(key, value)

    def remove(self, key: str, group: str = None) -> None:
        if group is not None:
            self.beginGroup(group)
            super().remove(key)
            return self.endGroup()
        return super().remove(key)

    def _get_default_format(self) -> QSettings.Format:
        return self.defaultFormat()

    def _set_default_path(self) -> str:
        if self.system() == Settings.System.windows:
            if self.scope() == QSettings.Scope.SystemScope:
                return EnvVar.get("FOLDERID_ProgramData")
            return EnvVar.get("FOLDERID_RoamingAppData")

        if self.scope() == QSettings.Scope.SystemScope:
            return os.path.join("etc", "xdg")
        return os.path.join(EnvVar.get("HOME"), ".config")

    def _init_configs(self, configs: list[AbstractConfig]) -> None:
        for config in configs:
            config.signal().connect(
                lambda: QTimer.singleShot(0, lambda: self._update_config(config)))

    def _setup_configs(self, configs: list[AbstractConfig]) -> None:
        for config in configs:
            _value = self.value(config.name(), 
                                config.default(),
                                config.type(),
                                config.group())

            QTimer.singleShot(0, lambda: config.set()(_value))
            config.signal().connect(
                lambda: QTimer.singleShot(0, lambda: self._update_config(config)))

    def _update_config(self, config) -> None:
        self.setValue(config.name(), 
                      config.get()(),
                      config.group())

    def current_system(self) -> System:
        return Settings.System(platform.system().strip().lower() or "unknow")

    def system(self) -> System:
        return self.current_system()