"""리뷰 프로세스 관련 UI 표시를 위한 모듈."""

import json
import threading
import time
import types
from collections.abc import Generator
from contextlib import contextmanager
from pathlib import Path
from typing import TYPE_CHECKING

from rich.align import Align
from rich.console import Console, Group
from rich.live import Live
from rich.panel import Panel
from rich.progress import BarColumn, Progress, SpinnerColumn, TextColumn
from rich.syntax import Syntax
from rich.table import Table
from rich.text import Text

from selvage.src.utils.base_console import console

if TYPE_CHECKING:
    from selvage.src.model_config import ModelInfoDict
    from selvage.src.utils.token.models import EstimatedCost


def _format_token_count(count: int) -> str:
    """토큰 수를 축약된 형태로 포맷팅합니다."""
    if count >= 1000:
        return f"{count / 1000:.1f}k"
    return str(count)


def _shorten_path(path: str) -> str:
    """경로를 축약된 형태로 표시합니다."""
    import os

    # 홈 디렉토리 축약
    path = path.replace(str(Path.home()), "~")

    # 경로가 너무 길면 가운데를 생략
    if len(path) > 60:
        parts = path.split(os.sep)
        if len(parts) > 3:
            # 앞 2개와 뒤 1개만 남기고 ...으로 생략
            shortened = os.sep.join(parts[:2] + ["..."] + parts[-1:])
            return shortened

    return path


def _load_review_log(log_path: str) -> dict | None:
    """리뷰 로그 파일을 로드합니다."""
    try:
        with open(log_path, encoding="utf-8") as f:
            return json.load(f)
    except (FileNotFoundError, json.JSONDecodeError, UnicodeDecodeError):
        console.error(f"Cannot read review log file: {log_path}")
        return None


def _format_severity_badge(severity: str) -> str:
    """심각도 배지를 생성합니다."""
    severity_upper = severity.upper()
    if severity_upper == "HIGH":
        return "[bold red]HIGH[/bold red]"
    elif severity_upper == "MEDIUM":
        return "[bold yellow]MEDIUM[/bold yellow]"
    elif severity_upper == "LOW":
        return "[bold blue]LOW[/bold blue]"
    else:
        return "[bold cyan]INFO[/bold cyan]"


def _detect_language_from_filename(filename: str) -> str:
    """파일명에서 프로그래밍 언어를 추론합니다."""
    if not filename:
        return "text"

    ext = Path(filename).suffix.lower()
    language_map = {
        ".py": "python",
        ".js": "javascript",
        ".ts": "typescript",
        ".jsx": "jsx",
        ".tsx": "tsx",
        ".java": "java",
        ".cpp": "cpp",
        ".c": "c",
        ".h": "c",
        ".hpp": "cpp",
        ".cs": "csharp",
        ".php": "php",
        ".rb": "ruby",
        ".go": "go",
        ".rs": "rust",
        ".swift": "swift",
        ".kt": "kotlin",
        ".scala": "scala",
        ".sql": "sql",
        ".html": "html",
        ".css": "css",
        ".scss": "scss",
        ".sass": "sass",
        ".json": "json",
        ".xml": "xml",
        ".yaml": "yaml",
        ".yml": "yaml",
        ".toml": "toml",
        ".md": "markdown",
        ".sh": "bash",
        ".bash": "bash",
        ".zsh": "zsh",
        ".fish": "fish",
    }

    return language_map.get(ext, "text")


def _create_syntax_block(code: str, filename: str = "") -> Syntax:
    """코드 블록을 구문 강조와 함께 생성합니다."""
    language = _detect_language_from_filename(filename)

    return Syntax(
        code.strip(),
        language,
        theme="monokai",
        line_numbers=True,
        word_wrap=True,
        background_color="default",
    )


def _create_recommendations_panel(recommendations: list) -> Panel:
    """추천사항을 패널로 생성합니다."""
    if not recommendations:
        content = "[dim]No recommendations available.[/dim]"
    else:
        content_lines = []
        for i, rec in enumerate(recommendations, 1):
            content_lines.append(f"[bold cyan]{i}.[/bold cyan] {rec}")
        content = "\n".join(content_lines)

    return Panel(
        content,
        title="[bold green]Recommendations[/bold green]",
        border_style="green",
        padding=(1, 2),
    )


class ProgressDisplay:
    """통합된 진행 상황 표시 클래스 (컨텍스트 매니저 + 직접 사용 모두 지원)."""

    def __init__(
        self, model: str, console: Console, manual_refresh: bool = True
    ) -> None:
        """통합 진행 상황 표시를 초기화합니다.

        Args:
            model: 모델명
            console: Rich Console 인스턴스
            manual_refresh: True면 수동 refresh (새 패턴),
                False면 자동 refresh (레거시 호환)
        """
        self.model = model
        self.console = console
        self.manual_refresh = manual_refresh
        self.progress = Progress(
            SpinnerColumn(),
            TextColumn("[progress.description]{task.description}"),
            BarColumn(),
            transient=False,
        )
        self.task = self.progress.add_task(
            "Analyzing code and generating review...", total=100
        )
        self.live = None
        self.stop_progress = threading.Event()
        self.progress_thread = None
        self.current_message = "Analyzing code and generating review..."
        self._panel = None

    def _create_panel(self) -> Panel:
        """현재 모드에 맞는 패널을 생성합니다."""
        title = Text("Selvage : Code reviews with an edge!", style="bold cyan")
        model_info = Text(f"Model: {self.model}", style="dim")

        content = Group(
            Align.center(title),
            Text(""),
            Align.center(model_info),
            Text(""),
            self.progress,
        )

        return Panel(
            content,
            title="[bold]Code Review in Progress[/bold]",
            border_style="blue",
            width=70,
            padding=(1, 2),
        )

    def _update_progress(self) -> None:
        """백그라운드에서 물결치는 진행률을 업데이트합니다."""
        step = 0
        while not self.stop_progress.is_set():
            cycle_length = 50
            progress_value = (step % cycle_length) * (100 / cycle_length)
            self.progress.update(self.task, completed=progress_value)
            self._on_progress_update()
            step += 1
            time.sleep(0.1)

    def _on_progress_update(self) -> None:
        """Progress 업데이트 시 필요에 따라 명시적 refresh."""
        if self.manual_refresh and self.live:
            self.live.refresh()

    def update_message(self, message: str) -> None:
        """진행 상황 메시지를 업데이트합니다."""
        self.current_message = message
        self.progress.update(self.task, description=message)
        # manual_refresh 모드일 때만 강제 refresh
        if self.manual_refresh and self.live:
            self.live.refresh()

    def transition_to_multiturn(self, message: str) -> None:
        """멀티턴 처리 모드로 부드럽게 전환합니다."""
        self.update_message(message)
        # Live display를 강제로 재시작하여 UI 정리
        if self.live:
            self.live.stop()
            self.live.start()

    def complete(self) -> None:
        """정상 완료 시 진행 상황 표시를 종료합니다."""
        if self.stop_progress:
            self.stop_progress.set()
        if self.progress_thread:
            self.progress_thread.join()

        # 완료 시 100%로 설정
        self.progress.update(self.task, completed=100)
        if self.live:
            time.sleep(0.5)  # 완료 상태를 잠시 보여줌
            self.live.stop()

    # === 컨텍스트 매니저 지원 ===
    def __enter__(self) -> "ProgressDisplay":
        """컨텍스트 매니저 시작."""
        self.start()
        return self

    def __exit__(
        self,
        exc_type: type[BaseException] | None,
        exc_val: BaseException | None,
        exc_tb: types.TracebackType | None,
    ) -> None:
        """컨텍스트 매니저 종료."""
        self.stop()

    # === 진행 상황 제어 메서드 ===
    def start(self) -> None:
        """진행 상황 표시를 시작합니다."""
        self._panel = self._create_panel()
        self.live = Live(
            self._panel,
            refresh_per_second=10,
            console=self.console,
            transient=True,
            auto_refresh=not self.manual_refresh,  # manual_refresh에 따라 결정
        )
        self.live.start()

        self.progress_thread = threading.Thread(target=self._update_progress)
        self.progress_thread.start()

    def stop(self) -> None:
        """진행 상황 표시를 즉시 종료합니다."""
        if self.stop_progress:
            self.stop_progress.set()
        if self.progress_thread:
            self.progress_thread.join()

        if self.live:
            self.live.stop()


class ReviewDisplay:
    """리뷰 프로세스 관련 UI 표시를 관리하는 클래스."""

    def __init__(self) -> None:
        """디스플레이 인스턴스를 초기화합니다."""
        self.console = Console()

    def model_info(self, model_name: str, description: str) -> None:
        """모델 정보를 Panel로 출력합니다."""
        content = f"[bold cyan]{model_name}[/bold cyan]\n[dim]{description}[/dim]"

        panel = Panel.fit(
            content,
            title="[bold]Review AI Model[/bold]",
            border_style="cyan",
        )
        self.console.print(panel)

    def log_saved(self, log_path: str) -> None:
        """리뷰 로그 저장 완료 메시지를 Panel로 출력합니다."""

        # 경로를 간단하게 표시 (홈 디렉토리는 ~ 로 표시)
        simplified_path = _shorten_path(log_path)

        # Panel content composition
        content = (
            f"[bold green]Save Complete[/bold green]\n[dim]{simplified_path}[/dim]"
        )

        panel = Panel.fit(
            content,
            title="[bold]Result Saved[/bold]",
            border_style="green",
        )
        self.console.print(panel)

    def review_complete(
        self,
        model_info: "ModelInfoDict",
        log_path: str,
        estimated_cost: "EstimatedCost",
    ) -> None:
        """리뷰 완료 결과를 통합된 Panel로 출력합니다."""
        # 토큰 정보를 축약된 형태로 표시
        token_info = (
            f"{_format_token_count(estimated_cost.input_tokens)} → "
            f"{_format_token_count(estimated_cost.output_tokens)} tokens"
        )

        # 경로를 간단하게 표시
        simplified_path = _shorten_path(log_path)

        # Integrated Panel content composition
        content = (
            f"[bold cyan]Model:[/bold cyan] [white]{model_info['full_name']}[/white]\n"
            f"[dim]{model_info['description']}[/dim]\n\n"
            f"[bold yellow]Cost:[/bold yellow] "
            f"[white]{estimated_cost.total_cost_usd}[/white] "
            f"[dim]({token_info})[/dim]\n"
            "[dim]* Estimated cost. Check exact cost from each AI service.[/dim]\n\n"
            f"[bold green]Saved:[/bold green] [white]{simplified_path}[/white]"
        )

        panel = Panel(
            Align.center(content),
            title="[bold]Code Review Complete[/bold]",
            border_style="cyan",
            width=80,
            padding=(1, 2),
        )

        self.console.print(panel)

    def print_review_result(self, log_path: str, use_pager: bool = True) -> None:
        """리뷰 결과를 터미널에 출력합니다."""

        log_data = _load_review_log(log_path)
        if not log_data:
            return

        review_response = log_data.get("review_response")
        if not review_response:
            console.error("No review response data available.")
            return

        model_info = log_data.get("model", {})
        model_name = model_info.get("name", "Unknown")

        # 요약 정보 패널
        summary = review_response.get("summary", "")
        score = review_response.get("score")
        issues = review_response.get("issues", [])
        recommendations = review_response.get("recommendations", [])

        # Summary panel creation
        summary_content = f"[bold cyan]Model:[/bold cyan] {model_name}\n\n"
        summary_content += (
            f"[bold yellow]Overall Score:[/bold yellow] {score}/10\n\n" if score else ""
        )
        summary_content += f"[bold red]Issues Found:[/bold red] {len(issues)}\n\n"
        summary_content += (
            f"[bold green]Recommendations:[/bold green] {len(recommendations)}\n\n"
        )

        if summary:
            summary_content += f"[bold white]Summary:[/bold white]\n{summary}"

        summary_panel = Panel(
            summary_content,
            title="[bold]Review Result Summary[/bold]",
            border_style="cyan",
            padding=(1, 2),
        )

        # 출력 함수 정의
        def _print_content() -> None:
            # 요약 패널 출력
            self.console.print(summary_panel)
            self.console.print()

            # 이슈 정보 출력
            if issues:
                self.console.print("[bold cyan]Issue Details[/bold cyan]\n")
                for i, issue in enumerate(issues, 1):
                    severity = issue.get("severity", "INFO").upper()
                    # file과 file_name 둘 다 확인
                    file_name = issue.get("file") or issue.get("file_name", "")
                    line_number = issue.get("line_number", "")
                    description = issue.get("description", "")
                    suggestion = issue.get("suggestion", "")
                    target_code = issue.get("target_code", "")
                    suggested_code = issue.get("suggested_code", "")

                    # Issue content composition (increased spacing between items)
                    issue_content = f"[bold]Severity:[/bold] {severity}\n\n"
                    issue_content += f"[bold]File:[/bold] {file_name}"
                    if line_number:
                        issue_content += f" (line {line_number})"
                    issue_content += f"\n\n[bold]Description:[/bold]\n{description}"

                    if suggestion:
                        issue_content += f"\n\n[bold]Suggestion:[/bold]\n{suggestion}"

                    border_style = (
                        "red"
                        if severity == "HIGH"
                        else "yellow"
                        if severity == "MEDIUM"
                        else "blue"
                    )

                    issue_panel = Panel(
                        issue_content,
                        title=f"[bold]{i}. {severity}[/bold]",
                        border_style=border_style,
                        padding=(1, 2),
                    )
                    self.console.print(issue_panel)

                    # 코드 블록이 있는 경우 별도 패널로 출력
                    if target_code or suggested_code:
                        if target_code:
                            self.console.print()
                            current_syntax = _create_syntax_block(
                                target_code, file_name
                            )
                            current_panel = Panel(
                                current_syntax,
                                title="[bold red]Current Code[/bold red]",
                                border_style="red",
                                padding=(0, 1),
                            )
                            self.console.print(current_panel)

                        if suggested_code:
                            self.console.print()
                            suggested_syntax = _create_syntax_block(
                                suggested_code, file_name
                            )
                            suggested_panel = Panel(
                                suggested_syntax,
                                title="[bold green]Improved Code[/bold green]",
                                border_style="green",
                                padding=(0, 1),
                            )
                            self.console.print(suggested_panel)

                    self.console.print()  # 이슈 사이 간격
            else:
                self.console.print("[bold green]No issues found![/bold green]")

            # 추천사항 출력
            if recommendations:
                self.console.print()
                rec_panel = _create_recommendations_panel(recommendations)
                self.console.print(rec_panel)

        # Pager 사용 여부에 따라 출력
        if use_pager:
            # Pager로 출력 (스크롤링 가능)
            with self.console.pager(styles=True):
                _print_content()
        else:
            # 직접 출력 (테스트용)
            _print_content()

    @contextmanager
    def enhanced_progress_review(
        self, model: str
    ) -> Generator[ProgressDisplay, None, None]:
        """메시지 업데이트 기능이 있는 진행 상황 표시를 제공합니다."""
        # ProgressDisplay는 자체적으로 컨텍스트 매니저이므로 더 간단해짐
        with ProgressDisplay(model, self.console, manual_refresh=True) as progress:
            yield progress

    def create_updatable_progress(self, model: str) -> ProgressDisplay:
        """업데이트 가능한 진행 상황 표시를 생성합니다."""
        return ProgressDisplay(model, self.console, manual_refresh=True)

    @contextmanager
    def progress_review(self, model: str) -> Generator[None, None, None]:
        """코드 리뷰 진행 상황을 통합된 Panel로 표시합니다."""
        # Progress 설정 (퍼센트 표시 제거)
        progress = Progress(
            SpinnerColumn(),
            TextColumn("[progress.description]{task.description}"),
            BarColumn(),
            transient=False,
        )

        task = progress.add_task("Analyzing code and generating review...", total=100)

        # Panel을 한 번만 생성하여 고정
        title = Text("Selvage : Code reviews with an edge!", style="bold cyan")
        model_info = Text(f"Model: {model}", style="dim")

        content = Group(
            Align.center(title),
            Text(""),  # 빈 줄
            Align.center(model_info),
            Text(""),  # 빈 줄
            progress,  # Progress 객체는 내부적으로 업데이트됨
        )

        panel = Panel(
            content,
            title="[bold]Code Review in Progress[/bold]",
            border_style="blue",
            width=70,
            padding=(1, 2),
        )

        # 고정된 Panel 객체를 Live에 전달
        with Live(
            panel, refresh_per_second=10, console=self.console, transient=True
        ) as _:
            # 백그라운드에서 물결치는 진행률 업데이트
            stop_progress = threading.Event()

            def update_progress() -> None:
                step = 0
                while not stop_progress.is_set():
                    # 톱니파 패턴: 0에서 100까지 갔다가 다시 0에서 시작
                    cycle_length = 50  # 한 사이클의 길이 (조절 가능)
                    progress_value = (step % cycle_length) * (100 / cycle_length)
                    progress.update(task, completed=progress_value)

                    step += 1
                    time.sleep(0.1)

            progress_thread = threading.Thread(target=update_progress)
            progress_thread.start()

            try:
                yield
            finally:
                stop_progress.set()
                progress_thread.join()
                # 완료 시에는 100%로 설정하고 잠시 보여준 후 사라지게 함
                progress.update(task, completed=100)
                time.sleep(0.5)  # 완료 상태를 잠시 보여줌

    def show_available_models(self) -> None:
        """사용 가능한 모든 AI 모델을 가독성 있게 표시합니다."""
        from selvage.src.model_config import ModelConfig
        from selvage.src.models.model_provider import ModelProvider

        try:
            model_config = ModelConfig()
            all_models_config = model_config.get_all_models_config()

            if not all_models_config:
                console.error("Cannot load model configuration.")
                return

            # 제목 출력
            self.console.print("\n[bold cyan]Available AI Model List[/bold cyan]\n")

            # 프로바이더별로 그룹화
            providers_data = {}
            for model_key, model_info in all_models_config.items():
                provider = model_info["provider"]
                if provider not in providers_data:
                    providers_data[provider] = []
                providers_data[provider].append((model_key, model_info))

            # 각 프로바이더별로 테이블 생성
            for provider in [
                ModelProvider.OPENAI,
                ModelProvider.ANTHROPIC,
                ModelProvider.GOOGLE,
                ModelProvider.OPENROUTER,
            ]:
                if provider not in providers_data:
                    continue

                # 프로바이더별 테이블 생성
                table = Table(
                    title=f"[bold]{provider.get_display_name()}[/bold]",
                    show_header=True,
                    header_style="bold magenta",
                    border_style="blue",
                )
                table.add_column("Model Name", style="cyan", no_wrap=True)
                table.add_column("Aliases", style="green")
                table.add_column("Description", style="white")
                table.add_column("Context", style="yellow", justify="right")

                # 모델 정보 추가
                for model_key, model_info in providers_data[provider]:
                    aliases = ", ".join(model_info.get("aliases", []))
                    description = model_info.get("description", "")
                    context_limit = f"{model_info.get('context_limit', 0):,}"

                    table.add_row(
                        model_key,
                        aliases if aliases else "-",
                        description,
                        context_limit,
                    )

                self.console.print(table)
                self.console.print()  # 빈 줄 추가

            # 사용법 안내
            self.console.print(
                "[dim]Usage: [/dim][bold]selvage review --model "
                "<model_name_or_alias>[/bold]"
            )
            self.console.print(
                "[dim]Default model setting: [/dim]"
                "[bold]selvage config model <model_name>[/bold]"
            )

        except Exception as e:
            console.error(
                f"Error occurred while retrieving model list: {str(e)}", exception=e
            )


# 전역 리뷰 디스플레이 인스턴스
review_display = ReviewDisplay()
