"""Compose screen for the ALiCE TUI — multi-step wizard for building a Strands agent."""

from __future__ import annotations

from pathlib import Path
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from textual.app import ComposeResult

from textual.binding import Binding
from textual.containers import Grid, Horizontal, Vertical, VerticalScroll
from textual.reactive import reactive
from textual.widgets import Button, Footer, Input, Label, Select, Static, TextArea

from alice_cli.compose_engine import AVAILABLE_TOOLS, AgentSpec, render_agent_code
from alice_cli.tui.screens.base import AliceScreen
from alice_cli.tui.widgets.breadcrumb import BreadcrumbBar
from alice_cli.tui.widgets.clock import TerminalClock
from alice_cli.tui.widgets.header_bar import AliceHeaderBar
from alice_cli.tui.widgets.output import OutputPanel

_MODEL_PROVIDERS = [
    ("Amazon Bedrock (default)", "bedrock"),
    ("Ollama (local)", "ollama"),
    ("LiteLLM", "litellm"),
    ("Custom provider", "custom"),
]

_TOTAL_STEPS = 5

_STEP_LABELS = [
    "Identity",
    "System Prompt",
    "Model",
    "Tools",
    "Output & Review",
]


class StepIndicator(Static):
    """Displays the current step as a breadcrumb bar."""

    DEFAULT_CSS = """
    StepIndicator {
        width: 100%;
        height: 1;
        background: #2A1F00;
        color: #805800;
        text-align: center;
        padding: 0 1;
    }
    """

    step: reactive[int] = reactive(0)

    def watch_step(self, value: int) -> None:
        parts: list[str] = []
        for i, label in enumerate(_STEP_LABELS):
            if i < value:
                parts.append(f"[#88CC00]✓ {label}[/]")
            elif i == value:
                parts.append(f"[#FFD866 bold]▸ {label}[/]")
            else:
                parts.append(f"[#805800]{label}[/]")
        self.update("  ›  ".join(parts))


class CodePreview(Static):
    """Live preview of the generated agent code."""

    DEFAULT_CSS = """
    CodePreview {
        width: 100%;
        height: 100%;
        background: #0A1628;
        color: #88CC00;
        border: tall #1A3A5C;
        padding: 1 2;
        overflow-y: auto;
    }
    """

    def update_code(self, code: str) -> None:
        self.update(code or "[dim]Preview will appear here…[/]")


class ComposeScreen(AliceScreen):
    """Multi-step wizard for composing a Strands agent."""

    DEFAULT_CSS = """
    ComposeScreen #wizard-body {
        height: 1fr;
    }

    ComposeScreen #step-area {
        width: 1fr;
        min-width: 40;
        padding: 1 2;
    }

    ComposeScreen #preview-area {
        width: 2fr;
        min-width: 50;
        padding: 1 1;
    }

    ComposeScreen #preview-area Label {
        color: #805800;
        padding: 0 0 0 1;
    }

    ComposeScreen #preview-scroll {
        height: 1fr;
    }

    ComposeScreen .step-pane {
        display: none;
        height: auto;
        padding: 1 0;
    }

    ComposeScreen .step-pane.--visible {
        display: block;
    }

    ComposeScreen .step-hint {
        color: #805800;
        padding: 0 0 1 0;
    }

    ComposeScreen #nav-bar {
        height: 3;
        align: center middle;
        padding: 0 2;
    }

    ComposeScreen #nav-bar Button {
        margin: 0 1;
    }

    ComposeScreen .tool-grid {
        grid-size: 2;
        grid-gutter: 1;
        height: auto;
        padding: 0 0;
    }

    ComposeScreen .tool-grid Button {
        width: 100%;
        min-width: 14;
    }
    """

    BINDINGS = [
        Binding("right", "next_step", "Next", show=True),
        Binding("left", "prev_step", "Prev", show=True),
    ]

    current_step: reactive[int] = reactive(0)

    def compose(self) -> ComposeResult:
        yield AliceHeaderBar()
        yield BreadcrumbBar(id="breadcrumb")
        yield StepIndicator(id="step-indicator")

        with Horizontal(id="wizard-body"):
            # Left: step content
            with VerticalScroll(id="step-area"):
                # Step 0: Identity
                with Vertical(id="step-0", classes="step-pane --visible"):
                    yield Label("What should we call this agent?", classes="step-hint")
                    yield Label("Agent name:")
                    yield Input(
                        value="my_agent",
                        placeholder="e.g. research_assistant",
                        id="agent-name",
                    )

                # Step 1: System Prompt
                with Vertical(id="step-1", classes="step-pane"):
                    yield Label(
                        "Give your agent its personality and purpose.",
                        classes="step-hint",
                    )
                    yield Label("System prompt:")
                    yield TextArea(id="system-prompt")

                # Step 2: Model
                with Vertical(id="step-2", classes="step-pane"):
                    yield Label(
                        "Pick a model provider. Bedrock works out of the box.",
                        classes="step-hint",
                    )
                    yield Label("Model provider:")
                    yield Select(
                        [(label, value) for label, value in _MODEL_PROVIDERS],
                        value="bedrock",
                        id="model-provider",
                    )

                # Step 3: Tools
                with Vertical(id="step-3", classes="step-pane"):
                    yield Label(
                        "Toggle the tools your agent can use.",
                        classes="step-hint",
                    )
                    with Grid(classes="tool-grid"):
                        for tool in AVAILABLE_TOOLS:
                            yield Button(
                                f"☐ {tool.name}",
                                id=f"tool-{tool.name}",
                                classes="tool-off",
                            )

                # Step 4: Output & Review
                with Vertical(id="step-4", classes="step-pane"):
                    yield Label(
                        "Choose where to save, then review and generate.",
                        classes="step-hint",
                    )
                    yield Label("Output path:")
                    yield Input(
                        value="agents/my_agent.py",
                        placeholder="path/to/agent.py",
                        id="output-path",
                    )
                    yield Button(
                        "✦  Generate Agent  ✦",
                        id="btn-generate",
                        variant="primary",
                    )
                    yield OutputPanel(id="compose-output", wordstar=self._wordstar)

            # Right: live code preview
            with Vertical(id="preview-area"):
                yield Label("LIVE PREVIEW")
                with VerticalScroll(id="preview-scroll"):
                    yield CodePreview(id="code-preview")

        # Navigation bar
        with Horizontal(id="nav-bar"):
            yield Button("‹ Back", id="btn-prev")
            yield Button("Next ›", id="btn-next", variant="primary")

        yield TerminalClock()
        yield Footer()

    def on_mount(self) -> None:
        area = self.query_one("#system-prompt", TextArea)
        area.load_text("You are a helpful assistant.")
        self._sync_step_visibility()
        self._refresh_preview()

    # --- Step navigation ---

    def watch_current_step(self, value: int) -> None:
        self._sync_step_visibility()
        indicator = self.query_one("#step-indicator", StepIndicator)
        indicator.step = value
        self._refresh_preview()

    def _sync_step_visibility(self) -> None:
        """Show only the active step pane."""
        for i in range(_TOTAL_STEPS):
            pane = self.query_one(f"#step-{i}")
            if i == self.current_step:
                pane.add_class("--visible")
            else:
                pane.remove_class("--visible")

        # Update nav button states
        prev_btn = self.query_one("#btn-prev", Button)
        next_btn = self.query_one("#btn-next", Button)
        prev_btn.disabled = self.current_step == 0
        next_btn.disabled = self.current_step == _TOTAL_STEPS - 1

    def action_next_step(self) -> None:
        if self.current_step < _TOTAL_STEPS - 1:
            self.current_step += 1

    def action_prev_step(self) -> None:
        if self.current_step > 0:
            self.current_step -= 1

    # --- Live preview ---

    def _build_spec(self) -> AgentSpec:
        """Collect current form state into an AgentSpec."""
        agent_name = self.query_one("#agent-name", Input).value.strip() or "my_agent"
        system_prompt = self.query_one("#system-prompt", TextArea).text.strip()
        model_select = self.query_one("#model-provider", Select)
        model_provider = str(model_select.value) if model_select.value else "bedrock"
        tools = self._selected_tools()
        return AgentSpec(
            name=agent_name,
            system_prompt=system_prompt or "You are a helpful assistant.",
            model_provider=model_provider,
            tools=tools,
        )

    def _refresh_preview(self) -> None:
        """Re-render the live code preview from current form state."""
        spec = self._build_spec()
        code = render_agent_code(spec)
        preview = self.query_one("#code-preview", CodePreview)
        preview.update_code(code)

    # --- Event handlers ---

    def on_input_changed(self, event: Input.Changed) -> None:
        self._refresh_preview()
        # Sync agent name into output path
        if event.input.id == "agent-name":
            name = event.value.strip() or "my_agent"
            out_input = self.query_one("#output-path", Input)
            out_input.value = f"agents/{name}.py"

    def on_text_area_changed(self, event: TextArea.Changed) -> None:
        self._refresh_preview()
        # Auto-grow system prompt TextArea
        if event.text_area.id == "system-prompt":
            text = event.text_area.text
            line_count = text.count("\n") + 1
            # Grow from default 3 lines up to max 12
            new_height = max(3, min(line_count + 1, 12))
            event.text_area.styles.height = new_height

    def on_select_changed(self, event: Select.Changed) -> None:
        self._refresh_preview()

    def on_button_pressed(self, event: Button.Pressed) -> None:
        btn_id = event.button.id or ""

        if btn_id == "btn-next":
            self.action_next_step()
            return
        if btn_id == "btn-prev":
            self.action_prev_step()
            return

        # Tool toggle buttons
        if btn_id.startswith("tool-"):
            btn = event.button
            tool_name = btn_id.removeprefix("tool-")
            if "tool-on" in btn.classes:
                btn.remove_class("tool-on")
                btn.add_class("tool-off")
                btn.label = f"☐ {tool_name}"
            else:
                btn.remove_class("tool-off")
                btn.add_class("tool-on")
                btn.label = f"☑ {tool_name}"
            self._refresh_preview()
            return

        if btn_id == "btn-generate":
            self._generate()

    def _selected_tools(self) -> list[str]:
        tools: list[str] = []
        for tool in AVAILABLE_TOOLS:
            btn = self.query_one(f"#tool-{tool.name}", Button)
            if "tool-on" in btn.classes:
                tools.append(tool.name)
        return tools

    def _generate(self) -> None:
        output = self.query_one("#compose-output", OutputPanel)
        output.clear()

        spec = self._build_spec()
        code = render_agent_code(spec)
        output_path_str = self.query_one("#output-path", Input).value.strip()
        out_path = Path(output_path_str)

        try:
            out_path.parent.mkdir(parents=True, exist_ok=True)
            out_path.write_text(code)
            output.write(f"[#88CC00]✓ Agent written to {out_path}[/]\n")
            output.write(f"[dim]Run it with:  python {out_path}[/]")
            self.notify(f"Agent saved to {out_path}", severity="information")
        except OSError as exc:
            self._handle_error(exc, output)
