"""Application configuration using pydantic-settings with TOML file support."""

import os
import sys
from pathlib import Path

from pydantic import Field
from pydantic_settings import BaseSettings, PydanticBaseSettingsSource
from pydantic_settings.sources import TomlConfigSettingsSource


def _user_home() -> Path:
    """
    Return the current user's home directory.

    Returns
    -------
    Path
        Home directory path, resolved via platform-specific environment variables.
    """
    if sys.platform == "linux" or sys.platform == "darwin":
        return Path(os.getenv("HOME", ""))
    else:
        return Path(os.getenv("USERPROFILE", ""))


def _settings_home() -> Path:
    """
    Return the settings directory, creating it if necessary.

    Returns
    -------
    Path
        Platform-specific configuration directory for notulist.
    """
    if sys.platform == "linux" or sys.platform == "darwin":
        settings_home = _user_home() / ".config" / "notulist"

    else:
        settings_home = _user_home() / ".notulist"

    if not settings_home.exists():
        settings_home.mkdir(parents=True, exist_ok=True)

    return settings_home


def _default_editor() -> str:
    """
    Return the default text editor for the current platform.

    Returns
    -------
    str
        ``"vi"`` on Linux/macOS, ``"notepad"`` on Windows.
    """
    if sys.platform == "linux" or sys.platform == "darwin":
        return "vi"
    else:
        return "notepad"


def _default_repository() -> str:
    """
    Return the default notes repository path.

    Returns
    -------
    str
        Path to ``~/notes``.
    """
    return str(_user_home() / "notes")


class AppSettings(BaseSettings):
    """Application settings loaded from a TOML config file and environment variables."""

    editor: str = Field(default_factory=_default_editor)
    repository: str = Field(default_factory=_default_repository)

    @classmethod
    def settings_customise_sources(
        cls,
        settings_cls: type[BaseSettings],
        init_settings: PydanticBaseSettingsSource,
        env_settings: PydanticBaseSettingsSource,
        dotenv_settings: PydanticBaseSettingsSource,
        file_secret_settings: PydanticBaseSettingsSource,
    ):
        settings_file_path = _settings_home() / "config.toml"

        if not settings_file_path.exists():
            settings_file_path.touch()

        return (
            TomlConfigSettingsSource(settings_cls, settings_file_path),
            env_settings,
        )

    def save(self) -> None:
        """
        Write the current settings to ``config.toml``.

        Serializes all model fields as top-level TOML key-value pairs and
        writes them to the configuration file, overwriting its contents.
        """
        config_path = _settings_home() / "config.toml"
        lines = [
            f"{key} = {_toml_encode_value(value)}"
            for key, value in self.model_dump().items()
        ]
        config_path.write_text("\n".join(lines) + "\n")


def _toml_encode_value(value: object) -> str:
    """
    Encode a Python value as a TOML literal string.

    Parameters
    ----------
    value : object
        The value to encode. Supports ``str``, ``int``, ``float``, and ``bool``.

    Returns
    -------
    str
        TOML-formatted representation of the value.
    """
    if isinstance(value, str):
        escaped = value.replace("\\", "\\\\").replace('"', '\\"')
        return f'"{escaped}"'
    if isinstance(value, bool):
        return "true" if value else "false"
    return str(value)
