"""B-3 코드 리뷰 에이전트 테스트"""
import sys, ast, os, asyncio, json
from pathlib import Path

os.environ.setdefault("GUARDIA_SECRET_KEY", "test-b3-secret-key-32bytes-padded!")
os.environ.setdefault("DATABASE_URL", "sqlite+aiosqlite:///./test_b3.db")
os.environ.setdefault("GUARDIA_PROJECTS_ROOT", r"C:\GUARDiA\projects")

print("=== 1. 구문 검사 ===")
files = ["core/code_review.py", "routers/code_review.py", "main.py"]
ok = True
for f in files:
    try:
        with open(f, encoding="utf-8") as fh:
            src = fh.read()
        ast.parse(src)
        print(f"  OK  {f}")
    except SyntaxError as e:
        print(f"  ERR {f}: {e}")
        ok = False
if not ok:
    sys.exit(1)

print("\n=== 2. models.py CodeReview 모델 확인 ===")
with open("models.py", encoding="utf-8") as f:
    models_src = f.read()

checks = [
    ("class CodeReview(Base):", "CodeReview DB 모델"),
    ("class CodeReviewOut(BaseModel):", "CodeReviewOut Pydantic"),
    ("class CodeReviewRequest(BaseModel):", "CodeReviewRequest"),
    ("class ReviewSeverity(str, Enum):", "ReviewSeverity Enum"),
    ("class ReviewCategory(str, Enum):", "ReviewCategory Enum"),
    ("findings_json", "findings_json 컬럼"),
    ("project_dir", "project_dir 컬럼 (Project 모델)"),
    ("tech_stack", "tech_stack 컬럼"),
    ("last_review_score", "last_review_score 컬럼"),
]
for sym, desc in checks:
    status = "OK" if sym in models_src else "ERR"
    if status == "ERR":
        ok = False
    print(f"  {status}  {desc}")

print("\n=== 3. core/code_review.py 함수 확인 ===")
with open("core/code_review.py", encoding="utf-8") as f:
    cr_src = f.read()

fn_checks = [
    ("def scan_source_files(", "파일 스캔 함수"),
    ("def detect_tech_stack(", "기술 스택 감지"),
    ("async def _call_ollama(", "Ollama API 호출"),
    ("def _build_review_prompt(", "프롬프트 생성"),
    ("def _parse_findings(", "findings 파싱"),
    ("def _calculate_score(", "점수 산출"),
    ("async def run_code_review(", "메인 리뷰 실행"),
    ("def quick_security_scan(", "빠른 보안 스캔"),
    ("SECURITY_PATTERNS", "보안 패턴 목록"),
    ("SKIP_DIRS", "제외 디렉토리 목록"),
]
for sym, desc in fn_checks:
    status = "OK" if sym in cr_src else "ERR"
    if status == "ERR":
        ok = False
    print(f"  {status}  {desc}")

print("\n=== 4. routers/code_review.py 엔드포인트 확인 ===")
with open("routers/code_review.py", encoding="utf-8") as f:
    router_src = f.read()

endpoint_checks = [
    ('@router.post("", ', "POST /api/code-review (리뷰 요청)"),
    ('@router.get("/projects/list")', "GET /api/code-review/projects/list"),
    ('@router.get("/{review_id}", ', "GET /api/code-review/{id}"),
    ('@router.post("/quick-scan")', "POST /api/code-review/quick-scan"),
    ('@router.get("/{review_id}/findings")', "GET /api/code-review/{id}/findings"),
    ("BackgroundTasks", "비동기 백그라운드 실행"),
    ("_run_review_background", "백그라운드 실행 함수"),
]
for sym, desc in endpoint_checks:
    status = "OK" if sym in router_src else "ERR"
    if status == "ERR":
        ok = False
    print(f"  {status}  {desc}")

print("\n=== 5. projects/ 디렉토리 구조 확인 ===")
projects_root = Path(os.environ["GUARDIA_PROJECTS_ROOT"])
expected_projects = [
    "testcase-java-api",
    "testcase-py-api",
    "testcase-js-frontend",
    "testcase-php-legacy",
]
for proj in expected_projects:
    status = "OK" if (projects_root / proj).exists() else "ERR"
    if status == "ERR":
        ok = False
    print(f"  {status}  {proj}")

print("\n=== 6. scan_source_files 단위 테스트 ===")
try:
    import importlib.util
    spec = importlib.util.spec_from_file_location("cr_mod", "core/code_review.py")
    cr_mod = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(cr_mod)

    for proj in expected_projects:
        proj_path = projects_root / proj
        if proj_path.exists():
            files = cr_mod.scan_source_files(proj_path)
            stack = cr_mod.detect_tech_stack(files)
            print(f"  OK  {proj}: {len(files)}개 파일, 스택={stack}")
        else:
            print(f"  SKIP {proj}: 경로 없음")

except Exception as e:
    print(f"  INFO  임포트 오류 (정상): {type(e).__name__}: {str(e)[:80]}")

print("\n=== 7. quick_security_scan 단위 테스트 ===")
async def test_quick_scan():
    try:
        from core.code_review import quick_security_scan, PROJECTS_ROOT

        for proj in expected_projects:
            proj_path = PROJECTS_ROOT / proj
            if not proj_path.exists():
                continue
            findings = quick_security_scan(proj_path)
            crit = sum(1 for f in findings if f["severity"] == "CRITICAL")
            high = sum(1 for f in findings if f["severity"] == "HIGH")
            print(f"  OK  {proj}: {len(findings)}건 발견 (CRITICAL={crit}, HIGH={high})")

    except Exception as e:
        print(f"  INFO  스캔 오류: {type(e).__name__}: {str(e)[:80]}")

asyncio.run(test_quick_scan())

print("\n=== 8. 점수 산출 로직 테스트 ===")
try:
    from core.code_review import _calculate_score

    cases = [
        ([], 95, "빈 findings"),
        ([{"severity": "INFO"}] * 5, 95, "INFO만 5건"),
        ([{"severity": "LOW"}] * 3, 94, "LOW 3건 (6점 감점)"),
        ([{"severity": "MEDIUM"}] * 4, 80, "MEDIUM 4건 (20점 감점)"),
        ([{"severity": "HIGH"}] * 3, 70, "HIGH 3건 (30점 감점)"),
        ([{"severity": "CRITICAL"}] * 2 + [{"severity": "HIGH"}] * 3, 30, "CRITICAL 2건 + HIGH 3건"),
    ]
    for findings, expected, label in cases:
        score = _calculate_score(findings)
        status = "OK" if score == expected else f"WARN(got {score}, expected {expected})"
        print(f"  {status}  {label}: score={score}")

except Exception as e:
    print(f"  INFO  점수 계산 오류: {type(e).__name__}: {str(e)[:80]}")

print("\n=== 9. findings 파싱 테스트 ===")
try:
    from core.code_review import _parse_findings

    valid_json = '''[
        {"severity": "CRITICAL", "category": "SECURITY", "line": 42,
         "message": "SQL 인젝션 취약점", "suggestion": "PreparedStatement 사용"},
        {"severity": "HIGH", "category": "CODE_QUALITY", "line": null,
         "message": "null 반환", "suggestion": "Optional 사용"}
    ]'''
    result = _parse_findings(valid_json, "test/File.java")
    assert len(result) == 2
    assert result[0]["severity"] == "CRITICAL"
    assert result[0]["file"] == "test/File.java"
    print("  OK  유효한 JSON 파싱")

    result2 = _parse_findings("LLM이 설명을 길게 써서... []", "test/File.java")
    assert result2 == []
    print("  OK  빈 배열 파싱")

    result3 = _parse_findings("완전 잘못된 응답", "test/File.java")
    assert result3 == []
    print("  OK  잘못된 응답 파싱 (빈 배열 반환)")

except Exception as e:
    print(f"  ERR  findings 파싱 오류: {type(e).__name__}: {e}")
    ok = False

print("\n=== 10. 하네스 구조 확인 ===")
harness_checks = [
    (r"C:\GUARDiA\itsm\.claude\agents\sr-manager.md", "SR 매니저 에이전트"),
    (r"C:\GUARDiA\itsm\.claude\agents\code-reviewer.md", "코드 리뷰 에이전트"),
    (r"C:\GUARDiA\itsm\.claude\agents\deploy-engineer.md", "배포 엔지니어 에이전트"),
    (r"C:\GUARDiA\itsm\.claude\agents\sla-guardian.md", "SLA 가디언 에이전트"),
    (r"C:\GUARDiA\itsm\.claude\agents\incident-responder.md", "인시던트 대응 에이전트"),
    (r"C:\GUARDiA\itsm\.claude\skills\guardia-orchestrator\SKILL.md", "오케스트레이터 스킬"),
    (r"C:\GUARDiA\itsm\.claude\skills\code-review\SKILL.md", "코드 리뷰 스킬"),
    (r"C:\GUARDiA\itsm\.claude\skills\sr-lifecycle\SKILL.md", "SR 생명주기 스킬"),
    (r"C:\GUARDiA\itsm\.claude\skills\deploy-pipeline\SKILL.md", "배포 파이프라인 스킬"),
]
for path, desc in harness_checks:
    status = "OK" if Path(path).exists() else "ERR"
    if status == "ERR":
        ok = False
    print(f"  {status}  {desc}")

print("\n=== 11. main.py 등록 확인 ===")
with open("main.py", encoding="utf-8") as f:
    main_src = f.read()

main_checks = [
    ("code_review", "code_review 라우터 임포트"),
    ("code_review.router", "code_review 라우터 등록"),
]
for sym, desc in main_checks:
    status = "OK" if sym in main_src else "ERR"
    if status == "ERR":
        ok = False
    print(f"  {status}  {desc}")

print("\n=== B-3 코드 리뷰 에이전트 테스트 완료 ===")
if ok:
    print("모든 검사 통과")
else:
    sys.exit(1)
