from pydantic import BaseModel, EmailStr, Field
from typing import Optional
from datetime import datetime


class ContactRequest(BaseModel):
    name: str
    email: EmailStr
    company: Optional[str] = None
    message: str
    website: Optional[str] = ""  # honeypot: si viene relleno, es un bot
    turnstile_token: str = ""


class TokenRequest(BaseModel):
    api_key: str


class TokenResponse(BaseModel):
    access_token: str
    token_type: str = "bearer"
    expires_in: int = 900
    client_id: str


class ConvertOptions(BaseModel):
    include_metadata: bool = False
    validate_output: bool = True


class ConvertRequest(BaseModel):
    message: str
    format: str = "MT940"
    options: ConvertOptions = ConvertOptions()


class PlaygroundConvertRequest(BaseModel):
    message: str
    format: str = "MT940"
    turnstile_token: str = ""


class ValidateRequest(BaseModel):
    message: str
    format: str = "MT940"


class ValidateResponse(BaseModel):
    valid: bool
    format: str
    detail: Optional[str] = None


class ReconcileRequest(BaseModel):
    mt940_message: str
    format: str = "MT940"
    ledger_csv: str
    tolerance_days: int = Field(default=2, ge=0, le=30)


class BankEntryOut(BaseModel):
    value_date: str
    amount: float
    dc_indicator: str
    reference: str
    bank_reference: str = ""
    transaction_details: str = ""


class LedgerEntryOut(BaseModel):
    date: str
    amount: float
    reference: str = ""


class ReconcileMatchOut(BaseModel):
    bank: BankEntryOut
    ledger: LedgerEntryOut
    confidence: str
    match_reason: str


class ReconcileSummary(BaseModel):
    bank_count: int
    ledger_count: int
    matched_count: int
    unmatched_bank_count: int
    unmatched_ledger_count: int
    match_rate: float


class ReconcileResponse(BaseModel):
    matched: list[ReconcileMatchOut]
    unmatched_bank: list[BankEntryOut]
    unmatched_ledger: list[LedgerEntryOut]
    summary: ReconcileSummary


class ClientCreate(BaseModel):
    name: str
    email: EmailStr
    rate_limit_per_min: int = 100
    scopes: list[str] = ["convert"]


class ClientResponse(BaseModel):
    id: str
    name: str
    email: str
    rate_limit_per_min: int
    scopes: str
    active: bool
    created_at: datetime
    credits_remaining: Optional[int] = None
    credits_expire_at: Optional[datetime] = None
    api_key_preview: Optional[str] = None
    has_password: bool = False

    class Config:
        from_attributes = True


class ClientCreateResponse(ClientResponse):
    api_key: str


class PackageGrant(BaseModel):
    credits: int
    days_valid: int = 90


class MeResponse(BaseModel):
    client_id: str
    name: str
    api_key_preview: Optional[str] = None
    credits_remaining: Optional[int] = None
    credits_expire_at: Optional[datetime] = None


class LoginRequest(BaseModel):
    email: EmailStr
    password: str


class SessionResponse(BaseModel):
    client_id: str
    name: str
    email: str


class SetPasswordRequest(BaseModel):
    token: str
    password: str = Field(min_length=8)


class ForgotPasswordRequest(BaseModel):
    email: EmailStr


class ChangePasswordRequest(BaseModel):
    current_password: str
    new_password: str = Field(min_length=8)


class RegenerateKeyResponse(BaseModel):
    api_key: str
    api_key_preview: str


class AuditLogResponse(BaseModel):
    id: str
    request_id: str
    client_id: str
    timestamp: datetime
    format_in: str
    status: str
    error_detail: Optional[str]
    duration_ms: int
    ip_address: str

    class Config:
        from_attributes = True


class HealthResponse(BaseModel):
    status: str
    version: str
    db: str
    uptime_s: int


class ErrorResponse(BaseModel):
    error: str
    detail: str
    request_id: str
