"""DuckDB translation storage."""

from pathlib import Path

import duckdb


_SCHEMA_V2 = """
CREATE TABLE IF NOT EXISTS translations (
    source_text          TEXT NOT NULL,
    source_lang          TEXT NOT NULL,
    target_lang          TEXT NOT NULL,
    project_context_hash TEXT NOT NULL,
    string_context_hash  TEXT NOT NULL,
    plural_category      TEXT NOT NULL DEFAULT '',
    translated_text      TEXT NOT NULL,
    model                TEXT NOT NULL,
    status               TEXT NOT NULL DEFAULT 'translated',
    created_at           TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY(source_text, source_lang, target_lang, project_context_hash, string_context_hash, plural_category)
);
"""

_MIGRATION_V1_TO_V2 = """
CREATE TABLE translations_v2 (
    source_text          TEXT NOT NULL,
    source_lang          TEXT NOT NULL,
    target_lang          TEXT NOT NULL,
    project_context_hash TEXT NOT NULL,
    string_context_hash  TEXT NOT NULL,
    plural_category      TEXT NOT NULL DEFAULT '',
    translated_text      TEXT NOT NULL,
    model                TEXT NOT NULL,
    status               TEXT NOT NULL DEFAULT 'translated',
    created_at           TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY(source_text, source_lang, target_lang, project_context_hash, string_context_hash, plural_category)
);
INSERT INTO translations_v2
    SELECT source_text, source_lang, target_lang, project_context_hash,
           string_context_hash, '' as plural_category, translated_text,
           model, status, created_at
    FROM translations;
DROP TABLE translations;
ALTER TABLE translations_v2 RENAME TO translations;
"""

_LOOKUP_SQL = """
SELECT translated_text FROM translations
WHERE source_text = ? AND source_lang = ? AND target_lang = ?
  AND project_context_hash = ? AND string_context_hash = ?
  AND plural_category = '' AND status = 'translated'
"""

_INSERT_SQL = """
INSERT INTO translations
    (source_text, source_lang, target_lang, project_context_hash,
     string_context_hash, plural_category, translated_text, model, status)
VALUES (?, ?, ?, ?, ?, '', ?, ?, ?)
ON CONFLICT DO NOTHING
"""

_LOOKUP_PLURAL_SQL = """
SELECT plural_category, translated_text FROM translations
WHERE source_text = ? AND source_lang = ? AND target_lang = ?
  AND project_context_hash = ? AND string_context_hash = ?
  AND plural_category != '' AND status = 'translated'
"""

_INSERT_PLURAL_SQL = """
INSERT INTO translations
    (source_text, source_lang, target_lang, project_context_hash,
     string_context_hash, plural_category, translated_text, model, status)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT DO NOTHING
"""

_STATS_TOTAL = "SELECT count(*) FROM translations WHERE status = 'translated'"
_STATS_FAILED = "SELECT count(*) FROM translations WHERE status = 'failed'"
_STATS_BY_LANG = """
SELECT target_lang, count(*) FROM translations
WHERE status = 'translated' GROUP BY target_lang
"""

_CHECK_PLURAL_COLUMN = """
SELECT column_name FROM information_schema.columns
WHERE table_name = 'translations' AND column_name = 'plural_category'
"""


class TranslationStore:
    def __init__(self, db_path: Path):
        self._db_path = db_path
        try:
            self._conn = duckdb.connect(str(db_path))
        except duckdb.IOException as e:
            if "lock" in str(e).lower():
                raise RuntimeError(
                    f"Cannot open {db_path} — it is locked by another process. "
                    f"Stop any running apps (e.g., Flask, Django) that use this database, then try again."
                ) from None
            raise

    def initialize(self):
        # Check if table exists
        tables = self._conn.execute(
            "SELECT table_name FROM information_schema.tables WHERE table_name = 'translations'"
        ).fetchall()

        if not tables:
            # Fresh database — create v2 schema
            self._conn.execute(_SCHEMA_V2)
            return

        # Table exists — check if it has plural_category (v2)
        has_plural = self._conn.execute(_CHECK_PLURAL_COLUMN).fetchall()
        if not has_plural:
            # Migrate from v1 to v2
            self._conn.execute(_MIGRATION_V1_TO_V2)

    def lookup(
        self,
        source_text: str,
        source_lang: str,
        target_lang: str,
        project_context_hash: str,
        string_context_hash: str,
    ) -> str | None:
        result = self._conn.execute(
            _LOOKUP_SQL,
            [source_text, source_lang, target_lang, project_context_hash, string_context_hash],
        ).fetchone()
        return result[0] if result else None

    def insert(
        self,
        source_text: str,
        source_lang: str,
        target_lang: str,
        project_context_hash: str,
        string_context_hash: str,
        translated_text: str,
        model: str,
        status: str = "translated",
    ):
        self._conn.execute(
            _INSERT_SQL,
            [source_text, source_lang, target_lang, project_context_hash,
             string_context_hash, translated_text, model, status],
        )

    def lookup_plural(
        self,
        source_text: str,
        source_lang: str,
        target_lang: str,
        project_context_hash: str,
        string_context_hash: str,
    ) -> dict[str, str]:
        rows = self._conn.execute(
            _LOOKUP_PLURAL_SQL,
            [source_text, source_lang, target_lang, project_context_hash, string_context_hash],
        ).fetchall()
        return {row[0]: row[1] for row in rows}

    def insert_plural(
        self,
        source_text: str,
        source_lang: str,
        target_lang: str,
        project_context_hash: str,
        string_context_hash: str,
        plural_category: str,
        translated_text: str,
        model: str,
        status: str = "translated",
    ):
        self._conn.execute(
            _INSERT_PLURAL_SQL,
            [source_text, source_lang, target_lang, project_context_hash,
             string_context_hash, plural_category, translated_text, model, status],
        )

    def query(self, sql: str, params: list | None = None):
        return self._conn.execute(sql, params or []).fetchall()

    def stats(self) -> dict:
        total = self._conn.execute(_STATS_TOTAL).fetchone()[0]
        failed = self._conn.execute(_STATS_FAILED).fetchone()[0]
        by_lang_rows = self._conn.execute(_STATS_BY_LANG).fetchall()
        by_language = {row[0]: row[1] for row in by_lang_rows}
        return {
            "total_translations": total,
            "total_failed": failed,
            "by_language": by_language,
        }

    def close(self):
        self._conn.close()
