from __future__ import annotations
from typing import Type

from pathlib import Path

from .config import BaseConfig, Field, SettingsConfigDict
from .workspaces.workspaces import WorkspacesConfig, WorkspaceConfig


class SessionConfig(BaseConfig):
    model_config = SettingsConfigDict(env_prefix="tgzr_")
    verbose: bool = Field(False, description="Tchatty logs")


class Session:

    def __init__(self):
        self._config_filename = ".tgzr"
        self._home: Path = Path.cwd().resolve()
        config_path = SessionConfig.find_config_file(self._home, self._config_filename)
        if config_path is not None:
            self._config = SessionConfig.from_file(config_path)
        else:
            self._config: SessionConfig = SessionConfig(
                _env_file=Path.cwd() / self._config_filename  # type: ignore No parameter named "_env_file"
            )

        self._known_config_types: list[Type[BaseConfig]] = []

        self.declare_config_type(SessionConfig)
        self.declare_config_type(WorkspacesConfig)
        self.declare_config_type(WorkspaceConfig)

    @property
    def home(self) -> Path:
        if self._home is None:
            raise ValueError("Home not set. Please use `set_home(path) first.`")
        return self._home

    def set_home(
        self, path: str | Path, ensure_config_found: bool = True
    ) -> Path | None:
        """Returns the path of the config loaded or None."""
        path = Path(path).resolve()
        config_path = SessionConfig.find_config_file(path, self._config_filename)
        if config_path is None:
            if ensure_config_found:
                raise FileNotFoundError(
                    f"Could not find a {self._config_filename} file under {path!r} and ancestors. "
                    "(Use `ensure_config_found=False` to bypass this error.)"
                )
            self._home = path
            return None
        else:
            self._home = config_path.parent
            self._config = SessionConfig.from_file(config_path)
            return config_path

    @property
    def config(self) -> SessionConfig:
        if self._config is None:
            raise ValueError("Config not set. Please use `set_home(path) first.`")
        return self._config

    def save_config(self) -> Path:
        """Returns the path of the saved file."""
        return self.write_config_file(None, allow_overwrite=True)

    def write_config_file(
        self, path: str | Path | None, allow_overwrite: bool = False
    ) -> Path:
        """Returns the path of the saved file."""
        if path is None:
            path = self._home / self._config_filename
        path = Path(path).resolve()
        self._config.to_file(
            path,
            allow_overwrite=allow_overwrite,
            header_text="tgzr session config",
        )
        return path

    def declare_config_type(self, config_type: Type[BaseConfig]):
        """
        Declare the config type as used in the session.
        This is used for documentation and cli help.
        """
        self._known_config_types.append(config_type)

    def get_config_env_vars(self) -> list[tuple[str, list[tuple[str, str | None]]]]:
        """
        Returns a list of (name, description) for each config
        declared with `declare_config_type()`
        """
        config_env_vars = []
        for config_type in self._known_config_types:
            config_env_vars.append((config_type.__name__, config_type.used_env_vars()))
        return config_env_vars
