"""
today command — the core challenge loop.

Entry point: `skilark` or `skilark today`

Fetches the next unseen challenge, prompts for an answer, checks it,
records the result, and offers another round.  The interactive loop is
extracted into `run_challenge_loop()` so tests can call it directly
without touching ConfigStore or performing network I/O.
"""

import json

from rich.console import Console
from rich.prompt import Confirm, Prompt

from skilark_cli.answer_checker import check_answer
from skilark_cli.client import SkilarkClient
from skilark_cli.config_store import ConfigStore
from skilark_cli.display import render_challenge, render_hint, render_result
from skilark_cli.onboarding import run_onboarding

console = Console()


def run() -> None:
    """Entry point called from main.py for `skilark today`."""
    config_store = ConfigStore()

    if config_store.is_first_run():
        run_onboarding(config_store, api_url="https://api.skilark.com")

    config = config_store.load()
    client = SkilarkClient(base_url=config["api_url"], user_id=config["user_id"])

    # Use total_completed to drive the displayed day counter.  If the stats
    # endpoint is unavailable (e.g. no network), fall back to day 1 silently
    # so the user can still practice.
    try:
        stats = client.get_stats()
        day = stats.get("total_completed", 0) + 1
    except Exception:
        day = 1

    run_challenge_loop(client, topics=config["topics"], day=day)


def run_challenge_loop(client: SkilarkClient, topics: list[str], day: int) -> None:
    """Interactive challenge loop.

    Fetches one challenge at a time, handles the answer/hint/skip/quit
    interactions, records completions, and asks whether to continue.

    Separated from `run()` so tests can inject a mock client and drive the
    loop via patched Rich prompts without touching the filesystem or network.

    Args:
        client: SkilarkClient instance (or mock in tests).
        topics: Topic filter passed to get_next_challenge.
        day:    Starting day number displayed in the challenge header.
    """
    while True:
        challenge = client.get_next_challenge(topics=topics)
        if not challenge:
            console.print(
                "\n[dim]No more challenges available for your topics. "
                "Try adding more![/dim]\n"
            )
            return

        render_challenge(console, challenge, day=day)

        # Hints may arrive as a JSON string or as an already-parsed list.
        # Normalise to a list here so the rest of the loop is clean.
        hints = challenge.get("hints") or []
        if isinstance(hints, str):
            try:
                hints = json.loads(hints)
            except (json.JSONDecodeError, TypeError):
                hints = []

        hint_idx = 0

        while True:
            answer = Prompt.ask("  Your answer")

            if answer.lower() == "h":
                if hint_idx < len(hints):
                    render_hint(console, hints[hint_idx])
                    hint_idx += 1
                else:
                    console.print("[dim]  No more hints.[/dim]\n")
                continue

            if answer.lower() == "s":
                console.print("[dim]  Skipped.[/dim]\n")
                break

            if answer.lower() == "q":
                return

            correct = check_answer(answer, challenge["expected_answer"])
            self_corrected = False

            if not correct:
                render_result(
                    console,
                    correct=False,
                    expected_answer=challenge["expected_answer"],
                    explanation=challenge["explanation"],
                    deep_link=challenge["deep_link"],
                )
                self_corrected = Confirm.ask(
                    "  Were you actually right?", default=False
                )
                if self_corrected:
                    correct = True
            else:
                render_result(
                    console,
                    correct=True,
                    explanation=challenge["explanation"],
                    deep_link=challenge["deep_link"],
                )

            client.complete_challenge(
                challenge["id"],
                answer=answer,
                correct=correct,
                self_corrected=self_corrected,
            )
            break

        day += 1

        if not Confirm.ask("\n  Another?", default=True):
            console.print("[dim]  See you tomorrow.[/dim]\n")
            return
