from pathlib import Path

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles

from app.config import security_config
from app.handlers.secure import handle_secure
from app.handlers.vulnerable import handle_vulnerable
from app.models.scenarios import load_attack_samples, resolve_attack_meta
from app.models.schemas import (
    AttackMeta,
    ChatRequest,
    ChatResult,
    CompareResponse,
    SecurityConfigUpdate,
)
from app.security.layer import security_layer

FRONTEND_DIR = Path(__file__).resolve().parent.parent / "frontend"

app = FastAPI(title="LLM 安全攻防演示平台", version="1.0.0")

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

if FRONTEND_DIR.exists():
    app.mount("/static", StaticFiles(directory=FRONTEND_DIR), name="static")


def _resolve_task(scenario_id: str, task: str | None) -> str:
    if task:
        return task
    scenario = load_attack_samples().get(scenario_id, {})
    return scenario.get("task", "faq")


@app.get("/")
async def index():
    index_file = FRONTEND_DIR / "index.html"
    if index_file.exists():
        return FileResponse(index_file)
    return {"message": "LLM Security Demo API", "docs": "/docs"}


@app.get("/api/scenarios")
async def get_scenarios():
    return load_attack_samples()


@app.get("/api/security/config")
async def get_security_config():
    return security_config.model_dump()


@app.put("/api/security/config")
async def update_security_config(body: SecurityConfigUpdate):
    data = body.model_dump(exclude_none=True)
    for key, value in data.items():
        setattr(security_config, key, value)
    return security_config.model_dump()


@app.get("/api/audit/logs")
async def get_audit_logs():
    return security_layer.audit_logs[-50:]


@app.post("/api/chat", response_model=ChatResult)
async def chat(req: ChatRequest):
    task = _resolve_task(req.scenario_id, req.task)
    if req.mode == "vulnerable":
        return await handle_vulnerable(req.message, scenario_id=req.scenario_id, task=task)
    return await handle_secure(req.message, scenario_id=req.scenario_id, task=task)


@app.post("/api/compare", response_model=CompareResponse)
async def compare(req: ChatRequest):
    task = _resolve_task(req.scenario_id, req.task)
    meta = resolve_attack_meta(req.scenario_id, req.sample_id)

    vulnerable = await handle_vulnerable(req.message, scenario_id=req.scenario_id, task=task)
    secure = await handle_secure(req.message, scenario_id=req.scenario_id, task=task)

    return CompareResponse(
        attack_meta=AttackMeta(**meta),
        vulnerable=vulnerable,
        secure=secure,
    )


@app.post("/api/redteam/run")
async def redteam_run():
    samples_data = load_attack_samples()
    report = []

    for scenario_id, scenario in samples_data.items():
        task = scenario.get("task", "faq")
        for sample in scenario.get("samples", []):
            result = await compare(
                ChatRequest(
                    message=sample["input"],
                    scenario_id=scenario_id,
                    sample_id=sample["id"],
                )
            )
            report.append(
                {
                    "sample_id": sample["id"],
                    "scenario": scenario_id,
                    "level": sample.get("level", "未知"),
                    "vulnerable_success": result.vulnerable.attack_success,
                    "secure_blocked": not result.secure.attack_success,
                    "blocked_by": result.secure.blocked_by,
                }
            )

    total = len(report)
    blocked = sum(1 for r in report if r["secure_blocked"])
    vuln_hit = sum(1 for r in report if r["vulnerable_success"])

    by_level: dict[str, dict] = {}
    for r in report:
        lv = r["level"]
        if lv not in by_level:
            by_level[lv] = {"total": 0, "blocked": 0}
        by_level[lv]["total"] += 1
        if r["secure_blocked"]:
            by_level[lv]["blocked"] += 1

    return {
        "summary": {
            "total": total,
            "secure_blocked": blocked,
            "vulnerable_hit": vuln_hit,
            "block_rate": f"{blocked / total * 100:.1f}%" if total else "0%",
            "by_level": {
                k: {
                    **v,
                    "block_rate": f"{v['blocked'] / v['total'] * 100:.0f}%",
                }
                for k, v in by_level.items()
            },
        },
        "results": report,
    }
