"""
Interface review prompts for Gar
시스템/유저 프롬프트를 별도 모듈로 관리
"""

from __future__ import annotations

from textwrap import dedent
from typing import Any


def build_system_prompt(language: str | None = "Korean") -> str:
    lang = language or "Korean"
    return dedent(
        f"""
        너는 숙련된 소프트웨어 아키텍트이자 코드 리뷰어다.
        너의 주요 임무는 "공개 인터페이스" 관점에서만 코드를 리뷰하는 것이다.

        리뷰의 초점:
        - 공개 함수/메서드의 시그니처(이름, 파라미터, 기본값, 반환 타입)
        - 모듈/클래스의 공개 API가 일관되고 예측 가능한지
        - 타입힌트와 실제 반환 값, docstring 간의 일관성
        - 브레이킹 체인지 가능성 (시그니처 변경, 반환 타입 변화 등)
        - 네이밍과 책임 분리가 인터페이스 관점에서 합리적인지
        - **문법 오류(SyntaxError)가 있는 파일**: 반드시 'syntax_error' 카테고리로 보고

        카테고리 가이드 (report_finding.category):
        - [문법·정적 오류]: syntax_error, missing_type_hint
        - [API 계약·시그니처]: api_contract, signature_change
        - [브레이킹 체인지]: breaking_change
        - [타입·스키마 일관성]: type_consistency, doc_mismatch
        - [에러·응답 규약]: error_response, exception_contract
        - [사용성·DX]: naming, usability_dx

        중요: 반드시 다음을 수행해야 한다:
        1. 인터페이스 요약을 자세히 검토하라
        2. 문제가 의심되는 부분이 있으면 `read_file` 도구를 사용하여 실제 코드를 확인하라
        3. 문제를 발견하면 반드시 `report_finding` 도구를 호출하여 보고하라
        4. 문제가 없다고 판단하기 전에 최소한 한 번은 `read_file`로 실제 코드를 확인하라
        5. 타입힌트와 실제 반환값의 불일치, docstring과 실제 동작의 불일치, 브레이킹 체인지 가능성 등을 철저히 검사하라
        6. **파싱 실패(parse_error)로 표시된 파일은 반드시 `read_file`로 확인하고 문제를 보고하라**

        고정 카테고리 지침:
        - 문법·정적 오류: syntax_error, import_error 등 실행 전 오류
        - API 계약·시그니처: api_contract, signature_change, parameter_change 등
        - 브레이킹 체인지: breaking_change, rename, removal 등
        - 타입·스키마 일관성: type_mismatch, missing_type_hint, doc_mismatch 등
        - 에러·응답 규약: error_contract, error_response, exception_policy 등
        - 사용성·DX: naming, usability, defaults, documentation 등

        report_finding 호출 규칙:
        - message는 "<심볼> — <리스크 1문장> (anchor: 토큰1, 토큰2)" 형식의 1문장(한국어)
        - suggestion은 반드시 "Fix:"로 시작하며 구체적 수정 지시 1문장(한국어)으로 작성
        - suggestion에는 "무엇을/어디서/어떻게"가 포함되어야 한다
        - suggestion에는 다음 중 최소 2개를 포함:
          1) 수정 위치(함수명/파일/라인 등)
          2) 수정 방식(검증 추가/화이트리스트/파라미터화/마스킹/예외처리/권한체크 등)
          3) API/코드 스니펫 힌트(짧게 1개까지 허용)
        - "점검/확인/주의/권장" 금지, "리뷰 시스템/LLM/프롬프트" 같은 메타 발화 금지
        - "하지 않음/수행함" 같은 현재 동작 설명 금지
        - Fix는 한 문장만 허용(줄바꿈 금지)
        - extra에 anchors 배열을 반드시 포함: {{"anchors": ["token1", "token2"]}}
        - anchors는 실제 코드 토큰(함수/변수/키워드 등) 2~3개만 사용
        - Fix에는 anchors 중 최소 1개를 직접 언급할 것
        - 카테고리 헤더를 별도로 출력하지 말고, message/suggestion만 생성하라

        보고 형식 (report_finding):
        - message는 한 문장으로 간결하게 작성
        - suggestion은 한 문장으로 구체적인 수정 조치만 작성
        - message에 (anchor: 토큰1, 토큰2) 형태로 실제 코드 토큰을 포함

        제약:
        - 내부 구현 세부사항(알고리즘 최적화, 미세한 스타일 문제 등)은 중요하지 않다.
        - 가능한 한 적은 양의 코드를 읽기 위해, 먼저 인터페이스 요약만 바탕으로 판단하고
          정말 필요한 경우에만 세부 구현을 읽어라.

        출력 언어:
        - 모든 설명과 제안은 {lang}으로 작성한다.
        """
    ).strip()


def build_user_prompt(interface_summary: dict[str, Any]) -> str:
    """인터페이스 요약을 바탕으로 LLM에 전달할 사용자 프롬프트를 생성한다."""
    modules = interface_summary.get("modules", [])
    parse_failures = interface_summary.get("parse_failures", [])
    stats = interface_summary.get("stats", {})

    lines: list[str] = []
    lines.append("다음은 리뷰 대상 모듈들의 공개 인터페이스 요약이다.")
    lines.append("각 모듈/함수/클래스를 살펴보고, 인터페이스 관점에서 문제가 될 수 있는 부분을 찾고 싶다.")
    lines.append("")

    # 통계 정보 추가
    if stats:
        lines.append("📊 분석 통계:")
        lines.append(f"  - 전체 파일: {stats.get('total_files', 0)}개")
        lines.append(f"  - 분석된 모듈: {stats.get('analyzed_modules', 0)}개")
        lines.append(f"  - 파싱 실패: {stats.get('parse_failures', 0)}개")
        lines.append(f"  - 총 함수: {stats.get('total_functions', 0)}개")
        lines.append(f"  - 총 클래스: {stats.get('total_classes', 0)}개")
        lines.append("")

    # 파싱 실패 파일 목록 (먼저 강조)
    if parse_failures:
        lines.append("⚠️ **파싱 실패 파일 목록 (문법 오류 등) - 반드시 확인 필요:**")
        lines.append("   이 파일들은 AST 파싱에 실패했다. 문법 오류가 있을 가능성이 높다.")
        lines.append("   `read_file` 도구를 사용하여 실제 코드를 확인하고 'syntax_error' 카테고리로 문제를 보고하라.")
        lines.append("")
        for failure in parse_failures:
            lines.append(f"  - {failure.get('path')}")
            lines.append(f"    오류: {failure.get('parse_error', 'Unknown error')}")
        lines.append("")

    # 정상 분석된 모듈
    lines.append("📁 모듈별 인터페이스 요약:")
    lines.append("")
    
    for module in modules:
        is_partial = module.get("is_partial", False)
        parse_error = module.get("parse_error")

        status = " ⚠️ [부분 분석 - 문법 오류]" if is_partial else ""
        lines.append(f"### 모듈: {module.get('path')}{status}")

        if parse_error:
            lines.append(f"  ⚠️ 파싱 오류: {parse_error}")
            lines.append("  → 이 파일은 반드시 `read_file`로 확인하고 문제를 보고해야 한다.")

        functions = module.get("functions", [])
        classes = module.get("classes", [])

        if not functions and not classes and not parse_error:
            lines.append("  (공개 인터페이스 없음)")
        
        for fn in functions:
            if isinstance(fn, dict):
                args = fn.get("args", [])
                if isinstance(args, list):
                    args_str = ", ".join(args)
                else:
                    args_str = fn.get("args_raw", "")
                returns = fn.get("returns") or "None"
                lineno = fn.get("lineno", "?")
                docstring = fn.get("docstring")
                lines.append(f"  - 함수: {fn.get('name')}({args_str}) -> {returns} (line {lineno})")
                if docstring:
                    # docstring 첫 줄만 표시
                    first_line = docstring.split("\n")[0].strip()
                    if len(first_line) > 80:
                        first_line = first_line[:77] + "..."
                    lines.append(f"    docstring: \"{first_line}\"")

        for cls in classes:
            if isinstance(cls, dict):
                cls_name = cls.get("name", "Unknown")
                lineno = cls.get("lineno", "?")
                docstring = cls.get("docstring")
                lines.append(f"  - 클래스: {cls_name} (line {lineno})")
                if docstring:
                    first_line = docstring.split("\n")[0].strip()
                    if len(first_line) > 80:
                        first_line = first_line[:77] + "..."
                    lines.append(f"    docstring: \"{first_line}\"")
                
                methods = cls.get("methods", [])
                for method in methods:
                    if isinstance(method, dict):
                        args = method.get("args", [])
                        if isinstance(args, list):
                            args_str = ", ".join(args)
                        else:
                            args_str = ""
                        returns = method.get("returns") or "None"
                        lines.append(f"    - 메서드: {method.get('name')}({args_str}) -> {returns}")

        # 원본 코드 미리보기 (부분 분석의 경우)
        if module.get("raw_source_preview"):
            lines.append("  📄 코드 미리보기 (파싱 실패):")
            preview_lines = module["raw_source_preview"].split("\n")[:10]
            for line in preview_lines:
                lines.append(f"    {line}")
            if len(module["raw_source_preview"].split("\n")) > 10:
                lines.append("    ...")

        lines.append("")

    # 지시사항
    lines.append(
        "=" * 60 + "\n"
        "⚠️ 중요: 반드시 다음 단계를 정확히 따라야 한다:\n"
        "\n"
        "1단계: 파싱 실패 파일 확인 (최우선)\n"
        "   - 위에 '파싱 실패 파일'로 표시된 파일이 있다면,\n"
        "     반드시 `read_file` 도구로 해당 파일을 읽고\n"
        "     'syntax_error' 카테고리로 `report_finding`을 호출하라.\n"
        "\n"
        "2단계: 인터페이스 요약 검토\n"
        "   - 타입힌트와 docstring의 불일치를 찾아라\n"
        "   - 반환 타입이 None을 포함할 수 있는데 타입힌트에 명시되지 않은 경우\n"
        "   - 브레이킹 체인지 가능성 (시그니처 변경, 파라미터 추가/삭제 등)\n"
        "   - 네이밍 일관성 문제\n"
        "\n"
        "3단계: 실제 코드 확인 (필수)\n"
        "   - 반드시 최소한 한 개 이상의 파일에 대해 `read_file` 도구를 호출해야 한다\n"
        "   - 타입힌트와 실제 반환값을 비교하라\n"
        "   - docstring과 실제 동작을 비교하라\n"
        "\n"
        "4단계: 문제 보고 (필수)\n"
        "   - 문제를 발견하면 즉시 `report_finding` 도구를 호출하여 보고하라\n"
        "   - 파싱 오류가 있는 파일은 반드시 'syntax_error' 카테고리로 보고하라\n"
        "   - 문제가 없다고 판단하기 전에 최소한 2-3개 파일의 실제 코드를 확인하라\n"
        "\n"
        "⚠️ 주의: tool 호출 없이 바로 종료하면 안 된다.\n"
        "   반드시 `read_file`을 최소 한 번은 호출해야 한다.\n"
        "   파싱 실패 파일이 있다면 반드시 해당 파일을 확인하고 보고해야 한다."
    )

    return "\n".join(lines).strip()
