"""Configuration management for mnmd-anki-sync."""

import html
import sys
from enum import Enum
from pathlib import Path
from typing import List

import yaml
from pydantic import BaseModel, Field

from .utils.exceptions import ConfigError


class EditorProtocol(str, Enum):
    """Supported editor protocols for source links."""

    VSCODE = "vscode"
    VSCODIUM = "vscodium"
    NVIM = "nvim"
    OBSIDIAN = "obsidian"
    FILE = "file"  # Generic file:// protocol (requires system handler)


class Config(BaseModel):
    """Application configuration."""

    editor_protocol: EditorProtocol = Field(
        default=EditorProtocol.VSCODE, description="Editor protocol for source links"
    )
    anki_url: str = Field(default="http://localhost:8765", description="AnkiConnect URL")
    default_deck: str = Field(default="Default", description="Default Anki deck name")
    default_tags: List[str] = Field(
        default_factory=lambda: ["mnmd"], description="Default tags for cards"
    )

    @classmethod
    def load_from_file(cls, config_path: Path) -> "Config":
        """Load configuration from a YAML file.

        Args:
            config_path: Path to configuration file

        Returns:
            Config object

        Raises:
            ConfigError: If config file is invalid
        """
        if not config_path.exists():
            raise ConfigError(f"Config file not found: {config_path}")

        try:
            with open(config_path, "r", encoding="utf-8") as f:
                data = yaml.safe_load(f)

            if data is None:
                data = {}

            return cls(**data)
        except yaml.YAMLError as e:
            raise ConfigError(f"Invalid YAML in config file: {e}") from e
        except Exception as e:
            raise ConfigError(f"Error loading config: {e}") from e

    @classmethod
    def load_default(cls) -> "Config":
        """Load default configuration, optionally from ~/.mnmdrc.

        Returns:
            Config object
        """
        config_path = Path.home() / ".mnmdrc"
        if config_path.exists():
            try:
                return cls.load_from_file(config_path)
            except ConfigError as e:
                # Warn user that their config file is invalid
                print(
                    f"Warning: Invalid config file {config_path}: {e}\n"
                    "Using default configuration.",
                    file=sys.stderr,
                )

        return cls()

    def build_source_link(self, file_path: Path, line_number: int) -> str:
        """Build a source link using the configured editor protocol.

        Args:
            file_path: Path to source file
            line_number: Line number in file

        Returns:
            HTML link to open file in editor
        """
        absolute_path = file_path.resolve()

        if self.editor_protocol == EditorProtocol.VSCODE:
            url = f"vscode://file{absolute_path}:{line_number}:1"
            text = "Open in VS Code"
        elif self.editor_protocol == EditorProtocol.VSCODIUM:
            url = f"vscodium://file{absolute_path}:{line_number}:1"
            text = "Open in VSCodium"
        elif self.editor_protocol == EditorProtocol.NVIM:
            # Note: nvim:// requires custom protocol handler setup
            # See EDITOR_SETUP.md for registration instructions
            url = f"nvim://open?file={absolute_path}&line={line_number}"
            text = "Open in Neovim"
        elif self.editor_protocol == EditorProtocol.OBSIDIAN:
            url = f"obsidian://open?path={absolute_path}"
            text = "Open in Obsidian"
        elif self.editor_protocol == EditorProtocol.FILE:
            # Generic file:// protocol - opens with system default handler
            url = f"file://{absolute_path}"
            text = "Open File"
        else:
            # Fallback
            url = f"file://{absolute_path}"
            text = "Open File"

        # HTML-escape the URL and text to prevent injection
        escaped_url = html.escape(url, quote=True)
        escaped_text = html.escape(text)

        return f'<a href="{escaped_url}">{escaped_text}</a>'
