"""CLI progress rendering utilities (non-invasive to pipeline/services).

Renders:
- Download progress via `DownloadProgress`
- Processing progress via `ProcessingProgress`
- Batch progress via `BatchProgress`

This stays at CLI layer to avoid overlap with pipeline orchestration.
"""

from __future__ import annotations

from dataclasses import asdict
from typing import Optional

from rich.console import Console
from rich.progress import Progress, TextColumn, BarColumn, TaskProgressColumn, TimeElapsedColumn, TimeRemainingColumn

from ..services.media_types import DownloadProgress, ProcessingProgress


class CliProgressRenderer:
    """Thin renderer for progress updates in CLI commands."""

    def __init__(self, console: Optional[Console] = None) -> None:
        self.console = console or Console()
        self._progress: Optional[Progress] = None
        self._tasks: dict[str, int] = {}

    def __enter__(self) -> "CliProgressRenderer":
        self._progress = Progress(
            TextColumn("[bold blue]{task.description}"),
            BarColumn(),
            TaskProgressColumn(),
            TimeElapsedColumn(),
            TimeRemainingColumn(),
            transient=True,
        )
        self._progress.__enter__()
        return self

    def __exit__(self, exc_type, exc, tb) -> None:
        if self._progress:
            self._progress.__exit__(exc_type, exc, tb)
        self._progress = None
        self._tasks.clear()

    def track_download(self, label: str) -> None:
        if not self._progress:
            return
        self._tasks[label] = self._progress.add_task(label, total=100)

    def on_download_progress(self, label: str, progress: DownloadProgress) -> None:
        if not self._progress:
            return
        task_id = self._tasks.get(label)
        if task_id is None:
            task_id = self._progress.add_task(label, total=100)
            self._tasks[label] = task_id
        percentage = int(getattr(progress, "percentage", 0) or 0)
        self._progress.update(task_id, completed=max(0, min(100, percentage)))

    def track_processing(self, label: str, total_steps: int = 100) -> None:
        if not self._progress:
            return
        self._tasks[label] = self._progress.add_task(label, total=total_steps)

    def on_processing_progress(self, label: str, progress: ProcessingProgress) -> None:
        if not self._progress:
            return
        task_id = self._tasks.get(label)
        if task_id is None:
            task_id = self._progress.add_task(label, total=progress.total_steps or 100)
            self._tasks[label] = task_id
        # Use step-based advancement when available; else leave as-is
        total = progress.total_steps or 100
        current = progress.current_step or 0
        percent = int((current / total) * 100) if total > 0 else 0
        self._progress.update(task_id, completed=max(0, min(100, percent)))

    def render_batch_line(self, text: str) -> None:
        # For batch summary ticker lines
        self.console.print(text, end="")

    def print_kv(self, title: str, data: dict) -> None:
        serialized = {k: v for k, v in data.items()}
        self.console.print(f"[bold]{title}[/bold]: {serialized}")


def make_download_callback(renderer: CliProgressRenderer, label: str):
    """Adapt a renderer into a callable suitable for services expecting a callback."""
    def _cb(progress: DownloadProgress | ProcessingProgress) -> None:
        if isinstance(progress, DownloadProgress):
            renderer.on_download_progress(label, progress)
        elif isinstance(progress, ProcessingProgress):
            renderer.on_processing_progress(label, progress)
    return _cb


