"""Tests for talk_task_indicators formatting and rendering."""

from __future__ import annotations

import asyncio
import json
from io import StringIO

import pytest
from rich.console import Console

from anima.shell.cli_commands.talk_task_indicators import (
    emit_task_done,
    format_await_child_line,
    format_await_header,
    format_await_summary,
    format_task_wait_line,
    render_task_indicator,
)


class TestFormatTaskWaitLine:
    def test_active_task(self) -> None:
        line = format_task_wait_line("Analyze auth", 8)
        assert "\u25c7" in line  # ◇ hollow diamond
        assert "delegate:" in line
        assert "Analyze auth" in line
        assert "0:08" in line

    def test_completed_task(self) -> None:
        line = format_task_wait_line("Analyze auth", 47, status="completed")
        assert "\u25c6" in line  # ◆ filled diamond
        assert "\u2713" in line  # ✓

    def test_failed_task(self) -> None:
        line = format_task_wait_line("Analyze auth", 47, status="failed")
        assert "\u25c6" in line  # ◆
        assert "\u2717" in line  # ✗

    def test_long_description_truncated(self) -> None:
        long_desc = "A" * 60
        line = format_task_wait_line(long_desc, 5)
        assert "..." in line
        assert len(long_desc) > 40  # verify it would be truncated


class TestFormatAwaitHeader:
    def test_no_completed(self) -> None:
        line = format_await_header(3, 0, 12)
        assert "awaiting 3 tasks" in line
        assert "0:12" in line
        assert "done" not in line

    def test_partial_completed(self) -> None:
        line = format_await_header(3, 2, 34)
        assert "(2/3 done)" in line


class TestFormatAwaitSummary:
    def test_all_success(self) -> None:
        line = format_await_summary(3, 0, 41)
        assert "3 tasks completed" in line
        assert "failed" not in line

    def test_with_failures(self) -> None:
        line = format_await_summary(3, 1, 41)
        assert "(1 failed)" in line


class TestFormatAwaitChildLine:
    def test_completed_child(self) -> None:
        line = format_await_child_line("Analyze auth", 8, "completed")
        assert "\u2713" in line  # ✓
        assert "\u251c" in line  # ├

    def test_running_child_last(self) -> None:
        line = format_await_child_line("Check tests", 34, "running", is_last=True)
        assert "\u2514" in line  # └
        assert "\u28ff" in line  # ⣿ spinner

    def test_failed_child(self) -> None:
        line = format_await_child_line("Build", 5, "failed")
        assert "\u2717" in line  # ✗


class TestEmitTaskDone:
    def test_json_mode(self) -> None:
        buf = StringIO()
        console = Console(file=buf, force_terminal=False, color_system=None)
        emit_task_done(
            console=console,
            task_description="test task",
            elapsed_seconds=10,
            status="completed",
            json_output=True,
            child_id="inst_abc",
        )
        data = json.loads(buf.getvalue())
        assert data["event"] == "task_done"
        assert data["status"] == "completed"
        assert data["child_id"] == "inst_abc"
        assert data["elapsed_s"] == 10

    def test_human_mode(self) -> None:
        buf = StringIO()
        console = Console(file=buf, force_terminal=False, color_system=None)
        emit_task_done(
            console=console,
            task_description="test task",
            elapsed_seconds=5,
            status="failed",
            json_output=False,
        )
        output = buf.getvalue()
        assert "test task" in output


class TestRenderTaskIndicator:
    @pytest.mark.asyncio
    async def test_json_mode_emits_event(self) -> None:
        buf = StringIO()
        console = Console(file=buf, force_terminal=False, color_system=None)
        cancel = asyncio.Event()
        cancel.set()  # immediately cancel

        await render_task_indicator(
            console=console,
            task_description="test task",
            cancel_event=cancel,
            json_output=True,
            child_id="inst_test",
        )

        data = json.loads(buf.getvalue())
        assert data["event"] == "task_start"
        assert data["task"] == "test task"

    @pytest.mark.asyncio
    async def test_cancel_stops_rendering(self) -> None:
        buf = StringIO()
        console = Console(file=buf, force_terminal=False, color_system=None)
        cancel = asyncio.Event()

        async def cancel_after_delay() -> None:
            await asyncio.sleep(0.05)
            cancel.set()

        await asyncio.gather(
            render_task_indicator(
                console=console,
                task_description="quick task",
                cancel_event=cancel,
                json_output=False,
            ),
            cancel_after_delay(),
        )
        # Should have rendered at least one line
        assert "quick task" in buf.getvalue()
