"""
koci Output Formatter

Beautiful terminal output with configurable verbosity levels.
Uses Rich library for enhanced formatting.
"""

import sys
from enum import IntEnum
from typing import Optional, TextIO
from dataclasses import dataclass

try:
    from rich.console import Console
    from rich.table import Table
    from rich.panel import Panel
    from rich.tree import Tree
    RICH_AVAILABLE = True
except ImportError:
    RICH_AVAILABLE = False


class Verbosity(IntEnum):
    """Output verbosity levels."""
    QUIET = 0    # Only errors and final status
    NORMAL = 1   # Standard output (-v)
    VERBOSE = 2  # Detailed output (-vv)
    DEBUG = 3    # Debug output (-vvv)


def format_duration(seconds: float) -> str:
    """Format duration in human-readable form."""
    if seconds < 1:
        return f"{seconds*1000:.0f}ms"
    elif seconds < 60:
        return f"{seconds:.1f}s"
    elif seconds < 3600:
        minutes = int(seconds // 60)
        secs = seconds % 60
        return f"{minutes}m {secs:.0f}s"
    else:
        hours = int(seconds // 3600)
        minutes = int((seconds % 3600) // 60)
        return f"{hours}h {minutes}m"


def format_size(bytes_size: int) -> str:
    """Format byte size in human-readable form."""
    for unit in ['B', 'KB', 'MB', 'GB']:
        if bytes_size < 1024:
            return f"{bytes_size:.1f}{unit}"
        bytes_size /= 1024
    return f"{bytes_size:.1f}TB"


@dataclass
class Theme:
    """Color theme for output."""
    success: str = "green"
    error: str = "red"
    warning: str = "yellow"
    info: str = "blue"
    muted: str = "dim"
    stage: str = "bold cyan"
    job: str = "bold white"
    step: str = "white"


class OutputFormatter:
    """
    Formatted output with verbosity levels.

    Supports both Rich (beautiful) and plain text output.
    """

    def __init__(
        self,
        verbosity: Verbosity = Verbosity.NORMAL,
        stream: TextIO = None,
        use_color: bool = True,
        theme: Optional[Theme] = None,
    ):
        """
        Initialize formatter.

        Args:
            verbosity: Output verbosity level
            stream: Output stream (defaults to stdout)
            use_color: Whether to use colored output
            theme: Color theme
        """
        self.verbosity = verbosity
        self.stream = stream or sys.stdout
        self.use_color = use_color and RICH_AVAILABLE
        self.theme = theme or Theme()

        if self.use_color:
            self.console = Console(file=self.stream, force_terminal=use_color)
        else:
            self.console = None

        self._current_stage: Optional[str] = None
        self._current_job: Optional[str] = None

    def set_verbosity(self, level: int):
        """Set verbosity from integer (number of -v flags)."""
        self.verbosity = Verbosity(min(level, Verbosity.DEBUG))

    # Basic output methods

    def print(self, message: str, style: Optional[str] = None, level: Verbosity = Verbosity.NORMAL):
        """Print a message if verbosity allows."""
        if self.verbosity >= level:
            if self.console and style:
                self.console.print(message, style=style)
            else:
                print(message, file=self.stream)

    def debug(self, message: str):
        """Print debug message."""
        self.print(f"[DEBUG] {message}", self.theme.muted, Verbosity.DEBUG)

    def info(self, message: str):
        """Print info message."""
        self.print(message, self.theme.info, Verbosity.NORMAL)

    def success(self, message: str):
        """Print success message."""
        self.print(f"✓ {message}", self.theme.success, Verbosity.NORMAL)

    def error(self, message: str):
        """Print error message."""
        self.print(f"✗ {message}", self.theme.error, Verbosity.QUIET)

    def warning(self, message: str):
        """Print warning message."""
        self.print(f"⚠ {message}", self.theme.warning, Verbosity.NORMAL)

    # Pipeline output methods

    def pipeline_start(self, name: str, stages: int, jobs: int):
        """Output pipeline start."""
        if self.verbosity >= Verbosity.NORMAL:
            if self.console:
                self.console.print()
                self.console.print(Panel(
                    f"[bold]{name}[/bold]\n"
                    f"[dim]{stages} stages, {jobs} jobs[/dim]",
                    title="🚀 koci Pipeline",
                    border_style="blue",
                ))
            else:
                print(f"\n{'='*60}", file=self.stream)
                print(f"Pipeline: {name}", file=self.stream)
                print(f"Stages: {stages}, Jobs: {jobs}", file=self.stream)
                print(f"{'='*60}", file=self.stream)

    def pipeline_end(self, success: bool, duration: float):
        """Output pipeline completion."""
        if self.verbosity >= Verbosity.QUIET:
            duration_str = format_duration(duration)
            if self.console:
                self.console.print()
                if success:
                    self.console.print(Panel(
                        f"[bold green]Pipeline completed successfully[/bold green]\n"
                        f"[dim]Duration: {duration_str}[/dim]",
                        border_style="green",
                    ))
                else:
                    self.console.print(Panel(
                        f"[bold red]Pipeline failed[/bold red]\n"
                        f"[dim]Duration: {duration_str}[/dim]",
                        border_style="red",
                    ))
            else:
                print(f"\n{'='*60}", file=self.stream)
                status = "SUCCESS" if success else "FAILED"
                print(f"Pipeline {status} in {duration_str}", file=self.stream)
                print(f"{'='*60}", file=self.stream)

    def stage_start(self, name: str, jobs: int):
        """Output stage start."""
        self._current_stage = name
        if self.verbosity >= Verbosity.NORMAL:
            if self.console:
                self.console.print()
                self.console.print(f"[{self.theme.stage}]━━━ Stage: {name} ({jobs} jobs) ━━━[/]")
            else:
                print(f"\n--- Stage: {name} ({jobs} jobs) ---", file=self.stream)

    def stage_end(self, name: str, success: bool, duration: float):
        """Output stage completion."""
        if self.verbosity >= Verbosity.NORMAL:
            duration_str = format_duration(duration)
            icon = "✓" if success else "✗"
            color = self.theme.success if success else self.theme.error

            if self.console:
                self.console.print(f"[{color}]{icon} Stage {name} completed in {duration_str}[/]")
            else:
                status = "completed" if success else "failed"
                print(f"{icon} Stage {name} {status} in {duration_str}", file=self.stream)

    def job_start(self, name: str, image: str):
        """Output job start."""
        self._current_job = name
        if self.verbosity >= Verbosity.NORMAL:
            if self.console:
                self.console.print(f"\n  [{self.theme.job}]Job: {name}[/]")
                self.console.print(f"  [dim]Image: {image}[/dim]")
            else:
                print(f"\n  Job: {name}", file=self.stream)
                print(f"  Image: {image}", file=self.stream)

    def job_end(self, name: str, success: bool, duration: float):
        """Output job completion."""
        if self.verbosity >= Verbosity.NORMAL:
            duration_str = format_duration(duration)
            icon = "✓" if success else "✗"
            color = self.theme.success if success else self.theme.error

            if self.console:
                self.console.print(f"  [{color}]{icon} Job {name}: {duration_str}[/]")
            else:
                status = "success" if success else "failed"
                print(f"  {icon} Job {name}: {status} ({duration_str})", file=self.stream)

    def job_skipped(self, name: str, reason: str = "condition not met"):
        """Output job skipped."""
        if self.verbosity >= Verbosity.NORMAL:
            if self.console:
                self.console.print(f"  [dim]⊘ Job {name}: skipped ({reason})[/dim]")
            else:
                print(f"  ⊘ Job {name}: skipped ({reason})", file=self.stream)

    def step_start(self, name: str):
        """Output step start."""
        if self.verbosity >= Verbosity.VERBOSE:
            if self.console:
                self.console.print(f"    → {name}")
            else:
                print(f"    → {name}", file=self.stream)

    def step_output(self, line: str):
        """Output a line from step execution."""
        if self.verbosity >= Verbosity.VERBOSE:
            if self.console:
                self.console.print(f"      [dim]{line}[/dim]")
            else:
                print(f"      {line}", file=self.stream)

    def step_end(self, name: str, success: bool, duration: float):
        """Output step completion."""
        if self.verbosity >= Verbosity.VERBOSE:
            duration_str = format_duration(duration)
            icon = "✓" if success else "✗"
            color = self.theme.success if success else self.theme.error

            if self.console:
                self.console.print(f"    [{color}]{icon} {name} ({duration_str})[/]")
            else:
                print(f"    {icon} {name} ({duration_str})", file=self.stream)

    # Summary output

    def print_summary(self, result):
        """
        Print execution summary table.

        Args:
            result: ExecutionResult object
        """
        if self.verbosity < Verbosity.NORMAL:
            return

        if self.console:
            self._print_rich_summary(result)
        else:
            self._print_plain_summary(result)

    def _print_rich_summary(self, result):
        """Print Rich-formatted summary table."""
        table = Table(title="Pipeline Summary", show_header=True, header_style="bold")
        table.add_column("Stage", style="cyan")
        table.add_column("Job", style="white")
        table.add_column("Status")
        table.add_column("Duration", justify="right")

        for stage_result in result.stage_results:
            first_job = True
            for job_result in stage_result.job_results:
                stage_name = stage_result.stage.name if first_job else ""

                status_style = "green" if job_result.success else "red"
                status_text = job_result.status.value

                table.add_row(
                    stage_name,
                    job_result.job.name,
                    f"[{status_style}]{status_text}[/]",
                    format_duration(job_result.duration_seconds),
                )
                first_job = False

        self.console.print()
        self.console.print(table)

        # Total duration
        self.console.print(
            f"\n[bold]Total duration:[/bold] {format_duration(result.duration_seconds)}"
        )

    def _print_plain_summary(self, result):
        """Print plain text summary."""
        print("\n" + "="*60, file=self.stream)
        print("PIPELINE SUMMARY", file=self.stream)
        print("="*60, file=self.stream)

        for stage_result in result.stage_results:
            print(f"\nStage: {stage_result.stage.name}", file=self.stream)
            for job_result in stage_result.job_results:
                status = "✓" if job_result.success else "✗"
                duration = format_duration(job_result.duration_seconds)
                print(f"  {status} {job_result.job.name}: {job_result.status.value} ({duration})", file=self.stream)

        print(f"\nTotal duration: {format_duration(result.duration_seconds)}", file=self.stream)

    # Pipeline visualization

    def print_pipeline_graph(self, pipeline):
        """
        Print ASCII visualization of pipeline structure.

        Args:
            pipeline: Pipeline object
        """
        if self.console:
            self._print_rich_graph(pipeline)
        else:
            self._print_ascii_graph(pipeline)

    def _print_rich_graph(self, pipeline):
        """Print Rich tree visualization."""
        tree = Tree(f"[bold blue]📋 {pipeline.name}[/]")

        for stage in pipeline.stages:
            stage_tree = tree.add(f"[cyan]📁 {stage.name}[/]")

            for job in stage.jobs:
                job_label = f"[white]⚙ {job.name}[/]"
                if job.matrix:
                    job_label += f" [dim](matrix: {len(job.matrix.expand())} variants)[/dim]"
                if job.needs:
                    job_label += f" [dim]← {', '.join(job.needs)}[/dim]"

                job_tree = stage_tree.add(job_label)

                # Show steps at verbose level
                if self.verbosity >= Verbosity.VERBOSE:
                    for step in job.steps:
                        job_tree.add(f"[dim]→ {step.name}[/dim]")

        self.console.print()
        self.console.print(tree)

    def _print_ascii_graph(self, pipeline):
        """Print ASCII pipeline visualization."""
        print(f"\nPipeline: {pipeline.name}", file=self.stream)

        for i, stage in enumerate(pipeline.stages):
            is_last_stage = i == len(pipeline.stages) - 1
            prefix = "└── " if is_last_stage else "├── "
            print(f"{prefix}Stage: {stage.name}", file=self.stream)

            for j, job in enumerate(stage.jobs):
                is_last_job = j == len(stage.jobs) - 1
                stage_prefix = "    " if is_last_stage else "│   "
                job_prefix = "└── " if is_last_job else "├── "

                job_info = f"Job: {job.name}"
                if job.needs:
                    job_info += f" (needs: {', '.join(job.needs)})"

                print(f"{stage_prefix}{job_prefix}{job_info}", file=self.stream)


# Global formatter instance
_formatter: Optional[OutputFormatter] = None


def get_formatter() -> OutputFormatter:
    """Get the global output formatter."""
    global _formatter
    if _formatter is None:
        _formatter = OutputFormatter()
    return _formatter


def set_formatter(formatter: OutputFormatter):
    """Set the global output formatter."""
    global _formatter
    _formatter = formatter
