"""
Defines settings for Solid-LSP
"""

import logging
import os
import pathlib
from dataclasses import dataclass, field
from typing import TYPE_CHECKING, Any

from sensai.util.string import ToStringMixin

if TYPE_CHECKING:
    from solidlsp.ls_config import Language

log = logging.getLogger(__name__)


@dataclass
class SolidLSPSettings:
    solidlsp_dir: str = str(pathlib.Path.home() / ".solidlsp")
    """
    Path to the directory in which to store global Solid-LSP data (which is not project-specific)
    """
    project_data_path: str = ""
    """
    Absolute path to a directory where Solid-LSP can store project-specific data, e.g. cache files.
    For instance, if this is "/home/user/myproject/.solidlsp",
    then Solid-LSP will store project-specific data (e.g. caches) in that directory.
    """
    ls_specific_settings: dict["Language", dict[str, Any]] = field(default_factory=dict)
    """
    Advanced configuration option allowing to configure language server implementation specific options.
    Have a look at the docstring of the constructors of the corresponding LS implementations within solidlsp to see which options are available.
    No documentation on options means no options are available.
    """
    additional_workspace_folders: list[str] = field(default_factory=list)
    """
    Additional workspace folder paths for cross-package reference support.
    Paths can be absolute or relative to the project root. Each folder is added as a workspace
    folder in the LSP initialization, enabling language servers to discover symbols and references
    across package boundaries (e.g. in monorepos).
    """

    def __post_init__(self) -> None:
        os.makedirs(str(self.solidlsp_dir), exist_ok=True)
        os.makedirs(str(self.ls_resources_dir), exist_ok=True)

    @property
    def ls_resources_dir(self) -> str:
        return os.path.join(str(self.solidlsp_dir), "language_servers", "static")

    class CustomLSSettings(ToStringMixin):
        def __init__(self, settings: dict[str, Any] | None) -> None:
            self.settings = settings or {}

        def get(self, key: str, default_value: Any = None) -> Any:
            """
            Returns the custom setting for the given key or the default value if not set.
            If a custom value is set for the given key, the retrieval is logged.

            :param key: the key
            :param default_value: the default value to use if no custom value is set
            :return: the value
            """
            if key in self.settings:
                value = self.settings[key]
                log.info("Using custom LS setting %s for key '%s'", value, key)
            else:
                value = default_value
            return value

    def get_ls_specific_settings(self, language: "Language") -> CustomLSSettings:
        """
        Get the language server specific settings for the given language.

        :param language: The programming language.
        :return: A dictionary of settings for the language server.
        """
        return self.CustomLSSettings(self.ls_specific_settings.get(language))
