"""DARK room — sensory-deprivation dream dispatch chamber."""

import random

from h2g2.engine.game_object import (
    GameObject, Room, Flag, Direction,
)
from h2g2.engine.world import World
from h2g2.engine.state import GameState


# ---- Flavor texts ----

_ENTRY_TEXTS = [
    (
        "You are floating in a dark, formless void. You can see nothing. "
        "You can hear nothing. You can smell nothing. You are not even sure "
        "who you are."
    ),
    (
        "A cold grey fog rolls in, enveloping your senses. Your limbs are "
        "numb. Your mind is numb. Everything is numb."
    ),
    (
        "Mist swirls around you. Your thoughts dissolve into the gloom. "
        "You are nowhere."
    ),
]


# ---- Sensory discovery helpers ----

_SENSE_HINTS = {
    "listen": "You strain your ears. From somewhere far away, a faint hum reaches you.",
    "smell": "You inhale deeply. There is a faint chemical tang in the air.",
    "touch": "You reach out tentatively. Your fingers brush something cold and smooth.",
    "feel": "You reach out tentatively. Your fingers brush something cold and smooth.",
    "look": "You peer into the darkness. A faint glimmer pulses somewhere ahead.",
    "examine": "You peer into the darkness. A faint glimmer pulses somewhere ahead.",
}


# ---- Timed events ----

def _i_dark_hint(state: GameState) -> bool:
    """After 3 turns in DARK, hint at using senses."""
    out = state.output

    if state.here is None or state.here.id != "DARK":
        return False

    counter = state.flags.get("dark_counter", 0) + 1
    state.flags["dark_counter"] = counter

    if counter == 3:
        out.tell(
            "\nYou sense something in the darkness. Try using your senses.\n"
        )
        state.flags["dark_hint_given"] = True
        return True

    return False


def _i_dark_dispatch(state: GameState) -> bool:
    """After senses used or enough turns, dispatch to dream destination."""
    out = state.output

    if state.here is None or state.here.id != "DARK":
        return False

    if not state.flags.get("dark_exit_ready"):
        return False

    # Build weighted destination list
    destinations = []
    weights = []

    heart_prob = state.flags.get("heart_prob", 0)
    vogon_prob = state.flags.get("vogon_prob", 100)
    traal_prob = state.flags.get("traal_prob", 60)
    fleet_prob = state.flags.get("fleet_prob", 0)

    if heart_prob > 0 and state.world.rooms.get("ENTRY-BAY"):
        destinations.append("ENTRY-BAY")
        weights.append(heart_prob)
    if vogon_prob > 0 and state.world.rooms.get("HOLD"):
        destinations.append("HOLD")
        weights.append(vogon_prob)
    if traal_prob > 0 and state.world.rooms.get("LAIR"):
        destinations.append("LAIR")
        weights.append(traal_prob)
    if fleet_prob > 0 and state.world.rooms.get("WAR-CHAMBER"):
        destinations.append("WAR-CHAMBER")
        weights.append(fleet_prob)

    if not destinations:
        out.tell("\nThe darkness persists. Nothing happens.\n")
        return True

    chosen = random.choices(destinations, weights=weights, k=1)[0]
    dest = state.world.get_room(chosen)

    out.tell(
        "\nThe darkness shifts. Shapes coalesce around you. The world "
        "reassembles itself...\n\n"
    )

    # Move player to destination
    state.here = dest
    state.protagonist.move_to(dest)
    state.dreaming = True

    # Reset dark state
    state.flags["dark_counter"] = 0
    state.flags["dark_hint_given"] = False
    state.flags["dark_exit_ready"] = False
    state.flags["dark_senses_used"] = 0

    # Disable dispatch timer
    for entry in state.clock.entries:
        if entry.routine is _i_dark_dispatch:
            entry.enabled = False
    for entry in state.clock.entries:
        if entry.routine is _i_dark_hint:
            entry.enabled = False

    # Trigger destination room's M-ENTER via its action
    if dest.action:
        dest.action(state, "M-ENTER")

    return True


# ---- Room action handler ----

def _dark_action(state: GameState, rarg: str) -> bool:
    out = state.output

    if rarg == "M-ENTER":
        # Clear player inventory (ROB)
        if state.protagonist:
            for item in list(state.protagonist.children):
                item.move_to(state.world.local_globals)

        # Set dreaming
        state.dreaming = True

        # Display random entry text
        out.tell(random.choice(_ENTRY_TEXTS) + "\n")

        # Reset dark room state
        state.flags["dark_counter"] = 0
        state.flags["dark_hint_given"] = False
        state.flags["dark_exit_ready"] = False
        state.flags["dark_senses_used"] = 0

        # Queue hint timer (fires every turn, counts to 3)
        state.clock.queue(_i_dark_hint, -1, name="I-DARK-HINT")
        # Queue dispatch timer (fires every turn, waits for exit_ready)
        state.clock.queue(_i_dark_dispatch, -1, name="I-DARK-DISPATCH")

        return True

    if rarg == "M-LOOK":
        out.tell("It is pitch dark. You can see nothing.\n")
        return True

    if rarg == "M-END":
        # Handle sense verbs
        verb = state.prsa
        if verb in _SENSE_HINTS:
            out.tell(_SENSE_HINTS[verb] + "\n")
            senses_used = state.flags.get("dark_senses_used", 0) + 1
            state.flags["dark_senses_used"] = senses_used

            if senses_used >= 2 and state.flags.get("dark_hint_given"):
                out.tell(
                    "\nYou begin to get your bearings. You could try "
                    "walking now.\n"
                )
                state.flags["dark_exit_ready"] = True
            return True

        if verb in ("walk", "go") and state.flags.get("dark_exit_ready"):
            # Trigger dispatch immediately
            state.flags["dark_exit_ready"] = True
            _i_dark_dispatch(state)
            return True

        if verb in ("walk", "go"):
            out.tell("You stumble blindly but get nowhere.\n")
            return True

        return False

    return False


# ---- Dream restore callback ----

def _dream_restore(state: GameState) -> None:
    """Called when the player dies in a dream — return to DARK."""
    dark = state.world.rooms.get("DARK")
    if dark:
        state.here = dark
        state.protagonist.move_to(dark)
        if dark.action:
            dark.action(state, "M-ENTER")


# ---- Registration ----

def register(world: World, state: GameState) -> None:
    """Create the DARK dream dispatch room."""

    # ---- Initialize state flags ----

    state.flags.setdefault("dark_counter", 0)
    state.flags.setdefault("dark_hint_given", False)
    state.flags.setdefault("dark_exit_ready", False)
    state.flags.setdefault("dark_senses_used", 0)

    # Probability weights for dream dispatch
    state.flags.setdefault("heart_prob", 0)
    state.flags.setdefault("vogon_prob", 100)
    state.flags.setdefault("traal_prob", 60)
    state.flags.setdefault("fleet_prob", 0)

    # ---- DARK room ----

    world.register(Room(
        "DARK", desc="Dark",
        flags={Flag.RLANDBIT, Flag.ONBIT},
        action=_dark_action,
        exits={},  # No exits; player leaves via dispatch mechanic
    ))

    # Register dream restore callback
    state._dream_restore_callback = _dream_restore
