from __future__ import annotations

from datetime import datetime
from enum import Enum
from typing import Any

from pydantic import BaseModel, Field


class Verdict(str, Enum):
    VULNERABLE = "vulnerable"
    RESILIENT = "resilient"
    INCONCLUSIVE = "inconclusive"
    ERROR = "error"


class AttackPayload(BaseModel):
    id: str
    content: str
    attack_name: str
    category: str
    turn: int = 0
    metadata: dict[str, Any] = Field(default_factory=dict)


class TargetResponse(BaseModel):
    content: str
    raw: dict[str, Any] = Field(default_factory=dict)
    status_code: int = 200
    latency_ms: float = 0.0
    thread_id: str | None = None
    timestamp: datetime = Field(default_factory=datetime.utcnow)
    metadata: dict[str, Any] = Field(default_factory=dict)


class EvalResult(BaseModel):
    verdict: Verdict
    confidence: float = Field(ge=0.0, le=1.0, default=1.0)
    reasoning: str = ""
    evaluator_name: str = ""
    payload_id: str = ""
    payload_content: str = ""
    response_content: str = ""
    response_latency_ms: float = 0.0


class AttackConfig(BaseModel):
    name: str
    params: dict[str, Any] = Field(default_factory=dict)
    custom_payloads: list[str] | None = None
    steps: list[str] | None = None
    max_payloads: int | None = None


class EvalConfig(BaseModel):
    type: str
    params: dict[str, Any] = Field(default_factory=dict)


class BuffConfig(BaseModel):
    name: str
    params: dict[str, Any] = Field(default_factory=dict)


class TargetConfig(BaseModel):
    type: str = "http"
    url: str = ""
    method: str = "POST"
    headers: dict[str, str] = Field(default_factory=dict)
    body_template: str | None = None
    response_path: str | None = None
    preset: str | None = None
    timeout: float = 30.0


class TestCaseConfig(BaseModel):
    name: str
    description: str = ""
    attacks: list[AttackConfig] = Field(default_factory=list)
    evaluators: list[EvalConfig] | None = None
    buffs: list[BuffConfig] = Field(default_factory=list)
    multi_turn: bool = False
    max_turns: int = 5
    concurrency: int = Field(default=1, ge=1)
    tags: list[str] = Field(default_factory=list)


class TestSuiteConfig(BaseModel):
    name: str
    description: str = ""
    target: TargetConfig
    llm_model: str = "gpt-4o-mini"
    api_key: str | None = None
    concurrency: int = Field(default=1, ge=1)
    loggers: list[str] = Field(default_factory=lambda: ["console"])
    defaults: dict[str, Any] = Field(default_factory=dict)
    tests: list[TestCaseConfig] = Field(default_factory=list)
    tests_dir: str | None = None


class TestCaseResult(BaseModel):
    name: str
    attack_names: list[str] = Field(default_factory=list)
    total_payloads: int = 0
    vulnerable_count: int = 0
    resilient_count: int = 0
    inconclusive_count: int = 0
    error_count: int = 0
    eval_results: list[EvalResult] = Field(default_factory=list)
    duration_ms: float = 0.0


class TokenUsage(BaseModel):
    prompt_tokens: int = 0
    completion_tokens: int = 0
    total_tokens: int = 0


class TestSuiteResult(BaseModel):
    suite_name: str
    started_at: datetime = Field(default_factory=datetime.utcnow)
    completed_at: datetime | None = None
    case_results: list[TestCaseResult] = Field(default_factory=list)
    total_payloads: int = 0
    total_vulnerable: int = 0
    total_resilient: int = 0
    total_inconclusive: int = 0
    total_errors: int = 0
    token_usage: TokenUsage = Field(default_factory=TokenUsage)
