"""
Tier 1 E2E Tests: 2-Way Town Portal Engine, 6-Portal Map Charges,
Boss & Secret Chamber Quarantines, Death Penalty, and Game Design Matrix DB (R4, R5).
"""

from __future__ import annotations
import sqlite3
from pathlib import Path
import pytest
from tests.e2e_social_party.test_harness import TownPortalEngine


@pytest.fixture
def portal_engine() -> TownPortalEngine:
    return TownPortalEngine()


@pytest.fixture
def db_conn():
    db_path = Path("data/game_design_matrix.db")
    if db_path.exists():
        conn = sqlite3.connect(str(db_path))
    else:
        conn = sqlite3.connect(":memory:")
    yield conn
    conn.close()


class TestTier1TownPortalEngine:
    """Feature 12: 2-Way Town Portal Engine (Wilderness (wx, wy) linked to Hideout/Sanctuary)."""

    def test_town_portal_created_in_wilderness(self, portal_engine: TownPortalEngine) -> None:
        ok, msg, p_id = portal_engine.request_town_portal("hero_1", "zone_tang_kiem_nhai", "inst_w1", 120.0, 340.0)
        assert ok is True and p_id is not None
        portal = portal_engine.portals[p_id]
        assert portal["origin_zone"] == "zone_tang_kiem_nhai"
        assert portal["origin_x"] == 120.0 and portal["origin_y"] == 340.0

    def test_town_portal_links_to_player_hideout(self, portal_engine: TownPortalEngine) -> None:
        ok, _, p_id = portal_engine.request_town_portal("hero_1", "zone_tang_kiem_nhai", "inst_w1", 0.0, 0.0, hub_zone="zone_player_hideout")
        assert ok is True and portal_engine.portals[p_id]["hub_zone"] == "zone_player_hideout"

    def test_town_portal_links_to_sanctuary_hub(self, portal_engine: TownPortalEngine) -> None:
        ok, _, p_id = portal_engine.request_town_portal("hero_1", "zone_tang_kiem_nhai", "inst_w1", 0.0, 0.0, hub_zone="zone_boundless_sanctuary")
        assert ok is True and portal_engine.portals[p_id]["hub_zone"] == "zone_boundless_sanctuary"

    def test_town_portal_active_state(self, portal_engine: TownPortalEngine) -> None:
        _, _, p_id = portal_engine.request_town_portal("hero_1", "zone_wild", "inst_1", 10.0, 10.0)
        assert portal_engine.portals[p_id]["is_active"] is True

    def test_party_member_can_access_leader_portal(self, portal_engine: TownPortalEngine) -> None:
        _, _, p_id = portal_engine.request_town_portal("leader", "zone_wild", "inst_1", 50.0, 50.0)
        # Portals are accessible across party instances
        assert p_id in portal_engine.portals and portal_engine.portals[p_id]["is_active"] is True


class TestTier1SixPortalChargeSystem:
    """Feature 13: 6-Portal Map Charge System (Initial 6 charges, decrement on entry, seal at 0)."""

    def test_map_device_initializes_six_portals(self, portal_engine: TownPortalEngine) -> None:
        portal_engine.register_astral_map_device("map_t16_inst", initial_charges=6)
        assert portal_engine.map_charges["map_t16_inst"] == 6

    def test_map_portal_entry_consumes_one_charge(self, portal_engine: TownPortalEngine) -> None:
        portal_engine.register_astral_map_device("map_t16_inst", initial_charges=6)
        ok, _, remaining = portal_engine.enter_map_portal("map_t16_inst")
        assert ok is True and remaining == 5

    def test_map_portal_sequential_consumption_to_zero(self, portal_engine: TownPortalEngine) -> None:
        portal_engine.register_astral_map_device("map_t16_inst", initial_charges=6)
        for expected in [5, 4, 3, 2, 1, 0]:
            ok, _, remaining = portal_engine.enter_map_portal("map_t16_inst")
            assert ok is True and remaining == expected

    def test_map_device_sealed_at_zero_charges(self, portal_engine: TownPortalEngine) -> None:
        portal_engine.register_astral_map_device("map_t16_inst", initial_charges=6)
        for _ in range(6):
            portal_engine.enter_map_portal("map_t16_inst")
        ok, msg, remaining = portal_engine.enter_map_portal("map_t16_inst")
        assert ok is False and remaining == 0 and "MAP_SEALED" in msg

    def test_map_device_with_zero_initial_charges_rejected(self, portal_engine: TownPortalEngine) -> None:
        portal_engine.register_astral_map_device("empty_map", initial_charges=0)
        ok, msg, _ = portal_engine.enter_map_portal("empty_map")
        assert ok is False and "MAP_SEALED" in msg


class TestTier1BossEncounterLockout:
    """Feature 14: Anti-Exploit Boss Quarantine (Reject town portal & escape while boss is active)."""

    def test_town_portal_rejected_during_active_boss(self, portal_engine: TownPortalEngine) -> None:
        portal_engine.set_encounter_state("boss_inst_1", boss_active=True)
        ok, msg, p_id = portal_engine.request_town_portal("hero", "zone_boss_chamber", "boss_inst_1", 0.0, 0.0)
        assert ok is False and p_id is None
        assert "QUARANTINE_BOSS_ENGAGED" in msg

    def test_town_portal_permitted_after_boss_defeat(self, portal_engine: TownPortalEngine) -> None:
        portal_engine.set_encounter_state("boss_inst_1", boss_active=True)
        # Boss killed:
        portal_engine.set_encounter_state("boss_inst_1", boss_active=False)
        ok, _, p_id = portal_engine.request_town_portal("hero", "zone_boss_chamber", "boss_inst_1", 0.0, 0.0)
        assert ok is True and p_id is not None

    def test_boss_quarantine_lock_check_direct(self, portal_engine: TownPortalEngine) -> None:
        portal_engine.set_encounter_state("boss_inst_1", boss_active=True)
        locked, reason = portal_engine.check_quarantine_lock("zone_boss_chamber", "boss_inst_1")
        assert locked is True and "Boss" in reason

    def test_boss_quarantine_unlocked_when_inactive(self, portal_engine: TownPortalEngine) -> None:
        portal_engine.set_encounter_state("boss_inst_1", boss_active=False)
        locked, _ = portal_engine.check_quarantine_lock("zone_boss_chamber", "boss_inst_1")
        assert locked is False

    def test_boss_quarantine_instance_isolation(self, portal_engine: TownPortalEngine) -> None:
        portal_engine.set_encounter_state("boss_inst_1", boss_active=True)
        portal_engine.set_encounter_state("boss_inst_2", boss_active=False)
        assert portal_engine.check_quarantine_lock("zone_boss", "boss_inst_1")[0] is True
        assert portal_engine.check_quarantine_lock("zone_boss", "boss_inst_2")[0] is False


class TestTier1SecretChamberLockout:
    """Feature 15: Anti-Exploit Puzzle / Secret Chamber Quarantine."""

    def test_town_portal_rejected_in_secret_chamber(self, portal_engine: TownPortalEngine) -> None:
        portal_engine.set_encounter_state("secret_inst_1", secret_active=True)
        ok, msg, p_id = portal_engine.request_town_portal("hero", "zone_secret_chamber", "secret_inst_1", 0.0, 0.0)
        assert ok is False and p_id is None
        assert "QUARANTINE_SECRET_CHAMBER" in msg

    def test_town_portal_allowed_when_secret_chamber_cleared(self, portal_engine: TownPortalEngine) -> None:
        portal_engine.set_encounter_state("secret_inst_1", secret_active=True)
        portal_engine.set_encounter_state("secret_inst_1", secret_active=False)
        ok, _, p_id = portal_engine.request_town_portal("hero", "zone_secret_chamber", "secret_inst_1", 0.0, 0.0)
        assert ok is True and p_id is not None

    def test_secret_quarantine_check_direct(self, portal_engine: TownPortalEngine) -> None:
        portal_engine.set_encounter_state("secret_inst_1", secret_active=True)
        locked, reason = portal_engine.check_quarantine_lock("zone_secret", "secret_inst_1")
        assert locked is True and "Mật thất" in reason

    def test_simultaneous_boss_and_secret_quarantine(self, portal_engine: TownPortalEngine) -> None:
        portal_engine.set_encounter_state("double_lock_inst", boss_active=True, secret_active=True)
        locked, _ = portal_engine.check_quarantine_lock("zone_double", "double_lock_inst")
        assert locked is True

    def test_secret_chamber_instance_isolation(self, portal_engine: TownPortalEngine) -> None:
        portal_engine.set_encounter_state("secret_1", secret_active=True)
        portal_engine.set_encounter_state("secret_2", secret_active=False)
        assert portal_engine.check_quarantine_lock("zone_secret", "secret_1")[0] is True
        assert portal_engine.check_quarantine_lock("zone_secret", "secret_2")[0] is False


class TestTier1DeathPenaltyPortalHandling:
    """Feature 16: Death Penalty Portal Handling (Wilderness closes portal, Map consumes charge)."""

    def test_wilderness_death_closes_personal_portal(self, portal_engine: TownPortalEngine) -> None:
        _, _, p_id = portal_engine.request_town_portal("hero_1", "zone_wild", "inst_1", 0.0, 0.0)
        assert portal_engine.portals[p_id]["is_active"] is True
        portal_engine.on_player_death("hero_1", "zone_wild", "inst_1", is_map_instance=False)
        assert portal_engine.portals[p_id]["is_active"] is False

    def test_wilderness_death_does_not_close_others_portals(self, portal_engine: TownPortalEngine) -> None:
        _, _, p1 = portal_engine.request_town_portal("hero_1", "zone_wild", "inst_1", 0.0, 0.0)
        _, _, p2 = portal_engine.request_town_portal("hero_2", "zone_wild", "inst_1", 0.0, 0.0)
        portal_engine.on_player_death("hero_1", "zone_wild", "inst_1", is_map_instance=False)
        assert portal_engine.portals[p1]["is_active"] is False
        assert portal_engine.portals[p2]["is_active"] is True

    def test_map_instance_death_consumes_charge(self, portal_engine: TownPortalEngine) -> None:
        portal_engine.register_astral_map_device("map_inst", initial_charges=6)
        portal_engine.enter_map_portal("map_inst")  # 6 -> 5
        portal_engine.on_player_death("hero_1", "zone_map", "map_inst", is_map_instance=True)  # 5 -> 4
        assert portal_engine.map_charges["map_inst"] == 4

    def test_map_instance_multiple_deaths_exhaustion(self, portal_engine: TownPortalEngine) -> None:
        portal_engine.register_astral_map_device("hard_map", initial_charges=2)
        portal_engine.on_player_death("hero_1", "zone_map", "hard_map", is_map_instance=True)
        portal_engine.on_player_death("hero_2", "zone_map", "hard_map", is_map_instance=True)
        assert portal_engine.map_charges["hard_map"] == 0
        assert portal_engine.enter_map_portal("hard_map")[0] is False

    def test_wilderness_death_report_message(self, portal_engine: TownPortalEngine) -> None:
        portal_engine.request_town_portal("hero_1", "zone_wild", "inst_1", 0.0, 0.0)
        ok, msg = portal_engine.on_player_death("hero_1", "zone_wild", "inst_1", is_map_instance=False)
        assert ok is True and "WILDERNESS_DEATH" in msg


class TestTier1GameDesignMatrixSchema:
    """Feature 17: Game Design Matrix DB Tables (R5)."""

    def test_db_has_party_scaling_matrix_table(self, db_conn: sqlite3.Connection) -> None:
        tables = [r[0] for r in db_conn.execute("SELECT name FROM sqlite_master WHERE type='table'").fetchall()]
        assert "party_scaling_matrix" in tables

    def test_db_has_loot_allocation_modes_table(self, db_conn: sqlite3.Connection) -> None:
        tables = [r[0] for r in db_conn.execute("SELECT name FROM sqlite_master WHERE type='table'").fetchall()]
        assert "loot_allocation_modes" in tables

    def test_db_has_teleport_configs_table(self, db_conn: sqlite3.Connection) -> None:
        tables = [r[0] for r in db_conn.execute("SELECT name FROM sqlite_master WHERE type='table'").fetchall()]
        assert "teleport_configs" in tables

    def test_db_has_portal_quarantine_rules_table(self, db_conn: sqlite3.Connection) -> None:
        tables = [r[0] for r in db_conn.execute("SELECT name FROM sqlite_master WHERE type='table'").fetchall()]
        assert "portal_quarantine_rules" in tables

    def test_db_party_scaling_columns_integrity(self, db_conn: sqlite3.Connection) -> None:
        cols = [r[1] for r in db_conn.execute("PRAGMA table_info(party_scaling_matrix)").fetchall()]
        assert "party_size" in cols
        assert "exp_bonus_pct" in cols or "exp_multiplier" in cols or "description" in cols
