from __future__ import annotations

import time
from dataclasses import dataclass, field

from rich.console import Console, Group
from rich.live import Live
from rich.panel import Panel
from rich.progress import Progress, SpinnerColumn, BarColumn, TextColumn, TaskID
from rich.spinner import Spinner
from rich.table import Table
from rich.text import Text
from rich.theme import Theme


theme = Theme(
    {
        "success": "green bold",
        "info": "blue",
        "warning": "yellow",
        "error": "red bold",
        "critical": "red bold reverse",
        "high": "bright_red bold",
        "medium": "yellow",
        "low": "green",
        "header": "magenta bold",
        "path": "cyan",
        "category": "bright_blue",
        "line_number": "bright_black",
        "suggestion": "green italic",
        "progress": "bold cyan",
        "step": "dim",
    }
)

console = Console(theme=theme, force_terminal=True)

# 파일 읽기 완료 후 단계로 인정할 상태 문구 (이 중 하나로 바뀌면 "파일 읽기 중" 행 숨김)
POST_FILE_READ_STATUSES = frozenset({
    "LLM 생성 중",
    "결과 파싱/렌더링 중",
    "AST 분석 및 LLM 검토 중",
})


def render_progress_panel(
    mode_label: str, status_line: str | None, spinner: Spinner, progress: Progress | None = None, progress_handle: ProgressHandle | None = None
) -> Panel:
    header = Table.grid(padding=(0, 1))
    header.add_column()
    header.add_column()
    header.add_row(spinner, Text(f"{mode_label} 실행 중...", style="progress"))
    components = [header]
    # 단계별 상태 문구를 메인으로 (헤더 바로 아래)
    if status_line:
        components.append(Text(status_line, style="progress"))
    # 파일 읽기 단계일 때만 Progress(읽은/전체) 행 표시
    show_file_progress = progress_handle is None or progress_handle.total_files == 0 or progress_handle.read_files_count < progress_handle.total_files
    if progress and show_file_progress:
        components.append(progress)
    body = Group(*components)
    return Panel(body, border_style="cyan")


def render_done_panel(mode_label: str) -> Panel:
    body = Text("분석 완료", style="success")
    return Panel(body, border_style="cyan")


@dataclass
class ProgressHandle:
    mode_label: str
    status_line: str | None = None
    spinner: Spinner = field(default_factory=lambda: Spinner("dots", style="progress"))
    live: Live | None = None
    progress: Progress | None = None
    task_id: TaskID | None = None
    total_files: int = 0
    read_files_count: int = 0  # 읽은 파일 개수 추적


def start_progress(mode_label: str, total_files: int = 0) -> ProgressHandle:
    handle = ProgressHandle(mode_label=mode_label, total_files=total_files)
    
    # 파일 개수가 있으면 Progress bar 생성
    if total_files > 0:
        handle.progress = Progress(
            SpinnerColumn(),
            TextColumn("[progress.description]{task.description}"),
            TextColumn("({task.completed}/{task.total})"),
            console=console,
        )
        handle.task_id = handle.progress.add_task(
            f"파일 분석 중", total=total_files
        )
    
    initial_panel = render_progress_panel(
        handle.mode_label, handle.status_line, handle.spinner, handle.progress, progress_handle=handle
    )
    live = Live(initial_panel, console=console, refresh_per_second=12, transient=True)
    handle.live = live
    live.start()
    return handle


def update_status(handle: ProgressHandle | None, text: str) -> None:
    if not handle or not text or not handle.live:
        return
    if handle.status_line == text:
        return
    handle.status_line = text
    # 다음 단계로 넘어갔으면 파일 읽기 행을 숨기기 위해 카운트를 완료로 맞춤
    if text in POST_FILE_READ_STATUSES and handle.total_files > 0:
        handle.read_files_count = handle.total_files
        if handle.progress and handle.task_id is not None:
            handle.progress.update(handle.task_id, completed=handle.total_files)
    panel = render_progress_panel(
        handle.mode_label, handle.status_line, handle.spinner, handle.progress, progress_handle=handle
    )
    handle.live.update(panel, refresh=True)


def update_progress(handle: ProgressHandle | None, completed: int | None = None, advance: int = 1) -> None:
    """Progress bar 업데이트 (파일 개수 기준)"""
    if not handle or not handle.progress or not handle.task_id:
        return
    if completed is not None:
        handle.progress.update(handle.task_id, completed=completed)
    else:
        handle.progress.update(handle.task_id, advance=advance)
    if handle.live:
        panel = render_progress_panel(
            handle.mode_label, handle.status_line, handle.spinner, handle.progress, progress_handle=handle
        )
        handle.live.update(panel, refresh=True)


def update_file_read_progress(handle: ProgressHandle | None, completed: int | None = None, total: int | None = None) -> None:
    """파일 읽기 진행률 업데이트 (읽은 파일 수 / 전체 파일 수)"""
    if not handle:
        return
    
    # 파일 읽기 이후 단계로 넘어갔다면 더 이상 업데이트하지 않음
    if handle.status_line and handle.status_line in POST_FILE_READ_STATUSES:
        return
    
    # total이 제공되면 업데이트
    if total is not None and total > 0:
        handle.total_files = total
        # Progress bar가 없으면 생성
        if not handle.progress:
            handle.progress = Progress(
                SpinnerColumn(),
                TextColumn("[progress.description]{task.description}"),
                TextColumn("({task.completed}/{task.total})"),
                console=console,
            )
            handle.task_id = handle.progress.add_task(
                "파일 읽기 중", total=total
            )
        elif handle.task_id is not None:
            # 기존 task의 total 업데이트
            handle.progress.update(handle.task_id, total=total)
    
    # completed가 제공되면 업데이트
    if completed is not None:
        handle.read_files_count = completed
        if handle.progress and handle.task_id is not None:
            handle.progress.update(handle.task_id, completed=completed)
    else:
        # advance by 1
        handle.read_files_count += 1
        if handle.progress and handle.task_id is not None:
            handle.progress.update(handle.task_id, advance=1)
    
    # 패널 업데이트
    if handle.live:
        panel = render_progress_panel(
            handle.mode_label, handle.status_line, handle.spinner, handle.progress, progress_handle=handle
        )
        handle.live.update(panel, refresh=True)


def finish_progress(handle: ProgressHandle | None, delay_seconds: float = 0.35) -> None:
    if not handle or not handle.live:
        return
    handle.status_line = None
    done_panel = render_done_panel(handle.mode_label)
    handle.live.update(done_panel, refresh=True)
    if delay_seconds > 0:
        time.sleep(delay_seconds)
    handle.live.stop()
