"""Base screen class for the ALiCE TUI — DRY extraction of shared patterns."""

from __future__ import annotations

from typing import TYPE_CHECKING

import boto3
from botocore.exceptions import ClientError
from textual.binding import Binding
from textual.screen import Screen

from alice_cli.errors import AliceCLIError

if TYPE_CHECKING:
    from alice_cli.models import CLIConfig
    from alice_cli.tui.widgets.output import OutputPanel


class AliceScreen(Screen[None]):
    """Base class for all ALiCE TUI screens.

    Provides:
    - ``config`` property (typed, no ``type: ignore`` needed)
    - ``_wordstar`` property (reads ``self.app.wordstar``)
    - ``_create_session()`` for boto3 Session construction
    - ``_handle_error()`` for consistent error display
    - Default ``BINDINGS`` with Escape → pop_screen
    """

    BINDINGS = [
        Binding("escape", "pop_screen", "Back"),
    ]

    @property
    def config(self) -> CLIConfig:
        return self.app.alice_config  # type: ignore[attr-defined]

    @property
    def _wordstar(self) -> bool:
        return getattr(self.app, "wordstar", False)

    def _create_session(self) -> boto3.Session:
        """Create a boto3 Session from the app's CLI config."""
        return boto3.Session(
            profile_name=self.config.profile,
            region_name=self.config.region,
        )

    def _handle_error(self, exc: Exception, output: OutputPanel) -> None:
        """Display a friendly error message in the output panel."""
        if isinstance(exc, AliceCLIError):
            msg = exc.format_message()
        elif isinstance(exc, ClientError):
            code = exc.response.get("Error", {}).get("Code", "")
            if code == "ExpiredTokenException":
                profile = self.config.profile or "default"
                msg = f"SSO session expired — run: aws sso login --profile {profile}"
            else:
                msg = exc.response.get("Error", {}).get("Message", str(exc))
                msg = f"AWS error: {msg}"
        else:
            msg = f"Unexpected error: {exc}"
        output.write(f"[#FF6600]{msg}[/]")

    # ── Keyboard navigation helpers ───────────────────────────────────────

    def _text_input_has_focus(self) -> bool:
        """Return True if an Input or TextArea widget currently has focus.

        Used by ``key_j`` / ``key_k`` overrides to avoid intercepting
        normal typing when the user is inside a text field.
        """
        from textual.widgets import Input, TextArea

        focused = self.focused
        return isinstance(focused, Input | TextArea)

    # ── Token tracking helpers ────────────────────────────────────────────

    def _update_token_tracker(self, input_tokens: int, output_tokens: int) -> None:
        """Update the global TokenTracker widget if present in the app.

        Screens call this after each Bedrock API call to keep the
        persistent header counter in sync::

            self._update_token_tracker(usage_input, usage_output)

        Silently no-ops if the TokenTracker is not mounted.
        """
        try:
            from alice_cli.tui.widgets.token_tracker import TokenTracker

            tracker = self.app.query_one(TokenTracker)
            tracker.input_tokens += input_tokens
            tracker.output_tokens += output_tokens
        except Exception:  # noqa: BLE001
            pass  # TokenTracker may not be mounted

    # ── Prompt history helpers ────────────────────────────────────────────

    def _get_prompt_history(self, screen_name: str) -> list[str]:
        """Return the prompt history list for the given screen name."""
        state = getattr(self.app, "tui_state", None)
        if state is None:
            return []
        return state.prompt_history.get(screen_name, [])

    def _save_prompt(self, screen_name: str, prompt: str, max_items: int = 20) -> None:
        """Append a prompt to the history for the given screen, capped at *max_items*."""
        state = getattr(self.app, "tui_state", None)
        if state is None:
            return
        history = state.prompt_history.setdefault(screen_name, [])
        # Avoid consecutive duplicates
        if not history or history[-1] != prompt:
            history.append(prompt)
        # Trim to max
        if len(history) > max_items:
            state.prompt_history[screen_name] = history[-max_items:]
