"""
Terminal rendering helpers using Rich.

Each function accepts a Rich Console as its first argument so callers can
inject a buffered console in tests without touching stdout.
"""

from __future__ import annotations

from rich.console import Console
from rich.panel import Panel
from rich.syntax import Syntax
from rich.text import Text


# ---------------------------------------------------------------------------
# Internal helpers
# ---------------------------------------------------------------------------

_BAR_FULL = "█"
_BAR_EMPTY = "░"
_BAR_WIDTH = 16


def _progress_bar(filled: int, total: int, width: int = _BAR_WIDTH) -> str:
    """Return a block-character progress bar string.

    Examples:
        _progress_bar(8, 10, 10) -> "████████░░"
        _progress_bar(0, 10, 10) -> "░░░░░░░░░░"
    """
    if total <= 0:
        return _BAR_EMPTY * width
    ratio = min(filled / total, 1.0)
    filled_count = round(ratio * width)
    return _BAR_FULL * filled_count + _BAR_EMPTY * (width - filled_count)


def _topic_bars(topic_counts: dict[str, int], width: int = _BAR_WIDTH) -> list[tuple[str, str, int]]:
    """Return (topic, bar_str, count) rows scaled to the highest count."""
    if not topic_counts:
        return []
    max_count = max(topic_counts.values())
    rows = []
    for topic, count in sorted(topic_counts.items(), key=lambda kv: -kv[1]):
        bar = _progress_bar(count, max_count, width)
        rows.append((topic, bar, count))
    return rows


# ---------------------------------------------------------------------------
# Public rendering functions
# ---------------------------------------------------------------------------


def render_challenge(console: Console, challenge: dict, day: int) -> None:
    """Render a challenge panel to the console.

    The panel header shows the day number, topic, and title.  The code is
    syntax-highlighted inside the panel, preceded by the question text.

    Args:
        console:   Rich Console to render into.
        challenge: Challenge dict with keys: topic, title, code_display,
                   question, hints.
        day:       The current challenge day number (shown in the header).
    """
    source: str = challenge.get("source", "")
    title: str = challenge.get("title", "")
    code: str = challenge.get("code_display", "")
    question: str = challenge.get("question", "")

    # Detect syntax-highlight language from source; default to Python.
    lang_map = {
        "python": "python",
        "go": "go",
        "java": "java",
        "javascript": "javascript",
        "typescript": "typescript",
        "rust": "rust",
        "c": "c",
        "cpp": "cpp",
        "sql": "sql",
        "kubernetes": "yaml",
        "docker": "dockerfile",
        "terraform": "hcl",
        "cicd": "yaml",
        "bash": "bash",
        "linux": "bash",
    }
    lang = lang_map.get(source.lower(), "python")

    header = f"Day {day} · {source} · {title}"

    syntax = Syntax(code, lang, theme="monokai", line_numbers=False)

    # Print the question above the panel.
    if question:
        console.print()
        console.print(question)
        console.print()

    console.print(Panel(syntax, title=header, title_align="left", expand=False))
    console.print()
    console.print("[dim]\\[h] hint  \\[s] skip  \\[q] quit[/dim]")
    console.print()


def render_result(
    console: Console,
    *,
    correct: bool,
    explanation: str,
    deep_link: str,
    expected_answer: str | None = None,
) -> None:
    """Render the result of a challenge attempt.

    For a correct answer prints a green confirmation.  For an incorrect
    answer prints the expected answer in red, then always shows the
    explanation and a deep-link back to the refresher.

    Args:
        console:         Rich Console to render into.
        correct:         Whether the user's answer was judged correct.
        explanation:     Explanation text shown regardless of correctness.
        deep_link:       URL to the relevant refresher section.
        expected_answer: The correct answer string; shown only on failure.
    """
    console.print()

    if correct:
        console.print("[bold green]✓ Correct![/bold green]")
    else:
        wrong_line = Text("✗ Not quite.")
        if expected_answer is not None:
            wrong_line.append(f"  The answer is: {expected_answer}")
        console.print(wrong_line, style="bold red")

    console.print()
    console.print(explanation)
    console.print()
    console.print(f"[dim]→ Deep dive:[/dim] [cyan]{deep_link}[/cyan]")
    console.print()


def render_stats(console: Console, stats: dict) -> None:
    """Render a stats summary panel.

    Displays streak, weekly progress, all-time count, per-topic breakdowns,
    and the last session info.

    Args:
        console: Rich Console to render into.
        stats:   Stats dict with keys: streak, total_completed,
                 week_completed, week_goal, topic_counts (dict[str, int]),
                 last_session (dict with date/topic/title keys, or None).
    """
    streak: int = stats.get("streak", 0)
    total: int = stats.get("total_completed", 0)
    week_done: int = stats.get("week_completed", 0)
    week_goal: int = stats.get("week_goal", 10)
    topic_counts: dict[str, int] = stats.get("topic_counts") or {}
    last_session: dict | None = stats.get("last_session")

    streak_icon = " 🔥" if streak > 0 else ""
    console.print()
    console.print(f"[bold]Skilark · {streak} day streak{streak_icon}[/bold]")
    console.print()

    # Weekly progress bar
    week_bar = _progress_bar(week_done, week_goal, 10)
    console.print(
        f"[dim]This week[/dim]        {week_bar}  {week_done}/{week_goal}"
    )
    console.print(
        f"[dim]All time[/dim]         {total} challenges completed"
    )

    # Topic breakdown
    topic_rows = _topic_bars(topic_counts)
    if topic_rows:
        console.print()
        console.print("[bold]Topics[/bold]")
        max_label = max(len(t) for t, _, _ in topic_rows)
        for topic, bar, count in topic_rows:
            padding = " " * (max_label - len(topic))
            console.print(f"{topic}{padding}  {bar}  {count:>3}")

    # Last session
    if last_session:
        date_str: str = last_session.get("date", "")
        ls_topic: str = last_session.get("topic", "")
        ls_title: str = last_session.get("title", "")
        console.print()
        console.print(
            f"[dim]Last session[/dim]     {date_str} · {ls_topic} · {ls_title}"
        )

    console.print()


def render_hint(console: Console, hint_text: str) -> None:
    """Render a hint in a dimmed style.

    Args:
        console:   Rich Console to render into.
        hint_text: The hint string to display.
    """
    console.print()
    console.print(f"[dim]💡 {hint_text}[/dim]")
    console.print()
