from typing import Optional
from dataclasses import dataclass
from omegaconf import OmegaConf, DictConfig
import os


@dataclass
class Zotero:
    api_key: str
    library_id: str
    library_type: str

    def getattr(self, name):
        return getattr(self, name)

    def _setattr(self, name, value):
        setattr(self, name, value)


@dataclass
class Database:
    name: str
    path: str
    temp: str

    def getattr(self, name):
        return getattr(self, name)

    def _setattr(self, name, value):
        setattr(self, name, value)


@dataclass
class Mail:
    smtp_server: str
    port: int
    sender: str
    password: str
    use_user_name: bool
    printer_mail: str
    user_name: str
    signature: str | None = None
    empty_signature = """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">

    <html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style
    type="text/css">

    p, li { white-space: pre-wrap; }

    hr { height: 1px; border-width: 0; }

    li.unchecked::marker { content: "\2610"; }

    li.checked::marker { content: "\2612"; }

    </style></head><body style=" font-family:''Segoe UI''; font-size:9pt; font-weight:400;
    font-style:normal;">

    <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px;
    margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html>"""

    def getattr(self, name):
        return getattr(self, name)

    def _setattr(self, name, value):
        setattr(self, name, value)

    def setValue(self, **kwargs):
        for key, value in kwargs.items():
            if hasattr(self, key):
                setattr(self, key, value)
            else:
                raise KeyError(f"Invalid option: {key}")


class Icons:
    def __init__(self):
        self._path = None
        self._colors = None
        self._icons = None

    def assign(self, key, value):
        setattr(self, key, value)

    @property
    def path(self):
        return self._path

    @path.setter
    def path(self, value):
        self._path = value

    @property
    def colors(self):
        return self._colors

    @colors.setter
    def colors(self, value):
        self._colors = value

    @property
    def icons(self):
        return self._icons

    @icons.setter
    def icons(self, value):
        self._icons = value

    def get(self, name):
        return self.icons.get(name)


class Config:
    """A class to handle the configuration of the application. After initializing, it will try to load the config file and store it for future access. Any changes made can be saved to the file using the .save() method. Changes are used in real time in the app, if a restart is required, the Application will show a window.

    Raises:
        RuntimeError: Configuration not loaded

        KeyError: Invalid option

    """

    _config: Optional[DictConfig] = None

    def __init__(self, config_path: str):
        """
        Loads the configuration file and stores it for future access.

        Args:
            config_path (str): Path to the YAML configuration file.

        Raises:
            FileNotFoundError: Configuration file not found
        """
        if not os.path.exists(config_path):
            raise FileNotFoundError(f"Configuration file not found: {config_path}")
        self._config = OmegaConf.load(config_path)
        self.config_path = config_path

    def save(self):
        """
        Saves the current configuration to the file.

        Args:
            config_path (str): Path to the YAML configuration file.
        """
        OmegaConf.save(self._config, self.config_path)

    @property
    def zotero(self):
        return Zotero(**self._config.zotero)

    @property
    def zotero_attr(self, name):
        return getattr(self.zotero, name)

    @zotero_attr.setter
    def zotero_attr(self, name, value):
        self.zotero._setattr(name, value)

    @property
    def database(self):
        return Database(**self._config.database)

    @property
    def database_attr(self, name):
        return getattr(self.database, name)

    @database_attr.setter
    def database_attr(self, name, value):
        self.database._setattr(name, value)

    @property
    def mail(self):
        return Mail(**self._config.mail)

    def mail_attr(self, name):
        return getattr(self.mail, name)

    def set_mail_attr(self, name, value):
        OmegaConf.update(self._config, f"mail.{name}", value)

    def set_database_attr(self, name, value):
        OmegaConf.update(self._config, f"database.{name}", value)

    def set_zotero_attr(self, name, value):
        OmegaConf.update(self._config, f"zotero.{name}", value)

    def set_icon_attr(self, name, value):
        OmegaConf.update(self._config, f"icons.{name}", value)

    @property
    def save_path(self):
        return self._config.save_path

    @save_path.setter
    def save_path(self, value: str):
        self._config.save_path = value

    def load_config(self, path, filename):
        return OmegaConf.load(os.path.join(path, filename))

    @property
    def icons(self):
        icons = Icons()
        icons.assign("path", self._config.icon_path)
        icons.assign("colors", self._config.colors)
        icons.assign("icons", self._config.icons)
        return icons

    def dict(self):
        return OmegaConf.to_container(self._config)
