"""Translation exporter for pytlai."""

from __future__ import annotations

import csv
import json
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Literal


class TranslationExporter:
    """Export translations to various file formats.

    Supports exporting to JSON, YAML, PO (gettext), and CSV formats.
    Useful for creating offline translation files that can be shipped
    with applications.

    Example:
        >>> exporter = TranslationExporter()
        >>> exporter.export(
        ...     translations={"hash1": {"source": "Hello", "target": "Hola"}},
        ...     output_path="locale/es_ES.json",
        ...     source_lang="en",
        ...     target_lang="es_ES",
        ... )
    """

    def export(
        self,
        translations: dict[str, dict[str, str]],
        output_path: str | Path,
        source_lang: str = "en",
        target_lang: str = "unknown",
        file_format: Literal["json", "yaml", "po", "csv"] | None = None,
        metadata: dict[str, Any] | None = None,
    ) -> Path:
        """Export translations to a file.

        Args:
            translations: Dictionary mapping hash keys to translation entries.
                Each entry should have 'source' and 'target' keys.
            output_path: Path to the output file.
            source_lang: Source language code.
            target_lang: Target language code.
            file_format: Output format. If None, detected from extension.
            metadata: Additional metadata to include in the file.

        Returns:
            Path to the created file.

        Raises:
            ValueError: If format is not supported.
        """
        path = Path(output_path)

        # Detect format from extension if not specified
        if file_format is None:
            ext = path.suffix.lower()
            format_map = {
                ".json": "json",
                ".yaml": "yaml",
                ".yml": "yaml",
                ".po": "po",
                ".pot": "po",
                ".csv": "csv",
            }
            file_format = format_map.get(ext)
            if not file_format:
                raise ValueError(f"Cannot determine format for extension: {ext}")

        # Ensure parent directory exists
        path.parent.mkdir(parents=True, exist_ok=True)

        # Build metadata
        meta = {
            "source_lang": source_lang,
            "target_lang": target_lang,
            "generated": datetime.now(timezone.utc).isoformat(),
            "version": "1.0",
            "generator": "pytlai",
        }
        if metadata:
            meta.update(metadata)

        # Export based on format
        if file_format == "json":
            self._export_json(path, translations, meta)
        elif file_format == "yaml":
            self._export_yaml(path, translations, meta)
        elif file_format == "po":
            self._export_po(path, translations, meta)
        elif file_format == "csv":
            self._export_csv(path, translations, meta)
        else:
            raise ValueError(f"Unsupported format: {file_format}")

        return path

    def _export_json(
        self,
        path: Path,
        translations: dict[str, dict[str, str]],
        meta: dict[str, Any],
    ) -> None:
        """Export to JSON format."""
        data = {
            "meta": meta,
            "translations": translations,
        }

        with open(path, "w", encoding="utf-8") as f:
            json.dump(data, f, ensure_ascii=False, indent=2)

    def _export_yaml(
        self,
        path: Path,
        translations: dict[str, dict[str, str]],
        meta: dict[str, Any],
    ) -> None:
        """Export to YAML format."""
        try:
            import yaml
        except ImportError as e:
            raise ImportError(
                "YAML export requires the 'pyyaml' package. "
                "Install it with: pip install pytlai[yaml]"
            ) from e

        data = {
            "meta": meta,
            "translations": translations,
        }

        with open(path, "w", encoding="utf-8") as f:
            yaml.dump(data, f, allow_unicode=True, default_flow_style=False, sort_keys=False)

    def _export_po(
        self,
        path: Path,
        translations: dict[str, dict[str, str]],
        meta: dict[str, Any],
    ) -> None:
        """Export to PO (gettext) format."""
        lines = [
            "# Translation file generated by pytlai",
            f"# Source: {meta.get('source_lang', 'en')}",
            f"# Target: {meta.get('target_lang', 'unknown')}",
            f"# Generated: {meta.get('generated', '')}",
            "",
            'msgid ""',
            'msgstr ""',
            f'"Content-Type: text/plain; charset=UTF-8\\n"',
            f'"Language: {meta.get("target_lang", "")}\\n"',
            f'"Generated-By: pytlai\\n"',
            "",
        ]

        for hash_key, entry in translations.items():
            source = entry.get("source", "")
            target = entry.get("target", "")

            if not source:
                continue

            # Add hash as comment for reference
            lines.append(f"#. hash: {hash_key}")

            # Handle multi-line strings
            if "\n" in source:
                lines.append('msgid ""')
                for line in source.split("\n"):
                    lines.append(f'"{self._escape_po(line)}\\n"')
            else:
                lines.append(f'msgid "{self._escape_po(source)}"')

            if "\n" in target:
                lines.append('msgstr ""')
                for line in target.split("\n"):
                    lines.append(f'"{self._escape_po(line)}\\n"')
            else:
                lines.append(f'msgstr "{self._escape_po(target)}"')

            lines.append("")

        with open(path, "w", encoding="utf-8") as f:
            f.write("\n".join(lines))

    def _export_csv(
        self,
        path: Path,
        translations: dict[str, dict[str, str]],
        meta: dict[str, Any],
    ) -> None:
        """Export to CSV format."""
        with open(path, "w", encoding="utf-8", newline="") as f:
            writer = csv.writer(f)

            # Write header
            writer.writerow(["hash", "source", "target"])

            # Write translations
            for hash_key, entry in translations.items():
                writer.writerow([
                    hash_key,
                    entry.get("source", ""),
                    entry.get("target", ""),
                ])

    def _escape_po(self, s: str) -> str:
        """Escape a string for PO format."""
        return s.replace("\\", "\\\\").replace('"', '\\"').replace("\n", "\\n")

    def export_from_cache(
        self,
        cache: Any,
        output_path: str | Path,
        source_lang: str = "en",
        target_lang: str = "unknown",
        file_format: Literal["json", "yaml", "po", "csv"] | None = None,
    ) -> Path:
        """Export translations directly from a cache object.

        This method extracts translations from a cache that stores
        source text alongside translations (like FileCache).

        Args:
            cache: A cache object with _cache and _sources attributes.
            output_path: Path to the output file.
            source_lang: Source language code.
            target_lang: Target language code.
            file_format: Output format.

        Returns:
            Path to the created file.
        """
        translations: dict[str, dict[str, str]] = {}

        # Extract from cache
        cache_data = getattr(cache, "_cache", {})
        sources = getattr(cache, "_sources", {})

        for key, target in cache_data.items():
            # Key format is hash:lang, extract hash
            hash_key = key.split(":")[0] if ":" in key else key
            source = sources.get(key, "")

            translations[hash_key] = {
                "source": source,
                "target": target,
            }

        return self.export(
            translations=translations,
            output_path=output_path,
            source_lang=source_lang,
            target_lang=target_lang,
            file_format=file_format,
        )
