"""Interactive terminal renderer for forms using click prompts.

Works in tmux and plain terminals — no rich/curses dependency.
"""

from __future__ import annotations

import click
from typing import Any

from corpo.forms.definitions import FormDefinition, FormField, FormSection
from corpo.forms.validator import validate_field
from corpo.faq_hints import format_hints_for_field


class InteractiveRenderer:
    """Step-by-step terminal Q&A renderer for a form definition."""

    def __init__(self, form: FormDefinition, *, show_hints: bool = True):
        self.form = form
        self.show_hints = show_hints
        self.answers: dict[str, Any] = {}
        self._shown_hints: set[str] = set()  # Track which hints we've shown

    def run(self) -> dict[str, Any] | None:
        """Run the interactive form. Returns answers dict or None if cancelled."""
        click.echo("")
        click.echo(f"  {'=' * 56}")
        click.echo(f"  {self.form.title}")
        click.echo(f"  {self.form.description}")
        click.echo(f"  {'=' * 56}")

        total_sections = len(self.form.sections)
        section_idx = 0

        while section_idx < total_sections:
            section = self.form.sections[section_idx]
            result = self._render_section(section, section_idx + 1, total_sections)
            if result == "back":
                if section_idx > 0:
                    section_idx -= 1
                else:
                    click.echo("  Already at the first section.")
                continue
            elif result == "quit":
                return None
            section_idx += 1

        # Summary
        return self._show_summary()

    def _render_section(self, section: FormSection, num: int, total: int) -> str:
        """Render a section. Returns 'ok', 'back', or 'quit'."""
        click.echo("")
        click.echo(f"  -- {section.title} ({num}/{total}) --")
        click.echo("")

        field_idx = 0
        while field_idx < len(section.fields):
            field = section.fields[field_idx]
            result = self._render_field(field)
            if result == "back":
                if field_idx > 0:
                    field_idx -= 1
                else:
                    return "back"
                continue
            elif result == "quit":
                return "quit"
            field_idx += 1

        return "ok"

    def _render_field(self, field: FormField) -> str:
        """Render a single field prompt. Returns 'ok', 'back', or 'quit'."""
        # Show FAQ hints only once per hint (prevents repeated display)
        if self.show_hints:
            for kw in field.faq_keywords:
                if kw not in self._shown_hints:
                    hints = format_hints_for_field(kw)
                    if hints:
                        click.echo(hints)
                        self._shown_hints.add(kw)
                    break

        # Show help text
        if field.help:
            click.echo(f"  {field.help}")

        # Prefilled fields: show value and allow override
        if field.prefilled and field.default:
            click.echo(f"  {field.label}: {field.default}")
            override = click.prompt(
                "    Enter to accept, or type a new value",
                default="",
                show_default=False,
            )
            if override.strip().lower() in ("back", "<"):
                return "back"
            if override.strip().lower() in ("quit", "q"):
                return "quit"
            self.answers[field.id] = override.strip() if override.strip() else field.default
            return "ok"

        # Choice fields
        if field.type == "choice" and field.options:
            if len(field.options) == 1:
                # Single option — auto-select
                click.echo(f"  {field.label}: {field.options[0]}")
                self.answers[field.id] = field.options[0]
                return "ok"

            click.echo(f"  {field.label}:")
            for i, opt in enumerate(field.options, 1):
                marker = " *" if opt == field.default else ""
                click.echo(f"    {i}. {opt}{marker}")

            while True:
                raw = click.prompt(
                    "    Choose",
                    default=field.default or "",
                    show_default=bool(field.default),
                )
                if str(raw).strip().lower() in ("back", "<"):
                    return "back"
                if str(raw).strip().lower() in ("quit", "q"):
                    return "quit"
                # Accept number or value
                try:
                    idx = int(raw)
                    if 1 <= idx <= len(field.options):
                        self.answers[field.id] = field.options[idx - 1]
                        return "ok"
                except ValueError:
                    pass
                if str(raw) in field.options:
                    self.answers[field.id] = str(raw)
                    return "ok"
                click.echo(f"    Invalid choice. Pick 1-{len(field.options)} or type the value.")

        # Standard prompt
        while True:
            default = self.answers.get(field.id, field.default)
            raw = click.prompt(
                f"  {field.label}",
                default=default if default is not None else "",
                show_default=default is not None and default != "",
            )
            raw_str = str(raw).strip()
            if raw_str.lower() in ("back", "<"):
                return "back"
            if raw_str.lower() in ("quit", "q"):
                return "quit"

            # Coerce types
            value: Any = raw_str
            if field.type == "integer":
                try:
                    value = int(raw_str)
                except ValueError:
                    pass
            elif field.type == "percentage":
                try:
                    value = int(raw_str.rstrip("%"))
                except ValueError:
                    pass

            err = validate_field(field, value)
            if err:
                click.echo(f"    Error: {err}")
                continue

            self.answers[field.id] = value
            return "ok"

    def _show_summary(self) -> dict[str, Any] | None:
        """Show summary and ask for confirmation."""
        click.echo("")
        click.echo(f"  {'=' * 56}")
        click.echo("  Review your answers")
        click.echo(f"  {'=' * 56}")
        click.echo("")

        for section in self.form.sections:
            click.echo(f"  {section.title}:")
            for field in section.fields:
                val = self.answers.get(field.id, field.default)
                label = field.label.rstrip("?").rstrip(":")
                click.echo(f"    {label}: {val}")
            click.echo()

        confirmed = click.confirm("  Submit this form?", default=True)
        if confirmed:
            return dict(self.answers)
        return None
