"""Behave steps for TUI persona system."""

from __future__ import annotations

import shutil
import tempfile
import threading
from pathlib import Path

from behave import given, then, when
from behave.runner import Context

from cleveragents.tui.persona.registry import PersonaRegistry
from cleveragents.tui.persona.schema import Persona, PersonaPreset
from cleveragents.tui.persona.state import PersonaState


def _registry_for_temp_dir(path: Path) -> PersonaRegistry:
    return PersonaRegistry(config_dir=path)


@given("a temporary TUI persona registry")
def step_temp_registry(context: Context) -> None:
    temp_dir = Path(tempfile.mkdtemp())
    context.tui_persona_dir = temp_dir
    context.tui_registry = _registry_for_temp_dir(temp_dir)
    context.add_cleanup(lambda: shutil.rmtree(str(temp_dir), ignore_errors=True))


@when('I build a TUI persona named "{name}" with actor "{actor}"')
def step_build_persona(context: Context, name: str, actor: str) -> None:
    context.tui_persona = Persona(name=name, actor=actor)


@then("the persona should include exactly one default preset")
def step_default_preset(context: Context) -> None:
    defaults = [
        item for item in context.tui_persona.argument_presets if item.name == "default"
    ]
    assert len(defaults) == 1


@when('I save a TUI persona named "{name}" with actor "{actor}"')
def step_save_persona(context: Context, name: str, actor: str) -> None:
    persona = Persona(name=name, actor=actor)
    context.tui_registry.save(persona)


@given('I save a TUI persona named "{name}" with actor "{actor}"')
def step_given_save_persona(context: Context, name: str, actor: str) -> None:
    step_save_persona(context, name, actor)


@given(
    'I save TUI persona "{name}" with actor "{actor}" and extra preset "{preset_name}"'
)
def step_save_persona_with_extra_preset(
    context: Context, name: str, actor: str, preset_name: str
) -> None:
    persona = Persona(
        name=name,
        actor=actor,
        argument_presets=[
            PersonaPreset(name="default", display="default", overrides={}),
            PersonaPreset(
                name=preset_name, display=preset_name, overrides={"mode": "x"}
            ),
        ],
    )
    context.tui_registry.save(persona)


@given(
    'I save a TUI persona named "{name}" with actor "{actor}" and cycle order {cycle:d}'
)
def step_save_persona_cycle(
    context: Context, name: str, actor: str, cycle: int
) -> None:
    persona = Persona(name=name, actor=actor, cycle_order=cycle)
    context.tui_registry.save(persona)


@when(
    'I try to save a TUI persona named "{name}" with actor "{actor}" and cycle order {cycle:d}'
)
def step_save_persona_cycle_fail(
    context: Context, name: str, actor: str, cycle: int
) -> None:
    context.tui_cycle_error = None
    try:
        context.tui_registry.save(Persona(name=name, actor=actor, cycle_order=cycle))
    except Exception as exc:
        context.tui_cycle_error = exc


@then('loading persona "{name}" should succeed')
def step_loading_persona(context: Context, name: str) -> None:
    context.tui_loaded_persona = context.tui_registry.get(name)
    assert context.tui_loaded_persona is not None


@then('the loaded persona actor should be "{actor}"')
def step_loaded_actor(context: Context, actor: str) -> None:
    assert context.tui_loaded_persona.actor == actor


@then("saving the second persona should fail with cycle order error")
def step_cycle_error(context: Context) -> None:
    assert context.tui_cycle_error is not None
    assert "cycle_order" in str(context.tui_cycle_error)


@when('I set active persona to "{persona_name}" for session "{session_id}"')
def step_set_active_persona(
    context: Context, persona_name: str, session_id: str
) -> None:
    if not hasattr(context, "tui_state"):
        context.tui_state = PersonaState(registry=context.tui_registry)
    context.tui_state.set_active_persona(session_id, persona_name)


@then('active persona for session "{session_id}" should be "{persona_name}"')
def step_active_persona(context: Context, session_id: str, persona_name: str) -> None:
    persona = context.tui_state.active_persona(session_id)
    assert persona.name == persona_name


@when('I cycle persona preset for session "{session_id}"')
def step_cycle_preset(context: Context, session_id: str) -> None:
    if not hasattr(context, "tui_state"):
        context.tui_state = PersonaState(registry=context.tui_registry)
    context.tui_state.cycle_preset(session_id)


@then('current preset for session "{session_id}" should be "{preset_name}"')
def step_current_preset(context: Context, session_id: str, preset_name: str) -> None:
    assert context.tui_state.current_preset(session_id) == preset_name


@given('I create malformed TUI persona file "{name}"')
def step_create_malformed_persona_file(context: Context, name: str) -> None:
    malformed = context.tui_registry.personas_dir / f"{name}.yaml"
    context.tui_registry.ensure_dirs()
    malformed.write_text("name: broken\nactor:\n- not-a-string\n", encoding="utf-8")


@when("I list TUI personas")
def step_list_tui_personas(context: Context) -> None:
    context.tui_list_error = None
    context.tui_persona_names = []
    try:
        personas = context.tui_registry.list_personas()
        context.tui_persona_names = [persona.name for persona in personas]
    except Exception as exc:
        context.tui_list_error = exc


@then('TUI persona list should include "{name}"')
def step_tui_persona_list_includes(context: Context, name: str) -> None:
    assert context.tui_list_error is None
    assert name in context.tui_persona_names


@when('I export TUI persona "{name}" to "{output_path}"')
def step_export_tui_persona(context: Context, name: str, output_path: str) -> None:
    context.tui_export_error = None
    try:
        context.tui_registry.export_persona(name, Path(output_path))
    except Exception as exc:
        context.tui_export_error = exc


@then('TUI export should fail with "{message}"')
def step_tui_export_fails(context: Context, message: str) -> None:
    assert context.tui_export_error is not None
    assert message in str(context.tui_export_error)


@when('I import TUI persona from "{input_path}"')
def step_import_tui_persona(context: Context, input_path: str) -> None:
    context.tui_import_error = None
    try:
        context.tui_registry.import_persona(Path(input_path))
    except Exception as exc:
        context.tui_import_error = exc


@then('TUI import should fail with "{message}"')
def step_tui_import_fails(context: Context, message: str) -> None:
    assert context.tui_import_error is not None
    assert message in str(context.tui_import_error)


@when("I concurrently set TUI last persona names")
def step_concurrent_set_last_persona_names(context: Context) -> None:
    context.tui_concurrency_errors = []

    def _worker(persona_name: str) -> None:
        try:
            context.tui_registry.set_last_persona(persona_name)
        except Exception as exc:  # pragma: no cover - assertion handled after join
            context.tui_concurrency_errors.append(exc)

    threads: list[threading.Thread] = []
    for row in context.table:
        thread = threading.Thread(target=_worker, args=(row["name"],))
        threads.append(thread)
        thread.start()
    for thread in threads:
        thread.join()


@then("TUI concurrent update should complete without errors")
def step_tui_concurrent_update_no_errors(context: Context) -> None:
    assert context.tui_concurrency_errors == []
