"""
Unit Test Suite for FreeExile Map Dungeon, Boss Arena, and Quest Integration.
Validates:
1. Canonical registration of expanded Map & Boss Room Quests (Norm 06-08, Hidden 05, Epic 05).
2. Quest progress recording: room exploration, fog clearance, obstacle destruction, and boss gate breaching.
3. End-to-end procedural map generation, boss arena breach, and quest reward claiming.
4. Edge cases: partial completion, prerequisite gating, zero-trust validation.
"""

import pytest
from server.world.quest_engine import (
    create_default_quest_engine,
    QuestStatus,
    QuestEngine,
)
from server.world.procedural_map_engine import (
    ProceduralMapEngine,
    verify_path_connectivity,
)
from server.world.war_fog_engine import WarFogEngine
from server.world.map_data_types import TileType, ObstacleType


@pytest.fixture
def quest_engine() -> QuestEngine:
    return create_default_quest_engine()


def mark_prereq_claimed(engine: QuestEngine, player_id: str, quest_id: str) -> None:
    engine.initialize_player(player_id)
    q_def = engine.get_quest_definition(quest_id)
    if q_def:
        obj_map = {obj.objective_id: obj.with_increment(obj.target_count) for obj in q_def.objectives}
        from server.world.quest_types import PlayerQuestProgress
        engine._player_quests[player_id][quest_id] = PlayerQuestProgress(
            player_id=player_id,
            quest_id=quest_id,
            status=QuestStatus.CLAIMED,
            objectives=obj_map,
            started_at=1.0,
            completed_at=2.0,
            claimed_at=3.0,
        )


class TestMapQuestAndBossIntegration:
    def test_canonical_map_and_boss_quests_registered(self, quest_engine: QuestEngine):
        """Verifies expanded map exploration and boss arena quests exist in canonical registry."""
        expected_quest_ids = [
            "quest_norm_06_kham_pha_dia_dao",
            "quest_norm_07_pha_huy_phong_an_boss",
            "quest_norm_08_chinh_phuc_dai_bi_canh",
            "quest_hidden_05_mat_that_cuoi_ban_do",
            "quest_epic_05_chua_te_vuc_tham",
        ]
        for q_id in expected_quest_ids:
            q_def = quest_engine.get_quest_definition(q_id)
            assert q_def is not None, f"Quest {q_id} missing from registry"
            assert len(q_def.objectives) >= 1
            assert q_def.reward.exp > 0

    def test_room_exploration_and_fog_clearance_progression(self, quest_engine: QuestEngine):
        """Tests progressing and completing Norm 06 (room exploration + fog clearing)."""
        player_id = "explorer_hero_01"
        quest_engine.initialize_player(player_id, player_level=15)
        mark_prereq_claimed(quest_engine, player_id, "quest_norm_05_khai_mo_van_gioi_cac")

        # Accept quest
        assert quest_engine.accept_quest(player_id, "quest_norm_06_kham_pha_dia_dao", player_level=15)
        q = quest_engine.get_player_quest(player_id, "quest_norm_06_kham_pha_dia_dao")
        assert q is not None
        assert q.status == QuestStatus.IN_PROGRESS

        # Progress room exploration (4 rooms)
        quest_engine.record_room_exploration(player_id, "room_procedural_dungeon", count=3)
        assert q.status == QuestStatus.IN_PROGRESS
        quest_engine.record_room_exploration(player_id, "room_procedural_dungeon", count=1)
        assert q.objectives["obj_norm_06_explore_rooms"].is_completed is True
        assert q.status == QuestStatus.IN_PROGRESS  # Fog not yet cleared

        # Progress fog clearance (40%)
        quest_engine.record_fog_clearance(player_id, "fog_procedural_dungeon", percent=40)
        assert q.status == QuestStatus.COMPLETED

        # Claim reward
        ok, rew, _ = quest_engine.claim_quest_reward(player_id, "quest_norm_06_kham_pha_dia_dao")
        assert ok is True
        assert rew is not None
        assert rew.title == "Kẻ Soi Sáng Địa Đạo"
        assert rew.meridian_points == 4

    def test_obstacle_destruction_and_boss_gate_breach(self, quest_engine: QuestEngine):
        """Tests progressing Norm 07 by destroying obstacles and breaching boss gate."""
        player_id = "breacher_hero_02"
        quest_engine.initialize_player(player_id, player_level=18)
        mark_prereq_claimed(quest_engine, player_id, "quest_norm_06_kham_pha_dia_dao")

        assert quest_engine.accept_quest(player_id, "quest_norm_07_pha_huy_phong_an_boss", player_level=18)
        q = quest_engine.get_player_quest(player_id, "quest_norm_07_pha_huy_phong_an_boss")
        assert q is not None

        # Destroy 2 obstacles
        quest_engine.record_obstacle_destruction(player_id, "obstacle_destructible", count=2)
        assert q.objectives["obj_norm_07_destroy_obstacles"].is_completed is True

        # Breach the boss gate
        quest_engine.record_boss_gate_breach(player_id, "gate_boss_seal")
        assert q.objectives["obj_norm_07_breach_gate"].is_completed is True
        assert q.status == QuestStatus.COMPLETED

        ok, rew, _ = quest_engine.claim_quest_reward(player_id, "quest_norm_07_pha_huy_phong_an_boss")
        assert ok is True
        assert rew is not None
        assert rew.title == "Kẻ Phá Cổng Bí Cảnh"

    def test_end_to_end_procedural_map_and_quest_closed_loop(self, quest_engine: QuestEngine):
        """Full closed-loop: ProceduralMapEngine generates 64x64 map, player breaches gate, completes quest."""
        player_id = "dungeon_master_03"
        quest_engine.initialize_player(player_id, player_level=70)
        mark_prereq_claimed(quest_engine, player_id, "quest_epic_04_van_gioi_than_ma_tranh_ba")

        # 1. Accept epic quest: Đại Chiến Boss Arena 64x64
        assert quest_engine.accept_quest(player_id, "quest_epic_05_chua_te_vuc_tham", player_level=70)
        q = quest_engine.get_player_quest(player_id, "quest_epic_05_chua_te_vuc_tham")
        assert q is not None

        # 2. Procedural Map Engine generates large 64x64 map
        map_engine = ProceduralMapEngine(width=64, height=64)
        map_data = map_engine.generate_map(seed=202610, biome_id="BLEACHED_BONE_CANYON")

        assert map_data.width == 64
        assert map_data.boss_gate is not None
        assert map_data.boss_room is not None

        # 3. Simulate player breaching the boss arena gate on server
        breach_ok = map_engine.breach_boss_gate(map_data)
        assert breach_ok is True
        assert map_data.boss_gate_breached is True

        # 4. Quest engine records boss gate breach event
        quest_engine.record_boss_gate_breach(player_id, "gate_boss_seal_arena")
        assert q.objectives["obj_epic_05_breach_gate"].is_completed is True

        # 5. Slay the boss
        quest_engine.record_kill(player_id, "boss_black_dragon_demon", count=1)
        assert q.status == QuestStatus.COMPLETED

        # 6. Claim epic reward
        ok, rew, _ = quest_engine.claim_quest_reward(player_id, "quest_epic_05_chua_te_vuc_tham")
        assert ok is True
        assert rew is not None
        assert rew.title == "Hoang Vực Tối Cao Chúa Tể"
        assert rew.meridian_points == 40

    def test_clear_fog_percent_gauge_behavior(self, quest_engine: QuestEngine):
        """Verifies CLEAR_FOG_PERCENT behaves as a gauge (high-water mark), not an accumulator."""
        player_id = "gauge_tester_01"
        quest_engine.initialize_player(player_id, player_level=15)
        mark_prereq_claimed(quest_engine, player_id, "quest_norm_05_khai_mo_van_gioi_cac")

        assert quest_engine.accept_quest(player_id, "quest_norm_06_kham_pha_dia_dao", player_level=15)
        q = quest_engine.get_player_quest(player_id, "quest_norm_06_kham_pha_dia_dao")
        assert q is not None

        # 1. Report 15%
        quest_engine.record_fog_clearance(player_id, "fog_procedural_dungeon", percent=15)
        assert q.objectives["obj_norm_06_clear_fog"].current_count == 15

        # 2. Re-report 10% (should not accumulate, remains 15)
        quest_engine.record_fog_clearance(player_id, "fog_procedural_dungeon", percent=10)
        assert q.objectives["obj_norm_06_clear_fog"].current_count == 15

        # 3. Re-report 15% (remains 15)
        quest_engine.record_fog_clearance(player_id, "fog_procedural_dungeon", percent=15)
        assert q.objectives["obj_norm_06_clear_fog"].current_count == 15

        # 4. Advance to 35%
        quest_engine.record_fog_clearance(player_id, "fog_procedural_dungeon", percent=35)
        assert q.objectives["obj_norm_06_clear_fog"].current_count == 35
        assert q.objectives["obj_norm_06_clear_fog"].is_completed is False

        # 5. Advance to 40% (target reached)
        quest_engine.record_fog_clearance(player_id, "fog_procedural_dungeon", percent=40)
        assert q.objectives["obj_norm_06_clear_fog"].current_count == 40
        assert q.objectives["obj_norm_06_clear_fog"].is_completed is True
