"""
Unit test suite for FreeExile Player Hideout (Tiên Phủ Động Thiên) & Waygate System.
Validates:
1. Hideout instantiation, themes, and private state persistence.
2. Astral Map Device 6-portal lifecycle (PoE2 model: open 6 portals, consume 1 by 1, auto-seal at 0).
3. World Exploration Waygate routing to 10 Canonical Open World Zones.
4. Quest & Bounty Portal synchronization with QuestEngine.
5. Domestic facility interactions (Stash, Alchemy, Meridian Mat, AI Altar).
"""

import pytest
from server.world.hideout_engine import (
    HideoutEngine,
    HideoutTheme,
    AstralMap,
    FacilityType,
    CANONICAL_ZONES,
)


@pytest.fixture
def engine() -> HideoutEngine:
    return HideoutEngine()


def test_hideout_creation_and_themes(engine: HideoutEngine) -> None:
    player_id = "hero_swordsman_01"
    h1 = engine.get_or_create_hideout(player_id, theme=HideoutTheme.BAMBOO_SHRINE)

    assert h1.owner_player_id == player_id
    assert h1.theme == HideoutTheme.BAMBOO_SHRINE
    assert h1.map_device.total_portals == 6
    assert h1.world_gate.is_active is True
    assert h1.quest_gate.is_active is True

    # Check persistence
    h2 = engine.get_or_create_hideout(player_id)
    assert h1.hideout_id == h2.hideout_id

    # Change theme
    ok, msg = engine.change_hideout_theme(player_id, HideoutTheme.LUNAR_SANCTUARY)
    assert ok is True
    assert h1.theme == HideoutTheme.LUNAR_SANCTUARY


def test_astral_map_device_activation_and_6_portals(engine: HideoutEngine) -> None:
    player_id = "hero_swordsman_01"
    astral_map = AstralMap(
        map_id="map_vong_xoay_u_minh",
        name="Vòng Xoáy U Minh Cổ Địa",
        tier=14,
        zone_template_id="zone_blood_scale_ruins",
        item_quantity_bonus_pct=45,
        item_rarity_bonus_pct=30,
        monster_pack_size_pct=25
    )

    ok, msg, portals = engine.activate_map_device(player_id, astral_map)
    assert ok is True
    assert len(portals) == 6
    assert "Tier 14" in msg

    # Verify hexagonal distribution
    for p in portals:
        assert p["is_open"] is True
        assert p["tier"] == 14
        assert p["color"] == "#a855f7"

    summary = engine.get_hideout_summary(player_id)
    assert summary["map_device"]["portals_remaining"] == 6
    assert summary["map_device"]["total_portals"] == 6
    assert summary["map_device"]["tier"] == 14


def test_astral_map_device_invalid_tier_rejection(engine: HideoutEngine) -> None:
    player_id = "hero_swordsman_01"
    invalid_map = AstralMap(
        map_id="map_invalid",
        name="Vực Thẳm Vô Cực",
        tier=25,  # Exceeds max 16
        zone_template_id="zone_boundless_sandstorm"
    )

    ok, msg, portals = engine.activate_map_device(player_id, invalid_map)
    assert ok is False
    assert len(portals) == 0
    assert "Tier 1-16" in msg


def test_map_portal_consumption_lifecycle(engine: HideoutEngine) -> None:
    player_id = "hero_swordsman_01"
    astral_map = AstralMap(
        map_id="map_t10_hoa_quat",
        name="Luyện Ngục Hoang Cổ Hỏa Quật",
        tier=10,
        zone_template_id="zone_purgatory_lava_cavern"
    )

    engine.activate_map_device(player_id, astral_map)

    # Enter portal 1
    ok1, msg1, res1 = engine.enter_map_portal(player_id)
    assert ok1 is True
    assert res1 is not None
    assert res1["portals_remaining"] == 5

    # Enter remaining 5 portals
    for i in range(4):
        ok, msg, res = engine.enter_map_portal(player_id)
        assert ok is True
        assert res is not None

    # Last portal (portal 6)
    ok_last, msg_last, res_last = engine.enter_map_portal(player_id)
    assert ok_last is True
    assert res_last is not None
    assert res_last["portals_remaining"] == 0
    assert "CỔNG CUỐI CÙNG" in msg_last

    # Verify device state when exhausted
    hideout = engine.get_or_create_hideout(player_id)
    assert hideout.map_device.active_map is None
    assert hideout.map_device.active_instance_id is None
    assert hideout.map_device.portals_remaining == 0

    # 7th attempt must be rejected (all 6 portals exhausted)
    ok_fail, msg_fail, res_fail = engine.enter_map_portal(player_id)
    assert ok_fail is False
    assert res_fail is None
    assert "0/6" in msg_fail


def test_world_gate_configuration(engine: HideoutEngine) -> None:
    player_id = "hero_swordsman_01"

    # Valid zone
    ok, msg, payload = engine.configure_world_gate(player_id, "zone_boundless_sandstorm")
    assert ok is True
    assert payload["target_zone_name"] == "Sa Cốt Hoang Mạc"
    assert payload["min_level"] == 20

    # Invalid zone
    ok_bad, msg_bad, _ = engine.configure_world_gate(player_id, "zone_fake_realm")
    assert ok_bad is False
    assert "không tồn tại" in msg_bad


def test_quest_gate_configuration(engine: HideoutEngine) -> None:
    player_id = "hero_swordsman_01"

    ok, msg, payload = engine.configure_quest_gate(
        player_id=player_id,
        quest_id="quest_story_02_hac_giao",
        quest_title="Trảm Diệt Hắc Giao",
        target_zone_id="zone_abyssal_ice_pond",
        objective_x=90.0,
        objective_y=180.0
    )
    assert ok is True
    assert payload["quest_title"] == "Trảm Diệt Hắc Giao"
    assert payload["target_zone_name"] == "Vực Đầm Băng Độc"
    assert payload["vortex_color"] == "#fbbf24"


def test_hideout_facilities_interaction(engine: HideoutEngine) -> None:
    player_id = "hero_swordsman_01"

    # Stash
    ok, msg, data = engine.interact_facility(player_id, FacilityType.CONSIGNMENT_STASH_VAULT)
    assert ok is True
    assert data["facility"] == "STASH"

    # Forge
    ok, msg, data = engine.interact_facility(player_id, FacilityType.PRIMAL_FORGE_CAULDRON)
    assert ok is True
    assert data["facility"] == "FORGE"

    # Meridian
    ok, msg, data = engine.interact_facility(player_id, FacilityType.MERIDIAN_MEDITATION_MAT)
    assert ok is True
    assert data["facility"] == "MERIDIAN"

    # AI Altar
    ok, msg, data = engine.interact_facility(player_id, FacilityType.AGENT_ORB_ALTAR)
    assert ok is True
    assert data["facility"] == "AGENT_ORB"

    # Map Device
    ok, msg, data = engine.interact_facility(player_id, FacilityType.ASTRAL_MAP_DEVICE)
    assert ok is True
    assert data["facility"] == "MAP_DEVICE"


def test_map_device_portal_exhaustion_cleans_zone_engine_session(engine: HideoutEngine) -> None:
    """Verifies that consuming all 6 portals purges InstanceSession from ZoneEngine and clears active_instance_id."""
    from server.world.zone_engine import ZoneEngine

    ze = ZoneEngine()
    player_id = "hero_swordsman_01"
    astral_map = AstralMap(
        map_id="map_t14_blood_scale",
        name="Vòng Xoáy U Minh Cổ Địa",
        tier=14,
        zone_template_id="zone_blood_scale_ruins"
    )

    ok, _, res = engine.create_map_instance_session(player_id, astral_map, zone_engine=ze)
    assert ok is True
    inst_id = res["instance_id"]
    assert inst_id in ze.active_instances

    # Enter first 5 portals with zone_engine
    for _ in range(5):
        ok_enter, _, _ = engine.enter_map_portal(player_id, zone_engine=ze)
        assert ok_enter is True
        assert inst_id in ze.active_instances

    # Enter 6th and final portal
    ok_final, msg_final, res_final = engine.enter_map_portal(player_id, zone_engine=ze)
    assert ok_final is True
    assert res_final is not None
    assert res_final["portals_remaining"] == 0
    assert "CỔNG CUỐI CÙNG" in msg_final

    # Assert instance unregistered from ZoneEngine and active_instance_id cleared
    assert inst_id not in ze.active_instances
    dev = engine.get_or_create_hideout(player_id).map_device
    assert dev.active_instance_id is None
    assert dev.active_map is None
    assert dev.portals_remaining == 0

