from __future__ import annotations

from datetime import datetime
from decimal import Decimal
from typing import Any

from pydantic import BaseModel, ConfigDict, Field


class BudgetAllocationCreate(BaseModel):
    fiscal_year: int = Field(ge=2000, le=2100)
    period_type: str = Field(default="quarter", max_length=20)
    period_key: str = Field(min_length=1, max_length=30)
    department_id: str | None = Field(default=None, max_length=36)
    department_name: str = Field(min_length=1, max_length=100)
    cost_center: str | None = Field(default=None, max_length=50)
    project_code: str | None = Field(default=None, max_length=50)
    subject_code: str = Field(min_length=1, max_length=50)
    subject_name: str = Field(min_length=1, max_length=100)
    original_amount: Decimal = Field(ge=0)
    warning_threshold: Decimal = Field(default=Decimal("80.00"), ge=0, le=100)
    control_action: str = Field(default="block", max_length=30)
    description: str | None = Field(default=None, max_length=500)


class BudgetCheckRequest(BaseModel):
    fiscal_year: int | None = Field(default=None, ge=2000, le=2100)
    period_key: str | None = Field(default=None, max_length=30)
    department_id: str | None = Field(default=None, max_length=36)
    department_name: str | None = Field(default=None, max_length=100)
    cost_center: str | None = Field(default=None, max_length=50)
    project_code: str | None = Field(default=None, max_length=50)
    subject_code: str = Field(min_length=1, max_length=50)
    amount: Decimal = Field(ge=0)


class BudgetOperationRequest(BudgetCheckRequest):
    source_type: str = Field(min_length=1, max_length=40)
    source_id: str = Field(min_length=1, max_length=64)
    source_no: str = Field(min_length=1, max_length=80)
    reason: str | None = Field(default=None, max_length=500)


class BudgetBalanceRead(BaseModel):
    total_amount: Decimal
    reserved_amount: Decimal
    consumed_amount: Decimal
    available_amount: Decimal
    usage_rate: Decimal


class BudgetAllocationRead(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: str
    budget_no: str
    fiscal_year: int
    period_type: str
    period_key: str
    department_id: str | None
    department_name: str
    cost_center: str | None
    project_code: str | None
    subject_code: str
    subject_name: str
    original_amount: Decimal
    adjusted_amount: Decimal
    status: str
    warning_threshold: Decimal
    control_action: str
    description: str | None = None
    balance: BudgetBalanceRead
    created_at: datetime
    updated_at: datetime


class BudgetTransactionRead(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: str
    transaction_no: str
    allocation_id: str
    reservation_id: str | None
    source_type: str
    source_id: str
    source_no: str
    transaction_type: str
    amount: Decimal
    before_available_amount: Decimal
    after_available_amount: Decimal
    operator: str | None
    reason: str | None
    created_at: datetime


class BudgetTrendPointRead(BaseModel):
    period_key: str
    label: str
    total_amount: Decimal
    reserved_amount: Decimal
    consumed_amount: Decimal
    used_amount: Decimal
    available_amount: Decimal
    usage_rate: Decimal


class BudgetWarningRead(BaseModel):
    allocation_id: str
    budget_no: str
    fiscal_year: int
    period_key: str
    department_name: str
    cost_center: str | None = None
    subject_code: str
    subject_name: str
    total_amount: Decimal
    reserved_amount: Decimal
    consumed_amount: Decimal
    available_amount: Decimal
    usage_rate: Decimal
    warning_threshold: Decimal
    severity: str
    message: str
    occurred_at: datetime | None = None


class BudgetSummaryRead(BaseModel):
    fiscal_year: int | None = None
    period_key: str | None = None
    total_amount: Decimal
    reserved_amount: Decimal
    consumed_amount: Decimal
    available_amount: Decimal
    warning_count: int
    over_budget_count: int
    allocations: list[BudgetAllocationRead] = Field(default_factory=list)
    trend: list[BudgetTrendPointRead] = Field(default_factory=list)
    warnings: list[BudgetWarningRead] = Field(default_factory=list)


class BudgetCheckRead(BaseModel):
    passed: bool
    blocking_reasons: list[str] = Field(default_factory=list)
    flags: list[dict] = Field(default_factory=list)
    allocation: BudgetAllocationRead | None = None


class BudgetClaimAnalysisRead(BaseModel):
    budget_context: dict[str, Any] = Field(default_factory=dict)
    score: int
    rating: str
    risk_level: str
    summary: str
    metrics: dict[str, Any] = Field(default_factory=dict)
    basis: list[str] = Field(default_factory=list)
    suggestions: list[str] = Field(default_factory=list)


class BudgetOperationRead(BaseModel):
    ok: bool
    message: str
    reservation_id: str | None = None
    allocation: BudgetAllocationRead | None = None
    transaction: BudgetTransactionRead | None = None
    flags: list[dict] = Field(default_factory=list)
