from __future__ import annotations

from datetime import date, datetime
from decimal import Decimal
from typing import Any

from pydantic import BaseModel, ConfigDict, Field


class ReimbursementCreate(BaseModel):
    request_no: str
    employee_id: str
    title: str
    category: str
    amount: Decimal
    reason: str | None = None


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

    id: str
    request_no: str
    employee_id: str
    title: str
    category: str
    status: str
    amount: Decimal
    reason: str | None
    created_at: datetime
    updated_at: datetime


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

    id: str
    item_date: date
    item_type: str
    item_reason: str
    item_location: str
    item_amount: Decimal
    invoice_id: str | None
    is_system_generated: bool = False
    created_at: datetime
    updated_at: datetime


class ExpenseClaimAttachmentAnalysisRead(BaseModel):
    severity: str
    label: str
    headline: str
    summary: str
    points: list[str] = Field(default_factory=list)
    rule_basis: list[str] = Field(default_factory=list)
    suggestion: str = ""


class ExpenseClaimAttachmentDocumentFieldRead(BaseModel):
    key: str
    label: str
    value: str


class ExpenseClaimAttachmentDocumentInfoRead(BaseModel):
    document_type: str = "other"
    document_type_label: str = "其他单据"
    scene_code: str = "other"
    scene_label: str = "其他票据"
    fields: list[ExpenseClaimAttachmentDocumentFieldRead] = Field(default_factory=list)


class ExpenseClaimAttachmentRequirementRead(BaseModel):
    matches: bool = False
    current_expense_type: str = "other"
    current_expense_type_label: str = "其他"
    allowed_scene_labels: list[str] = Field(default_factory=list)
    recognized_scene_code: str = "other"
    recognized_scene_label: str = "其他票据"
    recognized_document_type: str = "other"
    recognized_document_type_label: str = "其他单据"
    message: str = ""


class ExpenseClaimAttachmentRead(BaseModel):
    file_name: str
    storage_key: str
    media_type: str
    size_bytes: int
    uploaded_at: datetime | None = None
    previewable: bool = True
    preview_kind: str = ""
    preview_url: str = ""
    analysis: ExpenseClaimAttachmentAnalysisRead | None = None
    document_info: ExpenseClaimAttachmentDocumentInfoRead | None = None
    requirement_check: ExpenseClaimAttachmentRequirementRead | None = None


class ExpenseClaimItemUpdate(BaseModel):
    item_date: date | None = None
    item_type: str | None = None
    item_reason: str | None = None
    item_location: str | None = None
    item_amount: Decimal | None = None
    invoice_id: str | None = None


class ExpenseClaimItemCreate(BaseModel):
    item_date: date | None = None
    item_type: str | None = None
    item_reason: str | None = None
    item_location: str | None = None
    item_amount: Decimal | None = None
    invoice_id: str | None = None


class ExpenseClaimUpdate(BaseModel):
    reason: str | None = Field(default=None, max_length=500)


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

    id: str
    claim_no: str
    employee_id: str | None
    employee_name: str
    department_id: str | None
    department_name: str
    employee_position: str | None = None
    employee_grade: str | None = None
    manager_name: str | None = None
    role_labels: list[str] = Field(default_factory=list)
    project_code: str | None
    expense_type: str
    reason: str
    location: str
    amount: Decimal
    currency: str
    invoice_count: int
    occurred_at: datetime
    submitted_at: datetime | None
    status: str
    approval_stage: str | None
    risk_flags_json: list[Any] = Field(default_factory=list)
    created_at: datetime
    updated_at: datetime
    items: list[ExpenseClaimItemRead] = Field(default_factory=list)


class ExpenseClaimActionResponse(BaseModel):
    message: str
    claim_id: str
    status: str | None = None


class ExpenseClaimReturnPayload(BaseModel):
    reason: str | None = Field(default=None, max_length=500)
    reason_codes: list[str] = Field(default_factory=list, max_length=10)


class ExpenseClaimApprovalPayload(BaseModel):
    opinion: str | None = Field(default=None, max_length=500)


class TravelReimbursementCalculatorRequest(BaseModel):
    days: int = Field(ge=1, le=365)
    location: str = Field(min_length=1, max_length=120)
    grade: str | None = Field(default=None, max_length=30)


class TravelReimbursementCalculatorResponse(BaseModel):
    days: int
    location: str
    matched_city: str
    city_tier: str
    grade: str
    grade_band: str
    grade_band_label: str
    hotel_rate: Decimal
    hotel_amount: Decimal
    allowance_region: str
    meal_allowance_rate: Decimal
    basic_allowance_rate: Decimal
    total_allowance_rate: Decimal
    allowance_amount: Decimal
    total_amount: Decimal
    rule_name: str
    rule_version: str
    formula_text: str
    summary_text: str


class ExpenseClaimAttachmentActionResponse(BaseModel):
    message: str
    claim_id: str
    item_id: str
    invoice_id: str | None = None
    item_date: date | None = None
    item_type: str | None = None
    item_reason: str | None = None
    item_location: str | None = None
    item_amount: Decimal | None = None
    claim_amount: Decimal | None = None
    attachment: ExpenseClaimAttachmentRead | None = None


class ExpenseClaimItemActionResponse(BaseModel):
    message: str
    claim_id: str
    item_id: str
