"""
Tests for the enrichment overlay (plan Part B) and the new filter axes /
bilingual display helpers (plan Part A).

Covers:
  * config_taxonomy.normalize_indoor_outdoor / normalize_space_needed
  * build_database.apply_enrichment keying, field application, estimated tally
  * DatabaseManager indoor_outdoor / space_needed equality filters
  * FTS5 indexing of the *_ro columns
  * Activity bilingual display helpers
"""

import os
import sys

import pytest

PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
if PROJECT_ROOT not in sys.path:
    sys.path.insert(0, PROJECT_ROOT)
SCRIPTS = os.path.join(PROJECT_ROOT, "scripts")
if SCRIPTS not in sys.path:
    sys.path.insert(0, SCRIPTS)

from app.models.activity import Activity  # noqa: E402
from app.models.database import DatabaseManager  # noqa: E402
from app.config_taxonomy import (  # noqa: E402
    normalize_indoor_outdoor,
    normalize_space_needed,
)
from import_common import content_key, normalize_name  # noqa: E402
from build_database import apply_enrichment  # noqa: E402


# --------------------------------------------------------------------------
# taxonomy normalizers
# --------------------------------------------------------------------------
@pytest.mark.parametrize("raw,expected", [
    ("indoor", "indoor"),
    ("Outdoor", "outdoor"),
    ("either", "either"),
    ("interior", "indoor"),
    ("aer liber", "outdoor"),
    ("both", "either"),
    ("", None),
    ("nonsense", None),
    (None, None),
])
def test_normalize_indoor_outdoor(raw, expected):
    assert normalize_indoor_outdoor(raw) == expected


@pytest.mark.parametrize("raw,expected", [
    ("mic", "mic"),
    ("MEDIU", "mediu"),
    ("mare", "mare"),
    ("small", "mic"),
    ("large", "mare"),
    ("", None),
    ("huge", None),
    (None, None),
])
def test_normalize_space_needed(raw, expected):
    assert normalize_space_needed(raw) == expected


# --------------------------------------------------------------------------
# apply_enrichment
# --------------------------------------------------------------------------
def _activity(name="Joc de test", description="O descriere de test.", language="ro"):
    return Activity(
        name=name, description=description, category="team-building",
        content_type="joc", source_file="t.txt", language=language,
    )


def _key_for(act: Activity) -> str:
    return content_key(
        act.normalized_name or normalize_name(act.name),
        act.language,
        act.description or "",
    )


def test_apply_enrichment_matches_and_applies_fields():
    act = _activity()
    key = _key_for(act)
    enrichment = {
        key: {
            "name_ro": "Joc de test (RO)",
            "description_ro": "Descriere îmbogățită în română.",
            "indoor_outdoor": "outdoor",
            "space_needed": "mediu",
            "participants_min": 4,
            "participants_max": 12,
            "estimated_fields": ["space_needed", "participants_min", "participants_max"],
        }
    }
    stats = apply_enrichment([act], enrichment)

    assert act.name_ro == "Joc de test (RO)"
    assert act.description_ro == "Descriere îmbogățită în română."
    assert act.indoor_outdoor == "outdoor"
    assert act.space_needed == "mediu"
    assert act.participants_min == 4 and act.participants_max == 12
    assert set(act.estimated_fields) == {"space_needed", "participants_min", "participants_max"}

    assert stats["entries"] == 1
    assert stats["matched"] == 1
    assert stats["orphaned"] == 0
    # indoor_outdoor stated, space_needed estimated
    assert stats["fields_stated"].get("indoor_outdoor") == 1
    assert stats["fields_estimated"].get("space_needed") == 1


def test_apply_enrichment_orphan_entry_counted():
    act = _activity()
    enrichment = {"deadbeef" * 5: {"name_ro": "nu se potrivește"}}
    stats = apply_enrichment([act], enrichment)
    assert stats["matched"] == 0
    assert stats["orphaned"] == 1
    assert act.name_ro is None  # untouched


def test_apply_enrichment_absent_fields_leave_value_untouched():
    act = _activity()
    act.participants_min = 5
    key = _key_for(act)
    # entry only translates name; participants must be preserved
    apply_enrichment([act], {key: {"name_ro": "Tradus"}})
    assert act.participants_min == 5
    assert act.name_ro == "Tradus"


def test_apply_enrichment_drops_unrecognised_enum():
    act = _activity()
    key = _key_for(act)
    apply_enrichment([act], {key: {"indoor_outdoor": "spaceship", "space_needed": "mic"}})
    assert act.indoor_outdoor is None       # unrecognised → dropped
    assert act.space_needed == "mic"


# --------------------------------------------------------------------------
# DB equality filters + FTS on *_ro
# --------------------------------------------------------------------------
@pytest.fixture
def db(tmp_path):
    return DatabaseManager(str(tmp_path / "enrich.db"))


def _insert(db, **overrides):
    base = dict(
        name="Activitate", description="desc", category="camp-outdoor",
        content_type="joc", source_file="t.txt", language="ro",
    )
    base.update(overrides)
    return db.insert_activity(Activity(**base))


def test_indoor_outdoor_equality_filter(db):
    _insert(db, name="In casa", indoor_outdoor="indoor")
    _insert(db, name="Afara", indoor_outdoor="outdoor")
    res = db.search_activities(indoor_outdoor="outdoor")
    assert len(res) == 1
    assert res[0]["name"] == "Afara"


def test_space_needed_equality_filter(db):
    _insert(db, name="Mic", space_needed="mic")
    _insert(db, name="Mare", space_needed="mare")
    res = db.search_activities(space_needed="mare")
    assert len(res) == 1
    assert res[0]["name"] == "Mare"


def test_fts_indexes_name_ro(db):
    _insert(db, name="Treasure Hunt", name_ro="Vânătoarea de comori")
    # term only present in the Romanian twin
    res = db.search_activities(search_text="comori")
    assert len(res) == 1
    assert res[0]["name"] == "Treasure Hunt"


def test_fts_indexes_description_ro(db):
    _insert(db, name="Game", description="english desc",
            description_ro="o activitate de cooperare")
    res = db.search_activities(search_text="cooperare")
    assert len(res) == 1


def test_ro_columns_round_trip(db):
    aid = _insert(
        db, name="X", name_ro="X-ro", description_ro="d-ro",
        rules_ro="r-ro", variations_ro="v-ro",
        indoor_outdoor="either", space_needed="mediu",
        estimated_fields=["duration_min"], source_id="src1",
        source_ids=["src1", "src2"], chunk_key="src1.part01",
    )
    row = db.get_activity_by_id(aid)
    loaded = Activity.from_dict(row)
    assert loaded.name_ro == "X-ro"
    assert loaded.indoor_outdoor == "either"
    assert loaded.space_needed == "mediu"
    assert loaded.estimated_fields == ["duration_min"]
    assert loaded.source_ids == ["src1", "src2"]
    assert loaded.chunk_key == "src1.part01"


# --------------------------------------------------------------------------
# display helpers
# --------------------------------------------------------------------------
def test_display_helpers_prefer_ro_with_fallback():
    act = _activity(name="Original", description="Original desc")
    assert act.get_display_name() == "Original"          # no translation yet
    assert act.get_display_description() == "Original desc"
    act.name_ro = "Tradus"
    act.description_ro = "Descriere tradusă"
    assert act.get_display_name() == "Tradus"
    assert act.get_display_description() == "Descriere tradusă"
    assert act.has_translation() is True


def test_is_estimated_and_axis_displays():
    act = _activity()
    act.indoor_outdoor = "outdoor"
    act.space_needed = "mare"
    act.estimated_fields = ["space_needed"]
    assert act.get_indoor_outdoor_display() == "Exterior"
    assert act.get_space_needed_display() == "Spațiu mare"
    assert act.is_estimated("space_needed") is True
    assert act.is_estimated("indoor_outdoor") is False
