"""
Regression Test Route
Chạy bộ test cases qua bất kỳ chatbot URL nào, đánh giá bằng AI Judge và lưu kết quả.
"""

import logging
import json
from typing import Any

import httpx
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel

from common.llm_factory import create_llm
from config import DEFAULT_MODEL
from api.regression_test.regression_db import (
    create_suite, add_test_case, list_suites, get_suite, delete_suite,
    save_test_run, list_test_runs, get_test_run, detect_regressions
)

logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/regression-test", tags=["Regression Test"])


# ═══ MODELS ═══

class SuiteCreateRequest(BaseModel):
    name: str
    target_url: str
    description: str = ""

class TestCaseCreateRequest(BaseModel):
    question: str
    expected_keywords: str
    expected_behavior: str
    category: str = ""
    difficulty: str = ""

class RunSuiteRequest(BaseModel):
    suite_id: int
    timeout: int = 60


# ═══ AI JUDGE ═══

async def _judge_response(question: str, response: str, expected_keywords: str, expected_behavior: str) -> dict:
    llm = create_llm(DEFAULT_MODEL, json_mode=True)
    prompt = f"""
    You are an AI Judge evaluating a chatbot's response in a regression test.
    
    Question: {question}
    Expected Keywords: {expected_keywords}
    Expected Behavior: {expected_behavior}
    
    Chatbot Response: {response}
    
    Evaluate the response out of 10 based on factual accuracy, relevance, tone, and helpfulness.
    Output JSON strictly:
    {{
        "score": <0-10 int>,
        "reasoning": "<brief string explaining the score>"
    }}
    """
    try:
        resp = await llm.ainvoke([{"role": "system", "content": "You strictly output JSON."}, {"role": "user", "content": prompt}])
        data = json.loads(resp.content)
        return {"score": int(data.get("score", 0)), "reasoning": str(data.get("reasoning", ""))}
    except Exception as e:
        logger.error(f"AI Judge error: {e}")
        return {"score": 0, "reasoning": "AI Judge failed to evaluate."}


# ═══ ENDPOINTS ═══

@router.post("/suites")
async def api_create_suite(req: SuiteCreateRequest):
    suite_id = create_suite(req.name, req.target_url, req.description)
    return {"status": "success", "suite_id": suite_id}

@router.get("/suites")
async def api_list_suites():
    return {"status": "success", "suites": list_suites()}

@router.get("/suites/{suite_id}")
async def api_get_suite(suite_id: int):
    suite = get_suite(suite_id)
    if not suite:
        raise HTTPException(status_code=404, detail="Suite not found")
    return {"status": "success", "suite": suite}

@router.post("/suites/{suite_id}/cases")
async def api_add_case(suite_id: int, req: TestCaseCreateRequest):
    case_id = add_test_case(suite_id, req.question, req.expected_keywords, req.expected_behavior, req.category, req.difficulty)
    return {"status": "success", "case_id": case_id}

@router.delete("/suites/{suite_id}")
async def api_delete_suite(suite_id: int):
    delete_suite(suite_id)
    return {"status": "success"}

@router.post("/suites/{suite_id}/import")
async def api_import_cases(suite_id: int, req: list[TestCaseCreateRequest]):
    cases = []
    for c in req:
        case_id = add_test_case(suite_id, c.question, c.expected_keywords, c.expected_behavior, c.category, c.difficulty)
        cases.append(case_id)
    return {"status": "success", "imported": len(cases)}


@router.post("/run", summary="Run all test cases in a suite")
async def run_tests(req: RunSuiteRequest):
    suite = get_suite(req.suite_id)
    if not suite:
        raise HTTPException(status_code=404, detail="Suite not found")
        
    target_url = suite["target_url"]
    test_cases = suite["test_cases"]
    results = []
    total_score = 0
    passed = 0

    async with httpx.AsyncClient(timeout=req.timeout) as client:
        for tc in test_cases:
            tc_id = tc["id"]
            question = tc["question"]

            try:
                resp = await client.post(
                    target_url,
                    json={"user_query": question},
                    headers={"Content-Type": "application/json"},
                )
                resp.raise_for_status()
                data = resp.json()
                ai_resp = data.get("ai_response", "")

                judge = await _judge_response(question, ai_resp, tc["expected_keywords"], tc["expected_behavior"])
                score = judge["score"]
                status = "success" if score >= 7 else "failed"
                if status == "success":
                    passed += 1
                total_score += score

                results.append({
                    "case_id": tc_id,
                    "question": question,
                    "status": status,
                    "response": ai_resp,
                    "score": score,
                    "judge_reasoning": judge["reasoning"],
                    "latency_ms": resp.elapsed.total_seconds() * 1000 if hasattr(resp, 'elapsed') else None,
                })
            except Exception as e:
                results.append({
                    "case_id": tc_id, 
                    "question": question,
                    "status": "error",
                    "response": str(e),
                    "score": 0,
                    "judge_reasoning": "Exception during request",
                    "latency_ms": None,
                })

    total = len(test_cases)
    avg_score = round(total_score / total, 2) if total > 0 else 0
    failed = total - passed

    run_data = {
        "suite_id": req.suite_id,
        "target_url": target_url,
        "total": total,
        "passed": passed,
        "failed": failed,
        "avg_score": avg_score,
        "model_name": DEFAULT_MODEL,
        "prompt_version": "v-latest", # Will be updated with actual if integrated
    }
    run_id = save_test_run(run_data, results)

    return {
        "status": "success",
        "run_id": run_id,
        "total": total,
        "passed": passed,
        "failed": failed,
        "avg_score": avg_score,
        "results": results,
    }


@router.get("/runs")
async def api_list_runs():
    return {"status": "success", "runs": list_test_runs()}

@router.get("/runs/{run_id}")
async def api_get_run(run_id: str):
    run = get_test_run(run_id)
    if not run:
        raise HTTPException(status_code=404, detail="Run not found")
    return {"status": "success", "run": run}

@router.get("/runs/{run_id}/regressions")
async def api_get_regressions(run_id: str):
    regressions = detect_regressions(run_id)
    return {"status": "success", "regressions": regressions}
