from __future__ import annotations

from datetime import datetime
from uuid import UUID

from pydantic import BaseModel, ConfigDict, Field


# ── Formula Config ───────────────────────────────────────────────


class FormulaConfigCreate(BaseModel):
    """Payload for creating a WoT threshold formula configuration."""

    name: str = Field(..., min_length=1, max_length=128)
    description: str | None = None

    # WoT threshold params
    duration_days: int = Field(default=30, ge=1, description="Duration of the vote in days")
    majority_pct: int = Field(default=50, ge=1, le=100, description="Majority percentage required")
    base_exponent: float = Field(default=0.1, ge=0.0, le=1.0, description="Base exponent B in the formula")
    gradient_exponent: float = Field(default=0.2, ge=0.0, le=2.0, description="Gradient exponent G in the formula")
    constant_base: float = Field(default=0.0, ge=0.0, le=1.0, description="Constant base C in the formula")

    # Smith criterion
    smith_exponent: float | None = Field(default=None, ge=0.0, le=1.0, description="Smith criterion exponent S")

    # TechComm criterion
    techcomm_exponent: float | None = Field(default=None, ge=0.0, le=1.0, description="TechComm criterion exponent T")

    # Nuanced vote
    nuanced_min_participants: int | None = Field(default=None, ge=0, description="Minimum participants for nuanced vote")
    nuanced_threshold_pct: int | None = Field(default=None, ge=0, le=100, description="Threshold percentage for nuanced vote")


class FormulaConfigUpdate(BaseModel):
    """Partial update payload for a formula configuration (all fields optional)."""

    name: str | None = Field(default=None, min_length=1, max_length=128)
    description: str | None = None

    duration_days: int | None = Field(default=None, ge=1)
    majority_pct: int | None = Field(default=None, ge=1, le=100)
    base_exponent: float | None = Field(default=None, ge=0.0, le=1.0)
    gradient_exponent: float | None = Field(default=None, ge=0.0, le=2.0)
    constant_base: float | None = Field(default=None, ge=0.0, le=1.0)

    smith_exponent: float | None = Field(default=None, ge=0.0, le=1.0)
    techcomm_exponent: float | None = Field(default=None, ge=0.0, le=1.0)

    nuanced_min_participants: int | None = Field(default=None, ge=0)
    nuanced_threshold_pct: int | None = Field(default=None, ge=0, le=100)


class FormulaConfigOut(BaseModel):
    """Full formula configuration representation."""

    model_config = ConfigDict(from_attributes=True)

    id: UUID
    name: str
    description: str | None = None
    duration_days: int
    majority_pct: int
    base_exponent: float
    gradient_exponent: float
    constant_base: float
    smith_exponent: float | None = None
    techcomm_exponent: float | None = None
    nuanced_min_participants: int | None = None
    nuanced_threshold_pct: int | None = None
    created_at: datetime


# ── Voting Protocol ──────────────────────────────────────────────


class VotingProtocolCreate(BaseModel):
    """Payload for creating a voting protocol."""

    name: str = Field(..., min_length=1, max_length=128)
    description: str | None = None
    vote_type: str = Field(..., max_length=32, description="binary, nuanced")
    formula_config_id: UUID = Field(..., description="Reference to the formula configuration")
    mode_params: str | None = Field(default=None, max_length=64, description='e.g. "D30M50B.1G.2T.1"')
    is_meta_governed: bool = Field(default=False, description="Whether this protocol is itself governed by meta-vote")


class VotingProtocolUpdate(BaseModel):
    """Partial update payload for a voting protocol (meta-governance)."""

    name: str | None = Field(default=None, min_length=1, max_length=128)
    description: str | None = None
    vote_type: str | None = Field(default=None, max_length=32)
    mode_params: str | None = Field(default=None, max_length=64)
    is_meta_governed: bool | None = None


class VotingProtocolOut(BaseModel):
    """Full voting protocol representation including formula config."""

    model_config = ConfigDict(from_attributes=True)

    id: UUID
    name: str
    description: str | None = None
    vote_type: str
    formula_config_id: UUID
    mode_params: str | None = None
    is_meta_governed: bool
    created_at: datetime
    formula_config: FormulaConfigOut


# ── Formula Simulation ───────────────────────────────────────────


class FormulaSimulationRequest(BaseModel):
    """Request payload for simulating a WoT threshold formula computation."""

    wot_size: int = Field(..., ge=1, description="Size of the WoT (eligible voter corpus)")
    total_votes: int = Field(..., ge=0, description="Number of votes cast (for + against)")
    majority_pct: int = Field(default=50, ge=1, le=100, description="Majority percentage M")
    base_exponent: float = Field(default=0.1, ge=0.0, le=1.0, description="Base exponent B")
    gradient_exponent: float = Field(default=0.2, ge=0.0, le=2.0, description="Gradient exponent G")
    constant_base: float = Field(default=0.0, ge=0.0, le=1.0, description="Constant base C")
    smith_wot_size: int | None = Field(default=None, ge=1, description="Smith sub-WoT size")
    smith_exponent: float | None = Field(default=None, ge=0.0, le=1.0, description="Smith exponent S")
    techcomm_size: int | None = Field(default=None, ge=1, description="TechComm size")
    techcomm_exponent: float | None = Field(default=None, ge=0.0, le=1.0, description="TechComm exponent T")


class FormulaSimulationResult(BaseModel):
    """Result of a formula simulation."""

    wot_threshold: int
    smith_threshold: int | None = None
    techcomm_threshold: int | None = None
    participation_rate: float
    required_ratio: float
    inertia_factor: float
