"""YAML configuration repository implementation."""

from __future__ import annotations

import asyncio
from pathlib import Path
from typing import TYPE_CHECKING, Any

import yaml

if TYPE_CHECKING:
    from portal.core.domain.models.config import PortalConfig
    from portal.core.domain.models.template import WorktreeTemplate


class YamlConfigRepository:
    """Repository for loading/saving YAML configuration."""

    def __init__(self) -> None:
        self.global_config_path = Path.home() / ".portal" / "config.yml"
        self.project_config_name = ".portal.yml"
        self._cache: PortalConfig | None = None

    async def load_config(self, project_path: Path | None = None) -> PortalConfig:
        """Load merged configuration from all sources."""
        from portal.core.domain.models.config import PortalConfig

        # Start with defaults
        config_dict = self._get_default_config()

        # Merge global config if exists
        if self.global_config_path.exists():
            global_config = await self._load_yaml_file(self.global_config_path)
            config_dict = self._merge_configs(config_dict, global_config)

        # Merge project config if exists
        if project_path:
            project_config_path = project_path / self.project_config_name
            if project_config_path.exists():
                project_config = await self._load_yaml_file(project_config_path)
                config_dict = self._merge_configs(config_dict, project_config)

        # Create and validate config model
        config = PortalConfig.model_validate(config_dict)
        self._cache = config
        return config

    async def save_global_config(self, config: PortalConfig) -> None:
        """Save global configuration."""
        self.global_config_path.parent.mkdir(parents=True, exist_ok=True)

        # Convert to dict, excluding defaults
        config_dict = config.model_dump(exclude_defaults=True, exclude_none=True)

        await self._save_yaml_file(self.global_config_path, config_dict)
        self._cache = None  # Invalidate cache

    async def save_project_config(self, project_path: Path, config: dict[str, Any]) -> None:
        """Save project-specific configuration."""
        config_path = project_path / self.project_config_name

        # Only save project-specific overrides
        await self._save_yaml_file(config_path, config)
        self._cache = None  # Invalidate cache

    async def load_template(self, template_name: str) -> WorktreeTemplate | None:
        """Load a worktree template."""
        from portal.core.domain.models.template import WorktreeTemplate

        # Check project templates first
        project_template_path = Path.cwd() / ".portal" / "templates" / f"{template_name}.yml"
        if project_template_path.exists():
            data = await self._load_yaml_file(project_template_path)
            return WorktreeTemplate.model_validate(data)

        # Check global templates
        global_template_path = Path.home() / ".portal" / "templates" / f"{template_name}.yml"
        if global_template_path.exists():
            data = await self._load_yaml_file(global_template_path)
            return WorktreeTemplate.model_validate(data)

        return None

    async def list_templates(self) -> list[str]:
        """List available template names."""
        templates = set()

        # Global templates
        global_template_dir = Path.home() / ".portal" / "templates"
        if global_template_dir.exists():
            for path in global_template_dir.glob("*.yml"):
                templates.add(path.stem)

        # Project templates
        project_template_dir = Path.cwd() / ".portal" / "templates"
        if project_template_dir.exists():
            for path in project_template_dir.glob("*.yml"):
                templates.add(path.stem)

        return sorted(templates)

    async def _load_yaml_file(self, path: Path) -> dict[str, Any]:
        """Load YAML file asynchronously."""

        def load_sync() -> dict[str, Any]:
            with open(path, encoding="utf-8") as f:
                return yaml.safe_load(f) or {}

        return await asyncio.to_thread(load_sync)

    async def _save_yaml_file(self, path: Path, data: dict[str, Any]) -> None:
        """Save YAML file asynchronously."""

        def save_sync() -> None:
            path.parent.mkdir(parents=True, exist_ok=True)
            with open(path, "w", encoding="utf-8") as f:
                yaml.dump(data, f, default_flow_style=False, sort_keys=False)

        await asyncio.to_thread(save_sync)

    def _get_default_config(self) -> dict[str, Any]:
        """Get default configuration."""
        return {
            "version": "1.0",
            "base_dir": "../{project}_worktrees",
            "colors": {
                "enabled": True,
                "sync_iterm": True,
                "sync_cursor": True,
                "sync_claude": True,
                "high_contrast": False,
            },
            "editor": {"default": "cursor", "auto_open": True},
            "shell": {
                "completions_enabled": True,
                "cd_function": True,
                "prompt_integration": False,
            },
            "branch_patterns": {
                "feature/*": "feature",
                "hotfix/*": "hotfix",
                "release/*": "release",
                "bugfix/*": "bugfix",
            },
        }

    def _merge_configs(self, base: dict[str, Any], override: dict[str, Any]) -> dict[str, Any]:
        """Deep merge configuration dictionaries."""
        result = base.copy()

        for key, value in override.items():
            if key in result and isinstance(result[key], dict) and isinstance(value, dict):
                result[key] = self._merge_configs(result[key], value)
            else:
                result[key] = value

        return result
