"""Interface review CLI utilities.

이 모듈은 interface 리뷰 모드에서 사용되는 유틸리티 함수들을 제공합니다.
실제 CLI 진입점은 common/cli.py에 있습니다.
"""

from __future__ import annotations

import logging
import os
import re
from pathlib import Path

from rich.panel import Panel

from common.context import ReviewFinding, ReviewReport
from common.file_collector import CollectionResult, FileCollector, FileCollectorConfig
from common.render import render_review_panel
from common.ui import console

logger = logging.getLogger(__name__)


def _expand_paths(paths: list[str], verbose: bool = False) -> tuple[list[Path], CollectionResult]:
    """경로 리스트를 확장하여 Python 파일 목록 반환.

    Args:
        paths: 파일 또는 디렉터리 경로 리스트. 비어 있으면 프로젝트 루트 전체 검사.
        verbose: 상세 로그 출력 여부

    Returns:
        (Python 파일 Path 리스트, 수집 결과)
    """
    config = FileCollectorConfig(
        extensions=frozenset({".py"}),
        include_empty=True,  # 빈 파일도 포함 (분석 대상)
    )
    collector = FileCollector(config)

    if not paths:
        # 경로가 없으면 프로젝트 루트의 모든 Python 파일 검사
        result = collector.collect_from_root()
    else:
        # 지정된 경로들 검사
        resolved_paths: list[Path] = []
        for raw in paths:
            p = Path(raw)
            if not p.is_absolute():
                p = Path(".") / p
            p = p.resolve()

            if not p.exists():
                if os.getenv("GAR_DEBUG") == "1":
                    console.print(f"[warning]경로를 찾을 수 없습니다: {raw} (건너뜀)[/warning]")
                continue

            resolved_paths.append(p)

        result = collector.collect(resolved_paths)

    # 수집 결과 로깅
    if verbose:
        if result.skipped_count > 0:
            logger.debug(f"건너뛴 항목: {result.skipped_count}개")
            for path, reason in result.skipped[:5]:
                logger.debug(f"  - {path}: {reason}")
            if result.skipped_count > 5:
                logger.debug(f"  ... 외 {result.skipped_count - 5}개")

        if result.error_count > 0:
            logger.warning(f"오류 발생 항목: {result.error_count}개")
            for path, error in result.errors:
                logger.warning(f"  - {path}: {error}")

    return result.valid_files, result


INTERFACE_SECTION_ORDER = [
    ("syntax", "문법·정적 오류"),
    ("api", "API 계약·시그니처"),
    ("breaking", "브레이킹 체인지"),
    ("type", "타입·스키마 일관성"),
    ("error", "에러·응답 규약"),
    ("dx", "사용성·DX"),
]


def _extract_anchor_tokens(text: str, max_tokens: int = 3) -> list[str]:
    if not text:
        return []
    candidates = re.findall(r"[A-Za-z_][A-Za-z0-9_]*", text)
    seen: set[str] = set()
    tokens: list[str] = []
    for token in candidates:
        if token in seen:
            continue
        seen.add(token)
        tokens.append(token)
        if len(tokens) >= max_tokens:
            break
    return tokens


def _extract_anchor_from_message(message: str) -> list[str]:
    match = re.search(r"\(anchor:\s*([^)]+)\)", message)
    if not match:
        return []
    raw = match.group(1)
    tokens = [t.strip() for t in raw.split(",") if t.strip()]
    return tokens[:3]


def _strip_anchor_suffix(message: str) -> str:
    return re.sub(r"\s*\(anchor:.*?\)\s*$", "", message).strip()


def _map_interface_section(category: str) -> str | None:
    cat = (category or "").lower()
    if cat in {"syntax_error", "missing_type_hint"} or "syntax" in cat:
        return "syntax"
    if "breaking" in cat:
        return "breaking"
    if "api" in cat or "contract" in cat or "signature" in cat:
        return "api"
    if "type" in cat or "schema" in cat or "doc_mismatch" in cat:
        return "type"
    if "error" in cat or "exception" in cat or "response" in cat:
        return "error"
    if "naming" in cat or "dx" in cat or "usability" in cat:
        return "dx"
    return None


def _build_interface_sections(findings: list[ReviewFinding]) -> dict[str, list[tuple[str, str]]]:
    sections = {key: [] for key, _label in INTERFACE_SECTION_ORDER}
    for f in findings:
        if f.category == "system":
            continue
        section_key = _map_interface_section(f.category)
        if not section_key:
            continue
        anchors: list[str] = []
        if isinstance(f.extra, dict):
            raw_anchors = f.extra.get("anchors")
            if isinstance(raw_anchors, list):
                anchors = [str(a).strip() for a in raw_anchors if str(a).strip()][:3]
        if not anchors:
            anchors = _extract_anchor_from_message(f.message)
        if not anchors:
            anchors = _extract_anchor_tokens(f.message)
        if not anchors:
            continue
        if not f.suggestion:
            continue
        if f.file:
            try:
                filename = os.path.relpath(f.file, os.getcwd())
            except ValueError:
                filename = str(f.file)
        else:
            filename = "unknown"
        # 줄번호가 있으면 (line: 번호) 형식으로 추가
        if f.line:
            location = f"{filename}:{anchors[0]} (line: {f.line})"
        else:
            location = f"{filename}:{anchors[0]}"
        message = _strip_anchor_suffix(f.message)
        anchor_text = ", ".join(anchors)
        risk_line = f"{location} — {message} (anchor: {anchor_text})"
        sections[section_key].append((risk_line, f.suggestion.strip()))
    return sections


def _format_interface_panel(report: ReviewReport) -> Panel:
    files = [f.file.name for f in report.findings if f.file]
    summary = ", ".join(dict.fromkeys(files))
    if len(summary) > 80:
        summary = summary[:77] + "..."
    header = summary if summary else "no files"
    sections = _build_interface_sections(report.findings)

    return render_review_panel(
        mode="interface",
        file_summary=header,
        section_order=INTERFACE_SECTION_ORDER,
        sections=sections,
        title="Interface Review",
    )


def build_interface_panel(report: ReviewReport) -> Panel:
    """리뷰 리포트를 패널로 반환 (고정 카테고리 헤더)"""
    return _format_interface_panel(report)


