"""
Tier 4 E2E Tests: Real-World End-to-End Application Scenarios.
Simulates complete 6-player raid journeys, social coordinated expeditions,
and full map portal depletion lifecycles.
"""

from __future__ import annotations
import math
import pytest
from tests.e2e_social_party.test_harness import (
    GroundLootDrop,
    GuildMemberPresenceDTO,
    GuildRosterService,
    LootAllocationMode,
    PartyScalingCalculator,
    PartyService,
    SocialService,
    TargetType,
    TeleportService,
    TownPortalEngine,
)


@pytest.fixture
def world_env():
    party_svc = PartyService()
    social_svc = SocialService()
    guild_svc = GuildRosterService()
    teleport_svc = TeleportService(party_svc, social_svc, guild_svc)
    portal_engine = TownPortalEngine()
    return party_svc, social_svc, guild_svc, teleport_svc, portal_engine


class TestTier4RealWorldApplicationScenarios:
    """Tier 4: Real-World End-to-End Application Scenarios."""

    def test_scenario_01_full_six_player_dungeon_run_lifecycle(self, world_env) -> None:
        """Complete 6-player dungeon raid simulation:

        1. Form 6-player party in Sanctuary Hub.
        2. Leader enters Tier 16 Map (consuming 1 of 6 portal charges).
        3. 5 members channel safe teleport (3.5s) to leader, validated through 5-gate security.
        4. Dynamic monster scaling applied (+250% HP, +50% armor, +10% res).
        5. Mob pack defeated in 15m radius: EXP (+150%) distributed by (Lvl+10)^2.71, Loot (+250% Qty).
        6. Boss arena entered: Boss quarantine locks town portal creation and inbound teleports.
        7. Boss defeated: Quarantine lifts, leader opens 2-way Town Portal, party retreats to Hideout.
        """
        party_svc, social_svc, guild_svc, teleport_svc, portal_engine = world_env

        # 1. Form 6-player party
        p = party_svc.create_party("leader", "RaidLeader", 80, "zone_boundless_sanctuary", "inst_hub")
        member_levels = [75, 76, 78, 80, 82]
        for idx, lvl in enumerate(member_levels, start=2):
            pid = f"m_{idx}"
            party_svc.invite_player(p.party_id, "leader", pid)
            party_svc.accept_invite(p.party_id, pid, f"Member_{idx}", lvl, "zone_boundless_sanctuary", "inst_hub")
        assert len(p.members) == 6

        # 2. Leader enters Tier 16 map device
        map_inst = "map_t16_slaughterhouse"
        portal_engine.register_astral_map_device(map_inst, initial_charges=6)
        ok_enter, _, rem_charges = portal_engine.enter_map_portal(map_inst)
        assert ok_enter is True and rem_charges == 5

        # Move leader to map instance
        p.members["leader"].zone_id = "zone_blood_scale_ruins"
        p.members["leader"].instance_id = map_inst
        teleport_svc.set_zone_state("zone_blood_scale_ruins", player_count=1, max_capacity=6)

        # 3. 5 members channel teleport to leader
        for idx in range(2, 7):
            pid = f"m_{idx}"
            ok_chan, _ = teleport_svc.start_teleport_channel(pid, TargetType.PARTY_MEMBER, "leader", "zone_blood_scale_ruins")
            assert ok_chan is True
            ok_done, dest = teleport_svc.complete_channel(pid, elapsed_time=3.5)
            assert ok_done is True and dest == "zone_blood_scale_ruins"
            p.members[pid].zone_id = "zone_blood_scale_ruins"
            p.members[pid].instance_id = map_inst

        # 4. Verify Dynamic Monster Scaling for 6 players
        scaling = PartyScalingCalculator.calculate_monster_scaling("BOSS", party_size=6)
        assert math.isclose(scaling["hp_mult"], 6.00)
        assert math.isclose(scaling["armor_mult"], 1.50)
        assert math.isclose(scaling["res_bonus"], 10.0)

        # 5. Elite Mob Pack Defeated in 15m radius
        nearby_all = party_svc.get_nearby_members("leader", radius=15.0)
        assert len(nearby_all) == 6
        item_qty, curr_qty, rarity = PartyScalingCalculator.calculate_loot_multipliers(6)
        assert math.isclose(item_qty, 3.50) and math.isclose(curr_qty, 3.50) and math.isclose(rarity, 2.50)

        exp_dist = PartyScalingCalculator.calculate_party_exp(50000, nearby_all)
        assert sum(exp_dist.values()) <= 50000 * 2.50
        assert exp_dist["m_6"] > exp_dist["m_2"]  # Lvl 82 gets more than Lvl 75

        # Loot Drop with Short Allocation
        rare_drop = GroundLootDrop("drop_apex", "bone_relic", "m_2", drop_timestamp=1000.0, allocation_mode=LootAllocationMode.SHORT)
        assert rare_drop.can_player_pickup("m_2", current_time=1001.0) is True
        assert rare_drop.can_player_pickup("leader", current_time=1001.0) is False
        assert rare_drop.can_player_pickup("leader", current_time=1006.0) is True

        # 6. Advance to Boss Room & Quarantine Trigger
        portal_engine.set_encounter_state(map_inst, boss_active=True)
        teleport_svc.set_zone_state("zone_blood_scale_ruins", is_boss_active=True)

        # Anti-exploit check: Leader cannot open portal mid-fight
        ok_portal, err, _ = portal_engine.request_town_portal("leader", "zone_blood_scale_ruins", map_inst, 0.0, 0.0)
        assert ok_portal is False and "QUARANTINE_BOSS" in err

        # Anti-exploit check: Inbound teleports blocked by Gate 5 Quarantine
        ok_inbound, reason = teleport_svc.validate_destination_5_gates("m_2", "leader", TargetType.PARTY_MEMBER, "zone_blood_scale_ruins")
        assert ok_inbound is False and "GATE_5_QUARANTINE" in reason

        # 7. Boss Defeated & Safe Retreat to Hideout
        portal_engine.set_encounter_state(map_inst, boss_active=False)
        teleport_svc.set_zone_state("zone_blood_scale_ruins", is_boss_active=False)

        ok_tp, _, p_id = portal_engine.request_town_portal("leader", "zone_blood_scale_ruins", map_inst, 50.0, 50.0, hub_zone="zone_player_hideout")
        assert ok_tp is True and p_id is not None
        assert portal_engine.portals[p_id]["hub_zone"] == "zone_player_hideout"
        assert portal_engine.portals[p_id]["is_active"] is True

    def test_scenario_02_social_guild_coordinated_expedition(self, world_env) -> None:
        """Social & Guild Coordinated Expedition:

        1. Player inspects online friends and guild roster.
        2. Sets friend notes and establishes 2-player co-op party.
        3. Encounters puzzle/secret chamber with active countdown.
        4. Verifies portal lockout prevents skipping puzzle mechanics.
        5. Successfully solves chamber and extracts safely.
        """
        party_svc, social_svc, guild_svc, teleport_svc, portal_engine = world_env

        # 1. Social query
        social_svc.send_friend_request("hero", "scout")
        social_svc.accept_friend_request("scout", "hero")
        social_svc.update_presence("scout", "Scout", 45, True, "zone_tang_kiem_nhai", "Tàng Kiếm Nhai")
        social_svc.set_friend_note("hero", "scout", "Pathfinder / Trap Disarmer")

        friends = social_svc.get_friend_presence("hero")
        assert len(friends) == 1 and friends[0].note == "Pathfinder / Trap Disarmer"

        # 2. Form party
        p = party_svc.create_party("hero", "Hero", 45, "zone_tang_kiem_nhai", "inst_explore")
        party_svc.invite_player(p.party_id, "hero", "scout")
        party_svc.accept_invite(p.party_id, "scout", "Scout", 45, "zone_tang_kiem_nhai", "inst_explore")

        # 3. Enter secret chamber
        chamber_inst = "secret_puzzle_room_42"
        portal_engine.set_encounter_state(chamber_inst, secret_active=True)

        # 4. Attempting town portal during countdown fails
        ok_portal, msg, _ = portal_engine.request_town_portal("hero", "zone_puzzle", chamber_inst, 0.0, 0.0)
        assert ok_portal is False and "QUARANTINE_SECRET" in msg

        # 5. Solve puzzle -> quarantine lifts -> portal succeeds
        portal_engine.set_encounter_state(chamber_inst, secret_active=False)
        ok_portal2, _, p_id = portal_engine.request_town_portal("hero", "zone_puzzle", chamber_inst, 0.0, 0.0)
        assert ok_portal2 is True and p_id is not None

    def test_scenario_03_map_charge_depletion_and_sealing_lifecycle(self, world_env) -> None:
        """Map portal charge depletion lifecycle:

        1. Map device initialized with 6 charges.
        2. Entries and deaths consume charges until depleted to 0.
        3. At 0 charges, further entries are definitively rejected (MAP_SEALED).
        """
        _, _, _, _, portal_engine = world_env
        map_id = "apex_map_seal_test"
        portal_engine.register_astral_map_device(map_id, initial_charges=6)

        # 3 entries
        for _ in range(3):
            ok, _, _ = portal_engine.enter_map_portal(map_id)
            assert ok is True
        assert portal_engine.map_charges[map_id] == 3

        # 3 deaths in map
        for _ in range(3):
            portal_engine.on_player_death("victim", "zone_apex", map_id, is_map_instance=True)
        assert portal_engine.map_charges[map_id] == 0

        # Attempting 7th action fails
        ok_sealed, msg, rem = portal_engine.enter_map_portal(map_id)
        assert ok_sealed is False and rem == 0 and "MAP_SEALED" in msg
