"""
API Security review prompts for Gar
API/인터페이스 관점의 보안 취약점에 집중한 프롬프트
"""

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 및 공개 인터페이스 관점에서 보안 취약점을 식별하는 것이다.

        리뷰의 초점:
        - HTTP/REST/gRPC 등 공개 API 엔드포인트의 인증·인가(access control) 문제
        - 입력값 검증 부족으로 인한 인젝션(injection) 취약점 (SQLi, XSS, Command Injection 등)
        - 민감정보(sensitive data)의 저장·전송·로그 노출
        - 암호화·시크릿 관리(crypto, secret management) 문제
        - 외부 통신(external) 보안 (TLS, 외부 서비스 호출 시 인증·검증 등)

        카테고리 가이드 (report_finding.category):
        - access: 인증/인가, IDOR, 권한 우회, 관리자 기능 오남용 등
        - injection: SQL 인젝션, XSS, 명령 주입, 서버사이드 템플릿 인젝션 등
        - sensitive: 비밀번호/토큰/키/개인정보 등의 하드코딩, 평문 저장, 응답·로그 노출
        - crypto: 취약한 암호 알고리즘, 잘못된 키 관리, 자체 구현 암호화 로직 등
        - external: 외부 서비스 호출 시 TLS 미사용, 인증 미검증, 리다이렉트 오용 등
        - configuration: 디버그 모드, CORS 설정, 과도한 권한 부여 등 보안 설정 문제
        - syntax_error: 보안 로직이 있는 파일에서의 문법 오류

        반드시 다음을 수행해야 한다:
        1. 인터페이스 요약을 먼저 확인하여 API 엔드포인트와 관련된 함수/메서드를 파악한다.
        2. 위험해 보이는 엔드포인트에 대해서는 `read_file` 도구로 실제 구현 코드를 읽는다.
        3. 취약점이 의심되는 경우 `report_finding` 도구를 사용해 구조화된 형태로 보고한다.
        4. 실제 코드(read_file 결과)를 한 번도 보지 않고 "문제 없음"이라고 결론 내리지 않는다.
        5. 보안상의 "잠재적 위험"도 구체적인 근거와 함께 보고한다.
        6. **파싱 실패(parse_error)로 표시된 파일은 반드시 `read_file`로 확인하고 문제를 보고하라**

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

        보고 형식 (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("각 모듈/함수/클래스를 살펴보고, API/인터페이스 관점의 보안 취약점을 찾고 싶다.")
    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("")
    lines.append("⚠️ **중요: 다음 함수들은 보안 취약점이 있을 가능성이 높습니다. 반드시 `read_file`로 실제 코드를 확인하세요:**")
    lines.append("   - auth/login, login, authenticate 등 인증 관련 함수")
    lines.append("   - update_role, change_role, delete_user 등 권한 관련 함수")
    lines.append("   - execute, query, run, system 등 데이터베이스/시스템 명령 함수")
    lines.append("   - get, post, request 등 HTTP 요청 처리 함수")
    lines.append("   - API_KEY, SECRET, PASSWORD 등 민감정보를 다루는 변수/함수")
    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")
                fn_name = fn.get("name", "")
                # 보안 취약점이 의심되는 함수명 강조
                security_keywords = ["auth", "login", "role", "delete", "update", "execute", "query", "system", "run", "secret", "key", "password", "token"]
                is_suspicious = any(keyword in fn_name.lower() for keyword in security_keywords)
                marker = " 🔒 [보안 검토 필수]" if is_suspicious else ""
                lines.append(f"  - 함수: {fn_name}({args_str}) -> {returns} (line {lineno}){marker}")
                if is_suspicious:
                    lines.append(f"    ⚠️ 이 함수는 보안 취약점이 있을 가능성이 높습니다. 반드시 `read_file`로 확인하세요.")
                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"
        "   - 위에 '🔒 [보안 검토 필수]'로 표시된 함수들을 우선적으로 확인하라.\n"
        "   - 공개 API/함수에서 보안 취약점 가능성 검토:\n"
        "     * 인증/인가 체크가 필요한데 없는 함수\n"
        "     * 입력 파라미터 검증이 부족한 함수\n"
        "     * 민감정보를 반환하거나 로깅하는 함수\n"
        "     * 외부 통신을 하는데 보안 체크가 없는 함수\n"
        "\n"
        "3단계: 실제 코드 확인 (필수 - 반드시 수행)\n"
        "   - 반드시 최소한 2-3개 이상의 API 엔드포인트 구현 파일에 대해 `read_file`을 호출해야 한다.\n"
        "   - 특히 '🔒 [보안 검토 필수]'로 표시된 함수가 있는 파일을 우선적으로 읽어라.\n"
        "   - 보안 취약점 패턴 확인:\n"
        "     * SQL 쿼리에서 f-string이나 문자열 포맷팅 사용\n"
        "     * subprocess, os.system, shell=True 사용\n"
        "     * 하드코딩된 비밀번호/API 키/시크릿\n"
        "     * requests.get(url, verify=False) 또는 http:// 사용\n"
        "     * jsonify, print, 로그에 민감정보 포함\n"
        "     * hashlib.md5, hashlib.sha1 등 약한 해시 사용\n"
        "     * 권한 체크 없이 사용자 데이터 접근\n"
        "\n"
        "4단계: 문제 보고 (필수)\n"
        "   - 문제를 발견하면 즉시 `report_finding` 도구를 호출하여 보고하라\n"
        "   - 발견된 취약점마다 적절한 카테고리(access, injection, sensitive, crypto, external 등)를 선택하라.\n"
        "   - 파싱 오류가 있는 파일은 반드시 'syntax_error' 카테고리로 보고하라\n"
        "   - **중요: 최소한 2-3개 파일의 실제 코드를 읽은 후에만 종료할 수 있다.**\n"
        "   - **중요: 하드코딩된 API_KEY, SECRET, PASSWORD 등이 보이면 반드시 'sensitive' 카테고리로 보고하라.**\n"
        "   - **중요: SQL 쿼리에 f-string이나 문자열 포맷팅이 보이면 반드시 'injection' 카테고리로 보고하라.**\n"
        "   - **중요: 권한 체크 없이 사용자 데이터를 수정/삭제하는 코드가 보이면 반드시 'access' 카테고리로 보고하라.**\n"
        "\n"
        "⚠️ 주의: tool 호출 없이 바로 종료하면 안 된다.\n"
        "   반드시 `read_file`을 최소 한 번은 호출해야 한다.\n"
        "   파싱 실패 파일이 있다면 반드시 해당 파일을 확인하고 보고해야 한다."
    )

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

