"""
GUARDiA GS인증 (Good Software 인증) 요건 자동 점검·보고
GS 1등급/2등급 인증을 위한 요건 체크리스트 자동 점검 및 보고서 생성
TTA(한국정보통신기술협회) 기준 준수
"""
import json
from datetime import datetime
from typing import Any, Dict, List, Optional
from fastapi import APIRouter, HTTPException, Query
from pydantic import BaseModel

router = APIRouter(prefix="/api/gs-cert", tags=["GS Certification"])


# ── GS인증 요건 체크리스트 ───────────────────────────────────────────────────
# TTA GS 인증 기준 (SW 시험 기준 V4.0)

GS_CHECKLIST = {
    "기능성": {
        "weight": 25,
        "items": [
            {"id": "F-01", "name": "기능 완전성",        "desc": "명세된 모든 기능이 구현됨",                          "required": True},
            {"id": "F-02", "name": "기능 정확성",        "desc": "올바른 결과와 필요한 정밀도 달성",                   "required": True},
            {"id": "F-03", "name": "기능 적절성",        "desc": "특정 사용자 목표 달성에 적절한 기능 제공",           "required": True},
            {"id": "F-04", "name": "기능 준수성",        "desc": "관련 표준/규약/규정 준수",                           "required": False},
            {"id": "F-05", "name": "상호운용성",         "desc": "다른 시스템과의 상호작용 가능",                      "required": False},
        ]
    },
    "신뢰성": {
        "weight": 20,
        "items": [
            {"id": "R-01", "name": "성숙성",             "desc": "소프트웨어 결함에 의한 고장 회피",                   "required": True},
            {"id": "R-02", "name": "결함 허용성",        "desc": "결함 발생 시에도 일정 성능 수준 유지",               "required": True},
            {"id": "R-03", "name": "회복성",             "desc": "고장 후 데이터 복구 및 성능 재확립 능력",            "required": True},
            {"id": "R-04", "name": "가용성",             "desc": "요구된 기간 동안 운영·접근 가능 상태 유지",          "required": False},
        ]
    },
    "사용성": {
        "weight": 15,
        "items": [
            {"id": "U-01", "name": "이해용이성",         "desc": "특정 작업에 적합한지 쉽게 이해 가능",                "required": True},
            {"id": "U-02", "name": "학습용이성",         "desc": "기능 학습이 용이",                                   "required": True},
            {"id": "U-03", "name": "운영용이성",         "desc": "사용자 제어 및 운영이 용이",                         "required": True},
            {"id": "U-04", "name": "접근성",             "desc": "장애인 등 다양한 사용자가 접근 가능 (WCAG 2.1 AA)", "required": True},
            {"id": "U-05", "name": "UI 심미성",          "desc": "사용자에게 즐겁고 만족스러운 상호작용 제공",         "required": False},
        ]
    },
    "효율성": {
        "weight": 15,
        "items": [
            {"id": "E-01", "name": "시간 효율성",        "desc": "적절한 응답·처리 속도 (95% 응답 < 3초)",            "required": True},
            {"id": "E-02", "name": "자원 효율성",        "desc": "CPU/메모리/디스크 자원 적절 사용",                   "required": True},
            {"id": "E-03", "name": "용량 만족성",        "desc": "최대 한계 처리 능력이 요건 충족",                    "required": False},
        ]
    },
    "유지보수성": {
        "weight": 10,
        "items": [
            {"id": "M-01", "name": "분석성",             "desc": "결함 진단·수정 위치 식별 용이",                      "required": True},
            {"id": "M-02", "name": "변경성",             "desc": "명세된 변경이 용이하게 이뤄짐",                      "required": True},
            {"id": "M-03", "name": "안정성",             "desc": "변경에 의한 예상치 못한 영향 최소화",                "required": True},
            {"id": "M-04", "name": "시험성",             "desc": "변경된 소프트웨어 검증 용이",                        "required": True},
            {"id": "M-05", "name": "모듈성",             "desc": "한 컴포넌트 변경이 다른 컴포넌트에 영향 최소",      "required": False},
        ]
    },
    "이식성": {
        "weight": 10,
        "items": [
            {"id": "P-01", "name": "적응성",             "desc": "다른 환경(OS/HW)에 적응 가능",                      "required": False},
            {"id": "P-02", "name": "설치성",             "desc": "지정 환경에 성공적으로 설치 가능",                   "required": True},
            {"id": "P-03", "name": "공존성",             "desc": "동일 환경 다른 소프트웨어와 공존 가능",              "required": False},
        ]
    },
    "보안성": {
        "weight": 5,
        "items": [
            {"id": "S-01", "name": "기밀성",             "desc": "인가된 사용자만 접근 (JWT/RBAC)",                   "required": True},
            {"id": "S-02", "name": "무결성",             "desc": "데이터 불법 접근 및 변경 방지",                      "required": True},
            {"id": "S-03", "name": "부인방지성",         "desc": "행위 발생 사실 부인 불가 (감사로그)",                "required": True},
            {"id": "S-04", "name": "책임추적성",         "desc": "사용자 행위 추적 가능",                              "required": True},
            {"id": "S-05", "name": "인증성",             "desc": "사용자/시스템 신원 확인 가능",                       "required": True},
            {"id": "S-06", "name": "취약점 제거",        "desc": "알려진 보안 취약점 (OWASP Top 10) 제거",            "required": True},
        ]
    },
}

# ITSM 현재 구현 상태 (자동 점검 기준)
ITSM_IMPLEMENTATION = {
    "F-01": True,   "F-02": True,   "F-03": True,   "F-04": True,   "F-05": True,
    "R-01": True,   "R-02": True,   "R-03": True,   "R-04": True,
    "U-01": True,   "U-02": True,   "U-03": True,   "U-04": False,  "U-05": True,
    "E-01": True,   "E-02": True,   "E-03": False,
    "M-01": True,   "M-02": True,   "M-03": True,   "M-04": True,   "M-05": True,
    "P-01": True,   "P-02": True,   "P-03": True,
    "S-01": True,   "S-02": True,   "S-03": True,   "S-04": True,   "S-05": True,  "S-06": True,
}

# GS인증 추가 필수 서류/산출물
REQUIRED_DOCUMENTS = [
    {"id": "DOC-01", "name": "소프트웨어 요구사항 명세서(SRS)",  "status": "완료", "path": "docs/srs.md"},
    {"id": "DOC-02", "name": "소프트웨어 설계 명세서",            "status": "완료", "path": "docs/design.md"},
    {"id": "DOC-03", "name": "테스트 케이스 명세서",              "status": "완료", "path": "docs/test_cases.md"},
    {"id": "DOC-04", "name": "사용자 매뉴얼",                     "status": "완료", "path": "workspace/guardia-docs/"},
    {"id": "DOC-05", "name": "설치 가이드",                       "status": "완료", "path": "docs/install.md"},
    {"id": "DOC-06", "name": "운영자 매뉴얼",                     "status": "완료", "path": "workspace/guardia-docs/"},
    {"id": "DOC-07", "name": "접근성 준수 확인서",                "status": "미완료","path": ""},
    {"id": "DOC-08", "name": "보안 취약점 점검 결과서",           "status": "완료", "path": "docs/security_audit.md"},
    {"id": "DOC-09", "name": "성능 시험 결과서",                  "status": "미완료","path": ""},
    {"id": "DOC-10", "name": "오픈소스 사용 신고서",              "status": "완료", "path": "docs/opensource.md"},
]

_overrides: Dict[str, bool] = {}   # 수동 업데이트


# ── Pydantic 모델 ──────────────────────────────────────────────────────────

class ItemUpdate(BaseModel):
    item_id: str
    status: bool
    note: Optional[str] = None

class AuditReport(BaseModel):
    grade: str       # "1등급" | "2등급" | "미달"
    score: float
    passed: int
    failed: int
    required_failed: List[str]
    by_category: Dict[str, Any]
    documents: List[Dict]
    recommendations: List[str]
    generated_at: str


# ── 점검 로직 ─────────────────────────────────────────────────────────────

def _run_audit() -> AuditReport:
    impl = {**ITSM_IMPLEMENTATION, **_overrides}

    total_score = 0.0
    passed = 0
    failed = 0
    required_failed: List[str] = []
    by_category: Dict[str, Any] = {}
    recommendations: List[str] = []

    for cat_name, cat_data in GS_CHECKLIST.items():
        weight = cat_data["weight"]
        items = cat_data["items"]
        cat_passed = 0
        cat_failed_items = []

        for item in items:
            iid = item["id"]
            ok = impl.get(iid, False)
            if ok:
                cat_passed += 1
                passed += 1
            else:
                failed += 1
                cat_failed_items.append(iid)
                if item["required"]:
                    required_failed.append(f"{iid}: {item['name']}")
                    recommendations.append(f"[{iid}] {item['desc']} — 즉시 구현 필요")
                else:
                    recommendations.append(f"[{iid}] {item['desc']} — 권고 사항")

        cat_score = (cat_passed / len(items)) * weight
        total_score += cat_score
        by_category[cat_name] = {
            "score":  round(cat_score, 2),
            "weight": weight,
            "passed": cat_passed,
            "total":  len(items),
            "failed": cat_failed_items,
        }

    # 등급 판정 (TTA 기준: 필수 항목 전체 통과 + 총점 80+ = 1등급, 70+ = 2등급)
    if not required_failed and total_score >= 80:
        grade = "GS 1등급"
    elif len(required_failed) <= 2 and total_score >= 70:
        grade = "GS 2등급"
    else:
        grade = "미달 (재심사 필요)"

    return AuditReport(
        grade=grade,
        score=round(total_score, 2),
        passed=passed,
        failed=failed,
        required_failed=required_failed,
        by_category=by_category,
        documents=REQUIRED_DOCUMENTS,
        recommendations=recommendations[:20],
        generated_at=datetime.utcnow().isoformat(),
    )


# ── API 엔드포인트 ─────────────────────────────────────────────────────────

@router.get("/checklist")
async def get_checklist():
    """GS인증 체크리스트 전체 조회."""
    impl = {**ITSM_IMPLEMENTATION, **_overrides}
    result = {}
    for cat, data in GS_CHECKLIST.items():
        result[cat] = {
            "weight": data["weight"],
            "items": [
                {**item, "passed": impl.get(item["id"], False)}
                for item in data["items"]
            ]
        }
    return {"checklist": result, "categories": list(GS_CHECKLIST.keys())}


@router.get("/audit")
async def run_audit():
    """GS인증 자동 점검 실행 — 등급 판정."""
    return _run_audit().model_dump()


@router.get("/audit/summary")
async def audit_summary():
    """점검 결과 요약 (경량)."""
    report = _run_audit()
    return {
        "grade":          report.grade,
        "score":          report.score,
        "passed":         report.passed,
        "failed":         report.failed,
        "required_failed": len(report.required_failed),
        "generated_at":  report.generated_at,
    }


@router.patch("/checklist/item")
async def update_item(req: ItemUpdate):
    """체크리스트 항목 수동 업데이트."""
    _overrides[req.item_id] = req.status
    return {
        "updated": True,
        "item_id": req.item_id,
        "status":  req.status,
        "note":    req.note,
    }


@router.get("/documents")
async def get_documents():
    """GS인증 필수 산출물 목록."""
    completed = sum(1 for d in REQUIRED_DOCUMENTS if d["status"] == "완료")
    return {
        "documents":    REQUIRED_DOCUMENTS,
        "total":        len(REQUIRED_DOCUMENTS),
        "completed":    completed,
        "missing":      len(REQUIRED_DOCUMENTS) - completed,
    }


@router.get("/report/json")
async def export_report_json():
    """GS인증 점검 보고서 JSON 내보내기."""
    report = _run_audit()
    return {
        "report_type": "GS_CERTIFICATION_AUDIT",
        "system":      "GUARDiA ITSM v2.1.0",
        "standard":    "TTA GS 인증 기준 SW 시험 V4.0",
        "result":      report.model_dump(),
    }


@router.get("/report/markdown")
async def export_report_markdown():
    """GS인증 점검 보고서 Markdown 내보내기."""
    report = _run_audit()
    lines = [
        "# GUARDiA ITSM GS인증 점검 보고서",
        f"생성일시: {report.generated_at}",
        f"판정 등급: **{report.grade}**",
        f"총점: {report.score}/100",
        f"통과: {report.passed}개 / 실패: {report.failed}개",
        "",
        "## 카테고리별 결과",
        "| 카테고리 | 가중치 | 통과 | 총수 | 점수 |",
        "|---------|--------|------|------|------|",
    ]
    for cat, data in report.by_category.items():
        lines.append(f"| {cat} | {data['weight']}% | {data['passed']} | {data['total']} | {data['score']} |")

    if report.required_failed:
        lines += ["", "## 필수 미통과 항목", ""]
        for item in report.required_failed:
            lines.append(f"- {item}")

    if report.recommendations:
        lines += ["", "## 개선 권고사항", ""]
        for rec in report.recommendations[:10]:
            lines.append(f"- {rec}")

    lines += ["", "## 필수 산출물", "| ID | 문서명 | 상태 |", "|-----|--------|------|"]
    for doc in report.documents:
        lines.append(f"| {doc['id']} | {doc['name']} | {doc['status']} |")

    return {"markdown": "\n".join(lines)}


@router.get("/requirements")
async def list_requirements():
    """GS인증 추가 요건 (공공기관 납품 기준)."""
    return {
        "requirements": [
            {"category": "법적 요건",   "items": [
                "저작권 등록 또는 소프트웨어 사업자 신고",
                "오픈소스 라이선스 적합성 검토",
                "개인정보보호법 준수 (개인정보 처리 시)",
            ]},
            {"category": "TTA 시험",    "items": [
                "TTA 공인 시험기관 기능 시험",
                "성능 시험 (부하, 스트레스)",
                "보안 취약점 시험 (OWASP Top 10)",
                "접근성 시험 (KWCAG 2.1)",
            ]},
            {"category": "공공기관 특화", "items": [
                "행정정보시스템 연동 가이드 준수",
                "GS 인증서 취득 후 3년 유효",
                "나라장터 등록 가능 (GS 1·2등급)",
                "공공기관 정보화사업 입찰 자격",
            ]},
        ]
    }


@router.get("/score/breakdown")
async def score_breakdown():
    """카테고리별 점수 분해 — 개선 우선순위 확인."""
    report = _run_audit()
    breakdowns = []
    for cat, data in report.by_category.items():
        max_possible = data["weight"]
        current      = data["score"]
        gap          = round(max_possible - current, 2)
        breakdowns.append({
            "category": cat,
            "current":  current,
            "maximum":  max_possible,
            "gap":      gap,
            "priority": "높음" if gap > 5 else ("중간" if gap > 2 else "낮음"),
        })
    breakdowns.sort(key=lambda x: x["gap"], reverse=True)
    return {
        "total_score":    report.score,
        "grade":          report.grade,
        "breakdown":      breakdowns,
        "quick_wins":     [b for b in breakdowns if b["gap"] > 0 and b["priority"] != "낮음"],
    }
