"""Live streaming UI helpers for the dynamic installer.

This module extracted the old `_LiveLogPanel` from the dynamic installer monolith.
"""

from __future__ import annotations

import sys
import time
import threading
from collections import deque
from typing import Optional

from rich.console import Console
from rich.live import Live
from rich.panel import Panel


class _LiveLogPanel:
    """Small live console panel for long-running operations."""

    def __init__(
        self,
        title: str,
        enabled: bool = True,
        max_lines: int = 16,
        *,
        console: Optional[Console] = None,
    ):
        self.title = title
        self._console = console or Console()
        self.enabled = enabled and self._console.is_terminal and sys.stdout.isatty()
        self.max_lines = max_lines
        self._lines = deque(maxlen=max_lines)
        self._live: Optional[Live] = None
        self._header = "Starting..."
        self._running = False
        self._frame = 0
        self._start_ts = 0.0
        self._tick_stop = threading.Event()
        self._tick_thread: Optional[threading.Thread] = None
        self._frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]

    def start(self):
        if not self.enabled:
            return
        self._running = True
        self._start_ts = time.time()
        self._frame = 0
        self._tick_stop.clear()
        self._live = Live(self._render(), console=self._console, refresh_per_second=8, transient=False)
        self._live.start()
        self._tick_thread = threading.Thread(target=self._tick_loop, daemon=True)
        self._tick_thread.start()

    def stop(self):
        self._running = False
        self._tick_stop.set()
        if self._tick_thread and self._tick_thread.is_alive():
            self._tick_thread.join(timeout=0.3)
        self._tick_thread = None
        if self._live:
            self._live.stop()
            self._live = None

    def set_header(self, text: str):
        self._header = text
        self._refresh()

    def add_line(self, text: str):
        if text:
            self._lines.append(text)
            self._refresh()

    def _refresh(self):
        if self._live:
            self._live.update(self._render())

    def _tick_loop(self):
        while not self._tick_stop.wait(0.12):
            self._frame = (self._frame + 1) % len(self._frames)
            self._refresh()

    def _render(self) -> Panel:
        if self._running:
            elapsed = int(max(0, time.time() - self._start_ts))
            anim = self._frames[self._frame]
            header = f"{anim} {self._header}  [dim]({elapsed}s)[/dim]"
        else:
            header = self._header

        body_lines = [f"[bold]{header}[/bold]"]
        if self._lines:
            body_lines.append("")
            body_lines.extend(f"[dim]{ln}[/dim]" for ln in self._lines)
        body = "\n".join(body_lines)
        return Panel(body, title=f"[bold cyan]{self.title}[/bold cyan]", border_style="cyan", expand=True)

