"""
Translation Dictionary Loader

Loads and parses translation dictionaries from project .dss directory.
"""

import json
from pathlib import Path
from typing import Dict, List, Optional, Union

from .models import TranslationDictionary, TranslationRegistry, TranslationSource
from .validator import TranslationValidator


class TranslationDictionaryLoader:
    """
    Loads translation dictionaries from project .dss/translations/ directory.

    Usage:
        loader = TranslationDictionaryLoader("/path/to/project")
        registry = await loader.load_all()

        # Or load specific dictionary
        figma_dict = await loader.load_dictionary("figma")
    """

    DEFAULT_DIR = ".dss/translations"

    def __init__(
        self, project_path: Union[str, Path], translations_dir: Optional[str] = None, validate: bool = True
    ):
        """
        Initialize loader.

        Args:
            project_path: Root path to project
            translations_dir: Custom translations directory (default: .dss/translations)
            validate: Whether to validate dictionaries on load
        """
        self.project_path = Path(project_path).resolve()
        translations_subdir = translations_dir or self.DEFAULT_DIR
        self.translations_dir = self._validate_safe_path(self.project_path / translations_subdir)
        self.validate = validate
        self.validator = TranslationValidator() if validate else None

    def _validate_safe_path(self, path: Path) -> Path:
        """
        Validate that path is within project directory (prevent path traversal).

        Args:
            path: Path to validate

        Returns:
            Validated path

        Raises:
            ValueError: If path is outside project directory
        """
        resolved = path.resolve()
        try:
            resolved.relative_to(self.project_path)
            return resolved
        except ValueError:
            raise ValueError(f"Path {path} is outside project directory {self.project_path}")

    async def load_all(self) -> TranslationRegistry:
        """
        Load all translation dictionaries from project.

        Returns:
            TranslationRegistry with all loaded dictionaries
        """
        registry = TranslationRegistry()

        if not self.translations_dir.exists():
            return registry

        for json_file in self.translations_dir.glob("*.json"):
            try:
                dictionary = await self.load_dictionary_file(json_file)
                if dictionary:
                    registry.dictionaries[dictionary.source.value] = dictionary
                    self._merge_to_registry(registry, dictionary)
            except Exception as e:
                # Log error but continue loading other dictionaries
                registry.conflicts.append(
                    {"file": str(json_file), "error": str(e), "type": "load_error"}
                )

        return registry

    async def load_dictionary(
        self, source: Union[str, TranslationSource]
    ) -> Optional[TranslationDictionary]:
        """
        Load a specific translation dictionary by source type.

        Args:
            source: Source type (e.g., "figma", "css", TranslationSource.FIGMA)

        Returns:
            TranslationDictionary or None if not found
        """
        if isinstance(source, str):
            source = TranslationSource(source)

        file_path = self.translations_dir / f"{source.value}.json"
        if not file_path.exists():
            return None

        return await self.load_dictionary_file(file_path)

    async def load_dictionary_file(
        self, file_path: Union[str, Path]
    ) -> Optional[TranslationDictionary]:
        """
        Load a translation dictionary from a specific file.

        Args:
            file_path: Path to JSON file

        Returns:
            TranslationDictionary or None if invalid
        """
        file_path = Path(file_path)
        if not file_path.exists():
            raise FileNotFoundError(f"Dictionary file not found: {file_path}")

        with open(file_path, "r", encoding="utf-8") as f:
            data = json.load(f)

        # Validate if enabled
        if self.validator:
            validation_result = self.validator.validate_dictionary(data)
            if not validation_result.is_valid:
                raise ValueError(
                    f"Invalid dictionary {file_path}: "
                    f"{[str(e) for e in validation_result.errors]}"
                )

        return TranslationDictionary(**data)

    def _merge_to_registry(self, registry: TranslationRegistry, dictionary: TranslationDictionary) -> None:
        """Merge dictionary mappings into registry."""
        # Merge token mappings
        for source_token, dss_token in dictionary.mappings.tokens.items():
            if source_token in registry.combined_token_map:
                existing = registry.combined_token_map[source_token]
                if existing != dss_token:
                    registry.conflicts.append(
                        {
                            "type": "token_conflict",
                            "source_token": source_token,
                            "existing_mapping": existing,
                            "new_mapping": dss_token,
                            "source": dictionary.source.value,
                        }
                    )
                    continue
            registry.combined_token_map[source_token] = dss_token

        # Merge component mappings
        for source_comp, dss_comp in dictionary.mappings.components.items():
            if source_comp in registry.combined_component_map:
                existing = registry.combined_component_map[source_comp]
                if existing != dss_comp:
                    registry.conflicts.append(
                        {
                            "type": "component_conflict",
                            "source_component": source_comp,
                            "existing_mapping": existing,
                            "new_mapping": dss_comp,
                            "source": dictionary.source.value,
                        }
                    )
                    continue
            registry.combined_component_map[source_comp] = dss_comp

        # Merge custom props
        for prop_name, prop_value in dictionary.custom_props.items():
            if prop_name in registry.all_custom_props:
                existing = registry.all_custom_props[prop_name]
                if existing != prop_value:
                    registry.conflicts.append(
                        {
                            "type": "custom_prop_conflict",
                            "prop_name": prop_name,
                            "existing_value": existing,
                            "new_value": prop_value,
                            "source": dictionary.source.value,
                        }
                    )
                    continue
            registry.all_custom_props[prop_name] = prop_value

    def get_translations_dir(self) -> Path:
        """Get the translations directory path."""
        return self.translations_dir

    def has_translations(self) -> bool:
        """Check if project has any translation dictionaries."""
        if not self.translations_dir.exists():
            return False
        return any(self.translations_dir.glob("*.json"))

    def list_available_dictionaries(self) -> List[str]:
        """List available dictionary source types."""
        if not self.translations_dir.exists():
            return []
        return [f.stem for f in self.translations_dir.glob("*.json")]
