"""
SAMMS Enterprise - Fixed Asset Registry Schemas
Fixed asset management with depreciation and automated journal entries
"""

from datetime import datetime, date
from typing import Optional, List, Dict, Any, Union, Literal
from decimal import Decimal
from enum import Enum
from pydantic import BaseModel, Field, ConfigDict, field_validator, model_validator, computed_field
from .base import (
    BaseResponseSchema,
    TimestampMixin,
    PaginationParams,
    ListResponseBase,
    AuditMixin,
    CompanyScopedMixin
)


# ==================== ENUMS ====================

class AssetStatus(str, Enum):
    """Asset lifecycle status"""
    DRAFT = "draft"
    PENDING_APPROVAL = "pending_approval"
    ACTIVE = "active"
    IN_USE = "in_use"
    UNDER_CONSTRUCTION = "under_construction"
    IDLE = "idle"
    HELD_FOR_SALE = "held_for_sale"
    DISPOSED = "disposed"
    FULLY_DEPRECIATED = "fully_depreciated"
    WRITTEN_OFF = "written_off"
    REVALUED = "revalued"
    IMPAIRED = "impaired"


class AssetCategory(str, Enum):
    """Asset category types"""
    LAND = "land"
    BUILDING = "building"
    MACHINERY = "machinery"
    EQUIPMENT = "equipment"
    VEHICLE = "vehicle"
    FURNITURE_FIXTURES = "furniture_fixtures"
    COMPUTER_HARDWARE = "computer_hardware"
    COMPUTER_SOFTWARE = "computer_software"
    LEASEHOLD_IMPROVEMENTS = "leasehold_improvements"
    INTANGIBLE_ASSETS = "intangible_assets"
    CONSTRUCTION_IN_PROGRESS = "construction_in_progress"
    GOODWILL = "goodwill"
    PATENTS = "patents"
    TRADEMARKS = "trademarks"
    COPYRIGHTS = "copyrights"
    LICENSES = "licenses"
    NATURAL_RESOURCES = "natural_resources"
    BIOLOGICAL_ASSETS = "biological_assets"
    INVESTMENT_PROPERTY = "investment_property"
    RIGHT_OF_USE_ASSET = "right_of_use_asset"
    OTHER = "other"


class DepreciationMethod(str, Enum):
    """Depreciation calculation methods"""
    STRAIGHT_LINE = "straight_line"
    DECLINING_BALANCE = "declining_balance"
    DOUBLE_DECLINING = "double_declining"
    SUM_OF_YEARS_DIGITS = "sum_of_years_digits"
    UNITS_OF_PRODUCTION = "units_of_production"
    NONE = "none"
    CUSTOM = "custom"


class AssetValuationMethod(str, Enum):
    """Asset valuation methods"""
    HISTORICAL_COST = "historical_cost"
    REVALUATION = "revaluation"
    FAIR_VALUE = "fair_value"
    NET_REALIZABLE_VALUE = "net_realizable_value"
    PRESENT_VALUE = "present_value"


class DisposalMethod(str, Enum):
    """Asset disposal methods"""
    SALE = "sale"
    SCRAPPING = "scrapping"
    DONATION = "donation"
    EXCHANGE = "exchange"
    THEFT = "theft"
    DESTRUCTION = "destruction"
    TRANSFER = "transfer"
    OTHER = "other"


class ImpairmentStatus(str, Enum):
    """Asset impairment status"""
    NOT_IMPAIRED = "not_impaired"
    POTENTIALLY_IMPAIRED = "potentially_impaired"
    IMPAIRED = "impaired"
    REVERSED = "reversed"


class MaintenanceType(str, Enum):
    """Types of maintenance"""
    PREVENTIVE = "preventive"
    CORRECTIVE = "corrective"
    PREDICTIVE = "predictive"
    EMERGENCY = "emergency"
    ROUTINE = "routine"
    OVERHAUL = "overhaul"


class MaintenanceStatus(str, Enum):
    """Maintenance record status"""
    SCHEDULED = "scheduled"
    IN_PROGRESS = "in_progress"
    COMPLETED = "completed"
    CANCELLED = "cancelled"
    OVERDUE = "overdue"


class InsuranceStatus(str, Enum):
    """Insurance policy status"""
    ACTIVE = "active"
    EXPIRED = "expired"
    CANCELLED = "cancelled"
    PENDING_RENEWAL = "pending_renewal"


# ==================== ASSET CLASS ====================

class AssetClassBase(BaseModel):
    """Base schema for asset classes"""
    name: str = Field(..., min_length=1, max_length=200, description="Asset class name")
    code: str = Field(..., min_length=1, max_length=20, pattern=r"^[A-Z][A-Z0-9._-]*$", description="Unique code")
    description: Optional[str] = Field(None, max_length=2000, description="Description")
    category: AssetCategory = Field(..., description="Asset category")
    parent_class_id: Optional[int] = Field(None, description="Parent asset class ID")
    depreciation_method: DepreciationMethod = Field(default=DepreciationMethod.STRAIGHT_LINE, description="Default depreciation method")
    useful_life_years: int = Field(..., ge=0, le=100, description="Default useful life in years")
    useful_life_months: int = Field(default=0, ge=0, le=1199, description="Additional months")
    salvage_value_percentage: Decimal = Field(default=Decimal('0'), ge=0, le=100, description="Default salvage value %")
    depreciation_rate: Optional[Decimal] = Field(None, ge=0, le=100, description="Depreciation rate for declining balance")
    asset_account_id: int = Field(..., description="GL account for asset cost")
    accumulated_depreciation_account_id: int = Field(..., description="GL account for accumulated depreciation")
    depreciation_expense_account_id: int = Field(..., description="GL account for depreciation expense")
    impairment_account_id: Optional[int] = Field(None, description="GL account for impairment losses")
    gain_loss_account_id: Optional[int] = Field(None, description="GL account for disposal gain/loss")
    is_active: bool = Field(default=True, description="Whether class is active")
    requires_tracking: bool = Field(default=True, description="Requires individual asset tracking")
    requires_maintenance: bool = Field(default=False, description="Requires maintenance tracking")
    requires_insurance: bool = Field(default=False, description="Requires insurance tracking")
    custom_fields_schema: Optional[Dict[str, Any]] = Field(None, description="Custom fields definition")


class AssetClassCreate(AssetClassBase):
    """Schema for creating asset classes"""
    pass


class AssetClassUpdate(BaseModel):
    """Schema for updating asset classes"""
    name: Optional[str] = Field(None, min_length=1, max_length=200)
    description: Optional[str] = Field(None, max_length=2000)
    depreciation_method: Optional[DepreciationMethod] = None
    useful_life_years: Optional[int] = Field(None, ge=0, le=100)
    useful_life_months: Optional[int] = Field(None, ge=0, le=1199)
    salvage_value_percentage: Optional[Decimal] = Field(None, ge=0, le=100)
    depreciation_rate: Optional[Decimal] = Field(None, ge=0, le=100)
    asset_account_id: Optional[int] = None
    accumulated_depreciation_account_id: Optional[int] = None
    depreciation_expense_account_id: Optional[int] = None
    impairment_account_id: Optional[int] = None
    gain_loss_account_id: Optional[int] = None
    is_active: Optional[bool] = None
    requires_tracking: Optional[bool] = None
    requires_maintenance: Optional[bool] = None
    requires_insurance: Optional[bool] = None
    custom_fields_schema: Optional[Dict[str, Any]] = None


class AssetClassResponse(AssetClassBase, BaseResponseSchema, CompanyScopedMixin):
    """Schema for asset class responses"""
    full_code: Optional[str] = Field(None, description="Full hierarchical code")
    total_assets: int = Field(default=0, description="Total assets in class")
    total_cost: Decimal = Field(default=Decimal('0'), description="Total asset cost")
    total_accumulated_depreciation: Decimal = Field(default=Decimal('0'), description="Total accumulated depreciation")
    total_net_book_value: Decimal = Field(default=Decimal('0'), description="Total net book value")

    model_config = ConfigDict(from_attributes=True)


# ==================== ASSET LOCATION ====================

class AssetLocationBase(BaseModel):
    """Base schema for asset locations"""
    name: str = Field(..., min_length=1, max_length=200, description="Location name")
    code: str = Field(..., min_length=1, max_length=20, description="Unique location code")
    description: Optional[str] = Field(None, max_length=2000, description="Description")
    parent_location_id: Optional[int] = Field(None, description="Parent location ID")
    location_type: str = Field(default="building", description="Location type: building, floor, room, warehouse, site, etc.")
    address_line1: Optional[str] = Field(None, max_length=200, description="Address line 1")
    address_line2: Optional[str] = Field(None, max_length=200, description="Address line 2")
    city: Optional[str] = Field(None, max_length=100, description="City")
    state_province: Optional[str] = Field(None, max_length=100, description="State/Province")
    postal_code: Optional[str] = Field(None, max_length=20, description="Postal code")
    country: Optional[str] = Field(None, max_length=100, description="Country")
    latitude: Optional[Decimal] = Field(None, ge=-90, le=90, description="GPS latitude")
    longitude: Optional[Decimal] = Field(None, ge=-180, le=180, description="GPS longitude")
    manager_id: Optional[int] = Field(None, description="Responsible manager user ID")
    department_id: Optional[int] = Field(None, description="Owning department ID")
    is_active: bool = Field(default=True, description="Whether location is active")


class AssetLocationCreate(AssetLocationBase):
    """Schema for creating asset locations"""
    pass


class AssetLocationUpdate(BaseModel):
    """Schema for updating asset locations"""
    name: Optional[str] = Field(None, min_length=1, max_length=200)
    description: Optional[str] = Field(None, max_length=2000)
    address_line1: Optional[str] = Field(None, max_length=200)
    address_line2: Optional[str] = Field(None, max_length=200)
    city: Optional[str] = Field(None, max_length=100)
    state_province: Optional[str] = Field(None, max_length=100)
    postal_code: Optional[str] = Field(None, max_length=20)
    country: Optional[str] = Field(None, max_length=100)
    latitude: Optional[Decimal] = Field(None, ge=-90, le=90)
    longitude: Optional[Decimal] = Field(None, ge=-180, le=180)
    manager_id: Optional[int] = None
    department_id: Optional[int] = None
    is_active: Optional[bool] = None


class AssetLocationResponse(AssetLocationBase, BaseResponseSchema, CompanyScopedMixin):
    """Schema for asset location responses"""
    full_path: Optional[str] = Field(None, description="Full hierarchical path")
    total_assets: int = Field(default=0, description="Total assets at location")
    total_asset_value: Decimal = Field(default=Decimal('0'), description="Total asset value at location")

    model_config = ConfigDict(from_attributes=True)


# ==================== FIXED ASSET ====================

class FixedAssetBase(BaseModel):
    """Base schema for fixed assets"""
    asset_number: str = Field(..., min_length=1, max_length=50, description="Unique asset number")
    name: str = Field(..., min_length=1, max_length=200, description="Asset name")
    description: Optional[str] = Field(None, max_length=2000, description="Asset description")
    asset_class_id: int = Field(..., description="Asset class ID")
    category: AssetCategory = Field(..., description="Asset category")
    status: AssetStatus = Field(default=AssetStatus.ACTIVE, description="Asset status")
    
    # Acquisition Information
    acquisition_date: date = Field(..., description="Date of acquisition")
    acquisition_cost: Decimal = Field(..., ge=0, description="Original acquisition cost")
    acquisition_type: str = Field(default="purchase", description="How asset was acquired: purchase, construction, donation, exchange, transfer")
    vendor_id: Optional[int] = Field(None, description="Vendor ID if purchased")
    purchase_order_id: Optional[int] = Field(None, description="Related purchase order ID")
    invoice_id: Optional[int] = Field(None, description="Related invoice ID")
    invoice_number: Optional[str] = Field(None, max_length=50, description="Invoice number")
    
    # Depreciation Settings
    depreciation_method: DepreciationMethod = Field(default=DepreciationMethod.STRAIGHT_LINE, description="Depreciation method")
    useful_life_years: int = Field(..., ge=0, le=100, description="Useful life in years")
    useful_life_months: int = Field(default=0, ge=0, le=1199, description="Additional months")
    salvage_value: Decimal = Field(default=Decimal('0'), ge=0, description="Expected salvage value")
    depreciation_start_date: Optional[date] = Field(None, description="Depreciation start date")
    depreciation_end_date: Optional[date] = Field(None, description="Depreciation end date")
    
    # Current Values
    accumulated_depreciation: Decimal = Field(default=Decimal('0'), description="Total accumulated depreciation")
    net_book_value: Optional[Decimal] = Field(None, description="Current net book value")
    revaluation_reserve: Decimal = Field(default=Decimal('0'), description="Revaluation reserve balance")
    impairment_loss: Decimal = Field(default=Decimal('0'), description="Accumulated impairment losses")
    
    # Location and Custody
    location_id: Optional[int] = Field(None, description="Physical location ID")
    custodian_id: Optional[int] = Field(None, description="Custodian employee ID")
    department_id: Optional[int] = Field(None, description="Owning department ID")
    cost_center_id: Optional[int] = Field(None, description="Cost center ID")
    
    # Physical Details
    serial_number: Optional[str] = Field(None, max_length=100, description="Serial number")
    model_number: Optional[str] = Field(None, max_length=100, description="Model number")
    manufacturer: Optional[str] = Field(None, max_length=200, description="Manufacturer")
    brand: Optional[str] = Field(None, max_length=100, description="Brand name")
    color: Optional[str] = Field(None, max_length=50, description="Color")
    size: Optional[str] = Field(None, max_length=50, description="Size")
    weight: Optional[Decimal] = Field(None, description="Weight")
    weight_unit: Optional[str] = Field(None, max_length=10, description="Weight unit")
    dimensions: Optional[str] = Field(None, max_length=100, description="Dimensions")
    
    # Identification
    barcode: Optional[str] = Field(None, max_length=100, description="Barcode")
    rfid_tag: Optional[str] = Field(None, max_length=100, description="RFID tag")
    plate_number: Optional[str] = Field(None, max_length=50, description="Asset plate number")
    
    # Additional Information
    warranty_expiry_date: Optional[date] = Field(None, description="Warranty expiry date")
    insurance_policy_id: Optional[int] = Field(None, description="Insurance policy ID")
    lease_id: Optional[int] = Field(None, description="Related lease ID")
    project_id: Optional[int] = Field(None, description="Related project ID")
    
    # GL Integration
    asset_account_id: int = Field(..., description="GL account for asset cost")
    accumulated_depreciation_account_id: int = Field(..., description="GL account for accumulated depreciation")
    depreciation_expense_account_id: int = Field(..., description="GL account for depreciation expense")
    
    # Custom Data
    custom_fields: Optional[Dict[str, Any]] = Field(None, description="Custom field values")
    tags: Optional[List[str]] = Field(None, description="Tags for categorization")
    
    # Attachments
    image_url: Optional[str] = Field(None, max_length=500, description="Asset image URL")
    document_ids: Optional[List[int]] = Field(None, description="Related document IDs")
    
    notes: Optional[str] = Field(None, max_length=5000, description="Additional notes")


class FixedAssetCreate(FixedAssetBase):
    """Schema for creating fixed assets"""
    auto_generate_depreciation: bool = Field(default=True, description="Auto-generate depreciation schedule")
    
    @model_validator(mode='after')
    def calculate_nbv(self):
        if self.net_book_value is None:
            self.net_book_value = self.acquisition_cost
        return self


class FixedAssetUpdate(BaseModel):
    """Schema for updating fixed assets"""
    name: Optional[str] = Field(None, min_length=1, max_length=200)
    description: Optional[str] = Field(None, max_length=2000)
    status: Optional[AssetStatus] = None
    location_id: Optional[int] = None
    custodian_id: Optional[int] = None
    department_id: Optional[int] = None
    cost_center_id: Optional[int] = None
    serial_number: Optional[str] = Field(None, max_length=100)
    model_number: Optional[str] = Field(None, max_length=100)
    barcode: Optional[str] = Field(None, max_length=100)
    rfid_tag: Optional[str] = Field(None, max_length=100)
    warranty_expiry_date: Optional[date] = None
    insurance_policy_id: Optional[int] = None
    custom_fields: Optional[Dict[str, Any]] = None
    tags: Optional[List[str]] = None
    image_url: Optional[str] = Field(None, max_length=500)
    notes: Optional[str] = Field(None, max_length=5000)


class FixedAssetResponse(FixedAssetBase, BaseResponseSchema, CompanyScopedMixin):
    """Schema for fixed asset responses"""
    asset_class_name: Optional[str] = None
    asset_class_code: Optional[str] = None
    location_name: Optional[str] = None
    custodian_name: Optional[str] = None
    department_name: Optional[str] = None
    vendor_name: Optional[str] = None
    
    # Calculated fields
    total_useful_life_months: int = Field(default=0, description="Total useful life in months")
    age_in_months: int = Field(default=0, description="Asset age in months")
    remaining_life_months: int = Field(default=0, description="Remaining useful life in months")
    depreciation_percentage: Decimal = Field(default=Decimal('0'), description="Depreciation percentage")
    is_fully_depreciated: bool = Field(default=False, description="Whether fully depreciated")
    impairment_status: ImpairmentStatus = Field(default=ImpairmentStatus.NOT_IMPAIRED)
    
    # Statistics
    total_depreciation_expense: Decimal = Field(default=Decimal('0'), description="Total depreciation expense")
    total_revaluations: int = Field(default=0, description="Number of revaluations")
    total_transfers: int = Field(default=0, description="Number of transfers")
    
    created_by_id: int
    approved_by_id: Optional[int] = None
    approved_at: Optional[datetime] = None

    model_config = ConfigDict(from_attributes=True)


# ==================== DEPRECIATION SCHEDULE ====================

class DepreciationScheduleLineBase(BaseModel):
    """Base schema for depreciation schedule lines"""
    fiscal_year: int = Field(..., ge=2000, le=2100, description="Fiscal year")
    fiscal_period: int = Field(..., ge=1, le=12, description="Fiscal period (month)")
    period_start_date: date = Field(..., description="Period start date")
    period_end_date: date = Field(..., description="Period end date")
    opening_net_book_value: Decimal = Field(..., description="Opening NBV")
    depreciation_amount: Decimal = Field(..., ge=0, description="Depreciation amount for period")
    closing_net_book_value: Decimal = Field(..., description="Closing NBV")
    is_posted: bool = Field(default=False, description="Whether journal entry is posted")
    journal_entry_id: Optional[int] = Field(None, description="Posted journal entry ID")
    posted_date: Optional[datetime] = Field(None, description="Date posted")


class DepreciationScheduleLineResponse(DepreciationScheduleLineBase, BaseResponseSchema):
    """Schema for depreciation schedule line responses"""
    asset_id: int
    model_config = ConfigDict(from_attributes=True)


class DepreciationScheduleBase(BaseModel):
    """Base schema for depreciation schedules"""
    asset_id: int = Field(..., description="Asset ID")
    schedule_type: str = Field(default="standard", description="Schedule type: standard, accelerated, custom")
    depreciation_method: DepreciationMethod = Field(..., description="Depreciation method")
    total_periods: int = Field(..., ge=1, description="Total depreciation periods")
    total_depreciation: Decimal = Field(..., description="Total depreciation amount")
    remaining_depreciation: Decimal = Field(default=Decimal('0'), description="Remaining depreciation")
    is_active: bool = Field(default=True, description="Whether schedule is active")


class DepreciationScheduleResponse(DepreciationScheduleBase, BaseResponseSchema):
    """Schema for depreciation schedule responses"""
    lines: List[DepreciationScheduleLineResponse] = Field(default_factory=list)
    asset_number: Optional[str] = None
    asset_name: Optional[str] = None

    model_config = ConfigDict(from_attributes=True)


# ==================== DEPRECIATION RUN ====================

class DepreciationRunLineBase(BaseModel):
    """Base schema for depreciation run lines"""
    asset_id: int = Field(..., description="Asset ID")
    asset_number: str = Field(..., description="Asset number")
    asset_name: str = Field(..., description="Asset name")
    opening_nbv: Decimal = Field(..., description="Opening net book value")
    depreciation_amount: Decimal = Field(..., description="Depreciation amount")
    closing_nbv: Decimal = Field(..., description="Closing net book value")
    depreciation_account_id: int = Field(..., description="Depreciation expense account")
    accumulated_account_id: int = Field(..., description="Accumulated depreciation account")
    is_selected: bool = Field(default=True, description="Whether to include in posting")
    journal_entry_line_id: Optional[int] = Field(None, description="Created journal entry line ID")


class DepreciationRunLineResponse(DepreciationRunLineBase, BaseResponseSchema):
    """Schema for depreciation run line responses"""
    run_id: int
    model_config = ConfigDict(from_attributes=True)


class DepreciationRunBase(BaseModel):
    """Base schema for depreciation runs"""
    name: str = Field(..., min_length=1, max_length=200, description="Run name")
    fiscal_year: int = Field(..., ge=2000, le=2100, description="Fiscal year")
    fiscal_period: int = Field(..., ge=1, le=12, description="Fiscal period")
    run_date: date = Field(..., description="Run date")
    description: Optional[str] = Field(None, max_length=2000, description="Description")
    status: str = Field(default="draft", description="Status: draft, posted, reversed")
    total_assets: int = Field(default=0, description="Total assets processed")
    total_depreciation: Decimal = Field(default=Decimal('0'), description="Total depreciation amount")
    journal_entry_id: Optional[int] = Field(None, description="Created journal entry ID")
    posted_at: Optional[datetime] = Field(None, description="Posted timestamp")
    posted_by_id: Optional[int] = Field(None, description="Posted by user ID")
    reversed_at: Optional[datetime] = Field(None, description="Reversed timestamp")
    reversed_by_id: Optional[int] = Field(None, description="Reversed by user ID")
    reversal_entry_id: Optional[int] = Field(None, description="Reversal journal entry ID")


class DepreciationRunCreate(DepreciationRunBase):
    """Schema for creating depreciation runs"""
    asset_ids: Optional[List[int]] = Field(None, description="Specific assets to include")
    asset_class_ids: Optional[List[int]] = Field(None, description="Asset classes to include")
    auto_post: bool = Field(default=False, description="Automatically post journal entry")


class DepreciationRunUpdate(BaseModel):
    """Schema for updating depreciation runs"""
    name: Optional[str] = Field(None, min_length=1, max_length=200)
    description: Optional[str] = Field(None, max_length=2000)


class DepreciationRunResponse(DepreciationRunBase, BaseResponseSchema, CompanyScopedMixin):
    """Schema for depreciation run responses"""
    lines: List[DepreciationRunLineResponse] = Field(default_factory=list)
    created_by_id: int

    model_config = ConfigDict(from_attributes=True)


# ==================== ASSET TRANSFER ====================

class AssetTransferBase(BaseModel):
    """Base schema for asset transfers"""
    transfer_number: str = Field(..., min_length=1, max_length=50, description="Transfer number")
    transfer_date: date = Field(..., description="Transfer date")
    transfer_type: str = Field(default="location", description="Transfer type: location, department, custodian, company")
    description: Optional[str] = Field(None, max_length=2000, description="Transfer description")
    
    # Source information
    from_location_id: Optional[int] = Field(None, description="Source location ID")
    from_department_id: Optional[int] = Field(None, description="Source department ID")
    from_custodian_id: Optional[int] = Field(None, description="Source custodian ID")
    from_company_id: Optional[int] = Field(None, description="Source company ID")
    
    # Destination information
    to_location_id: Optional[int] = Field(None, description="Destination location ID")
    to_department_id: Optional[int] = Field(None, description="Destination department ID")
    to_custodian_id: Optional[int] = Field(None, description="Destination custodian ID")
    to_company_id: Optional[int] = Field(None, description="Destination company ID")
    
    status: str = Field(default="pending", description="Status: pending, approved, completed, cancelled")
    approval_required: bool = Field(default=True, description="Whether approval is required")
    approved_by_id: Optional[int] = Field(None, description="Approved by user ID")
    approved_at: Optional[datetime] = Field(None, description="Approval timestamp")
    completed_at: Optional[datetime] = Field(None, description="Completion timestamp")
    notes: Optional[str] = Field(None, max_length=2000, description="Additional notes")


class AssetTransferCreate(AssetTransferBase):
    """Schema for creating asset transfers"""
    asset_ids: List[int] = Field(..., min_length=1, description="Asset IDs to transfer")


class AssetTransferUpdate(BaseModel):
    """Schema for updating asset transfers"""
    description: Optional[str] = Field(None, max_length=2000)
    notes: Optional[str] = Field(None, max_length=2000)


class AssetTransferResponse(AssetTransferBase, BaseResponseSchema, CompanyScopedMixin):
    """Schema for asset transfer responses"""
    assets: List[FixedAssetResponse] = Field(default_factory=list)
    from_location_name: Optional[str] = None
    to_location_name: Optional[str] = None
    from_department_name: Optional[str] = None
    to_department_name: Optional[str] = None
    from_custodian_name: Optional[str] = None
    to_custodian_name: Optional[str] = None
    requested_by_id: int

    model_config = ConfigDict(from_attributes=True)


# ==================== ASSET DISPOSAL ====================

class AssetDisposalLineBase(BaseModel):
    """Base schema for disposal lines"""
    asset_id: int = Field(..., description="Asset ID")
    asset_number: Optional[str] = None
    asset_name: Optional[str] = None
    original_cost: Decimal = Field(..., description="Original asset cost")
    accumulated_depreciation: Decimal = Field(..., description="Accumulated depreciation at disposal")
    net_book_value: Decimal = Field(..., description="Net book value at disposal")
    disposal_value: Decimal = Field(default=Decimal('0'), description="Proceeds from disposal")
    disposal_costs: Decimal = Field(default=Decimal('0'), description="Costs of disposal")
    gain_loss: Decimal = Field(default=Decimal('0'), description="Gain or loss on disposal")
    gain_loss_account_id: Optional[int] = Field(None, description="Gain/loss account ID")


class AssetDisposalLineCreate(AssetDisposalLineBase):
    """Schema for creating disposal lines"""
    pass


class AssetDisposalLineResponse(AssetDisposalLineBase, BaseResponseSchema):
    """Schema for disposal line responses"""
    disposal_id: int
    model_config = ConfigDict(from_attributes=True)


class AssetDisposalBase(BaseModel):
    """Base schema for asset disposals"""
    disposal_number: str = Field(..., min_length=1, max_length=50, description="Disposal number")
    disposal_date: date = Field(..., description="Disposal date")
    disposal_method: DisposalMethod = Field(..., description="Method of disposal")
    description: Optional[str] = Field(None, max_length=2000, description="Disposal description")
    
    # Buyer information (for sales)
    buyer_id: Optional[int] = Field(None, description="Buyer contact ID")
    buyer_name: Optional[str] = Field(None, max_length=200, description="Buyer name")
    buyer_address: Optional[str] = Field(None, max_length=500, description="Buyer address")
    
    # Financial details
    total_proceeds: Decimal = Field(default=Decimal('0'), description="Total proceeds from disposal")
    total_disposal_costs: Decimal = Field(default=Decimal('0'), description="Total disposal costs")
    total_gain_loss: Decimal = Field(default=Decimal('0'), description="Total gain or loss")
    
    # Status and approval
    status: str = Field(default="pending", description="Status: pending, approved, completed, cancelled")
    approval_required: bool = Field(default=True, description="Whether approval is required")
    approved_by_id: Optional[int] = Field(None, description="Approved by user ID")
    approved_at: Optional[datetime] = Field(None, description="Approval timestamp")
    completed_at: Optional[datetime] = Field(None, description="Completion timestamp")
    
    # GL Integration
    journal_entry_id: Optional[int] = Field(None, description="Created journal entry ID")
    
    # Additional information
    reference: Optional[str] = Field(None, max_length=100, description="Reference number")
    notes: Optional[str] = Field(None, max_length=2000, description="Additional notes")


class AssetDisposalCreate(AssetDisposalBase):
    """Schema for creating asset disposals"""
    lines: List[AssetDisposalLineCreate] = Field(..., min_length=1, description="Disposal lines")


class AssetDisposalUpdate(BaseModel):
    """Schema for updating asset disposals"""
    description: Optional[str] = Field(None, max_length=2000)
    buyer_id: Optional[int] = None
    buyer_name: Optional[str] = Field(None, max_length=200)
    buyer_address: Optional[str] = Field(None, max_length=500)
    reference: Optional[str] = Field(None, max_length=100)
    notes: Optional[str] = Field(None, max_length=2000)


class AssetDisposalResponse(AssetDisposalBase, BaseResponseSchema, CompanyScopedMixin):
    """Schema for asset disposal responses"""
    lines: List[AssetDisposalLineResponse] = Field(default_factory=list)
    total_original_cost: Decimal = Field(default=Decimal('0'), description="Total original cost")
    total_accumulated_depreciation: Decimal = Field(default=Decimal('0'), description="Total accumulated depreciation")
    total_net_book_value: Decimal = Field(default=Decimal('0'), description="Total net book value")
    requested_by_id: int

    model_config = ConfigDict(from_attributes=True)


# ==================== ASSET REVALUATION ====================

class AssetRevaluationBase(BaseModel):
    """Base schema for asset revaluations"""
    revaluation_number: str = Field(..., min_length=1, max_length=50, description="Revaluation number")
    revaluation_date: date = Field(..., description="Revaluation date")
    description: Optional[str] = Field(None, max_length=2000, description="Description")
    revaluation_type: str = Field(default="upward", description="Revaluation type: upward, downward")
    
    # Values
    previous_cost: Decimal = Field(..., description="Previous asset cost")
    new_cost: Decimal = Field(..., description="New asset cost")
    cost_adjustment: Decimal = Field(..., description="Cost adjustment amount")
    previous_accumulated_depreciation: Decimal = Field(..., description="Previous accumulated depreciation")
    new_accumulated_depreciation: Decimal = Field(..., description="New accumulated depreciation")
    depreciation_adjustment: Decimal = Field(..., description="Depreciation adjustment")
    previous_net_book_value: Decimal = Field(..., description="Previous NBV")
    new_net_book_value: Decimal = Field(..., description="New NBV")
    revaluation_reserve: Decimal = Field(..., description="Revaluation reserve amount")
    
    # Independent valuation
    valuer_name: Optional[str] = Field(None, max_length=200, description="Independent valuer name")
    valuation_report_date: Optional[date] = Field(None, description="Valuation report date")
    valuation_report_ref: Optional[str] = Field(None, max_length=100, description="Valuation report reference")
    
    # Status
    status: str = Field(default="pending", description="Status: pending, approved, completed, cancelled")
    approved_by_id: Optional[int] = Field(None, description="Approved by user ID")
    approved_at: Optional[datetime] = Field(None, description="Approval timestamp")
    
    # GL Integration
    journal_entry_id: Optional[int] = Field(None, description="Created journal entry ID")
    
    notes: Optional[str] = Field(None, max_length=2000, description="Additional notes")


class AssetRevaluationCreate(AssetRevaluationBase):
    """Schema for creating asset revaluations"""
    asset_id: int = Field(..., description="Asset ID")
    new_useful_life_years: Optional[int] = Field(None, ge=0, le=100, description="Revised useful life years")
    new_useful_life_months: Optional[int] = Field(None, ge=0, le=1199, description="Revised useful life months")


class AssetRevaluationUpdate(BaseModel):
    """Schema for updating asset revaluations"""
    description: Optional[str] = Field(None, max_length=2000)
    valuer_name: Optional[str] = Field(None, max_length=200)
    valuation_report_date: Optional[date] = None
    valuation_report_ref: Optional[str] = Field(None, max_length=100)
    notes: Optional[str] = Field(None, max_length=2000)


class AssetRevaluationResponse(AssetRevaluationBase, BaseResponseSchema, CompanyScopedMixin):
    """Schema for asset revaluation responses"""
    asset_id: int
    asset_number: Optional[str] = None
    asset_name: Optional[str] = None
    requested_by_id: int

    model_config = ConfigDict(from_attributes=True)


# ==================== ASSET IMPAIRMENT ====================

class AssetImpairmentBase(BaseModel):
    """Base schema for asset impairments"""
    impairment_number: str = Field(..., min_length=1, max_length=50, description="Impairment number")
    impairment_date: date = Field(..., description="Impairment date")
    description: Optional[str] = Field(None, max_length=2000, description="Description")
    impairment_type: str = Field(default="recognition", description="Type: recognition, reversal")
    
    # Values
    carrying_amount: Decimal = Field(..., description="Carrying amount before impairment")
    recoverable_amount: Decimal = Field(..., description="Recoverable amount (fair value less costs or value in use)")
    impairment_loss: Decimal = Field(..., ge=0, description="Impairment loss amount")
    new_carrying_amount: Decimal = Field(..., description="New carrying amount after impairment")
    
    # Impairment indicators
    impairment_indicators: Optional[List[str]] = Field(None, description="Indicators of impairment")
    
    # Status
    status: str = Field(default="pending", description="Status: pending, approved, completed, cancelled")
    approved_by_id: Optional[int] = Field(None, description="Approved by user ID")
    approved_at: Optional[datetime] = Field(None, description="Approval timestamp")
    
    # GL Integration
    journal_entry_id: Optional[int] = Field(None, description="Created journal entry ID")
    impairment_account_id: int = Field(..., description="Impairment loss account ID")
    
    notes: Optional[str] = Field(None, max_length=2000, description="Additional notes")


class AssetImpairmentCreate(AssetImpairmentBase):
    """Schema for creating asset impairments"""
    asset_id: int = Field(..., description="Asset ID")


class AssetImpairmentUpdate(BaseModel):
    """Schema for updating asset impairments"""
    description: Optional[str] = Field(None, max_length=2000)
    impairment_indicators: Optional[List[str]] = None
    notes: Optional[str] = Field(None, max_length=2000)


class AssetImpairmentResponse(AssetImpairmentBase, BaseResponseSchema, CompanyScopedMixin):
    """Schema for asset impairment responses"""
    asset_id: int
    asset_number: Optional[str] = None
    asset_name: Optional[str] = None
    requested_by_id: int

    model_config = ConfigDict(from_attributes=True)


# ==================== MAINTENANCE RECORD ====================

class AssetMaintenanceBase(BaseModel):
    """Base schema for asset maintenance records"""
    maintenance_number: str = Field(..., min_length=1, max_length=50, description="Maintenance number")
    maintenance_type: MaintenanceType = Field(..., description="Type of maintenance")
    maintenance_date: date = Field(..., description="Maintenance date")
    description: str = Field(..., min_length=1, max_length=2000, description="Maintenance description")
    status: MaintenanceStatus = Field(default=MaintenanceStatus.SCHEDULED, description="Maintenance status")
    
    # Scheduling
    scheduled_date: Optional[date] = Field(None, description="Scheduled date")
    completed_date: Optional[date] = Field(None, description="Completion date")
    
    # Cost
    labor_cost: Decimal = Field(default=Decimal('0'), ge=0, description="Labor cost")
    parts_cost: Decimal = Field(default=Decimal('0'), ge=0, description="Parts/materials cost")
    other_cost: Decimal = Field(default=Decimal('0'), ge=0, description="Other costs")
    total_cost: Decimal = Field(default=Decimal('0'), ge=0, description="Total maintenance cost")
    
    # Vendor/Technician
    vendor_id: Optional[int] = Field(None, description="Maintenance vendor ID")
    technician_name: Optional[str] = Field(None, max_length=200, description="Technician name")
    
    # Additional information
    work_performed: Optional[str] = Field(None, max_length=5000, description="Work performed details")
    parts_replaced: Optional[List[str]] = Field(None, description="Parts replaced")
    next_maintenance_date: Optional[date] = Field(None, description="Next scheduled maintenance")
    meter_reading: Optional[Decimal] = Field(None, description="Meter reading at maintenance")
    
    # Capitalization
    capitalize_cost: bool = Field(default=False, description="Capitalize maintenance cost")
    capitalization_amount: Optional[Decimal] = Field(None, description="Amount to capitalize")
    
    notes: Optional[str] = Field(None, max_length=2000, description="Additional notes")


class AssetMaintenanceCreate(AssetMaintenanceBase):
    """Schema for creating maintenance records"""
    asset_id: int = Field(..., description="Asset ID")


class AssetMaintenanceUpdate(BaseModel):
    """Schema for updating maintenance records"""
    maintenance_type: Optional[MaintenanceType] = None
    maintenance_date: Optional[date] = None
    description: Optional[str] = Field(None, min_length=1, max_length=2000)
    status: Optional[MaintenanceStatus] = None
    scheduled_date: Optional[date] = None
    completed_date: Optional[date] = None
    labor_cost: Optional[Decimal] = Field(None, ge=0)
    parts_cost: Optional[Decimal] = Field(None, ge=0)
    other_cost: Optional[Decimal] = Field(None, ge=0)
    vendor_id: Optional[int] = None
    technician_name: Optional[str] = Field(None, max_length=200)
    work_performed: Optional[str] = Field(None, max_length=5000)
    parts_replaced: Optional[List[str]] = None
    next_maintenance_date: Optional[date] = None
    meter_reading: Optional[Decimal] = None
    capitalize_cost: Optional[bool] = None
    capitalization_amount: Optional[Decimal] = None
    notes: Optional[str] = Field(None, max_length=2000)


class AssetMaintenanceResponse(AssetMaintenanceBase, BaseResponseSchema, CompanyScopedMixin):
    """Schema for maintenance record responses"""
    asset_id: int
    asset_number: Optional[str] = None
    asset_name: Optional[str] = None
    vendor_name: Optional[str] = None

    model_config = ConfigDict(from_attributes=True)


# ==================== INSURANCE ====================

class AssetInsuranceBase(BaseModel):
    """Base schema for asset insurance policies"""
    policy_number: str = Field(..., min_length=1, max_length=50, description="Policy number")
    policy_name: str = Field(..., min_length=1, max_length=200, description="Policy name")
    insurance_company: str = Field(..., min_length=1, max_length=200, description="Insurance company")
    
    # Coverage period
    start_date: date = Field(..., description="Coverage start date")
    end_date: date = Field(..., description="Coverage end date")
    status: InsuranceStatus = Field(default=InsuranceStatus.ACTIVE, description="Policy status")
    
    # Coverage details
    coverage_type: str = Field(default="all_risk", description="Coverage type: all_risk, named_perils, fire_only, etc.")
    insured_value: Decimal = Field(..., ge=0, description="Insured value")
    deductible: Decimal = Field(default=Decimal('0'), ge=0, description="Deductible amount")
    
    # Premium
    premium_amount: Decimal = Field(..., ge=0, description="Premium amount")
    premium_frequency: str = Field(default="annual", description="Premium frequency: annual, semi_annual, quarterly, monthly")
    next_premium_date: Optional[date] = Field(None, description="Next premium due date")
    
    # Beneficiary
    beneficiary: Optional[str] = Field(None, max_length=200, description="Beneficiary")
    
    # Agent/Broker
    agent_name: Optional[str] = Field(None, max_length=200, description="Agent/Broker name")
    agent_contact: Optional[str] = Field(None, max_length=200, description="Agent contact info")
    
    notes: Optional[str] = Field(None, max_length=2000, description="Additional notes")


class AssetInsuranceCreate(AssetInsuranceBase):
    """Schema for creating insurance policies"""
    asset_ids: Optional[List[int]] = Field(None, description="Covered asset IDs")


class AssetInsuranceUpdate(BaseModel):
    """Schema for updating insurance policies"""
    policy_name: Optional[str] = Field(None, min_length=1, max_length=200)
    insurance_company: Optional[str] = Field(None, min_length=1, max_length=200)
    start_date: Optional[date] = None
    end_date: Optional[date] = None
    status: Optional[InsuranceStatus] = None
    coverage_type: Optional[str] = None
    insured_value: Optional[Decimal] = Field(None, ge=0)
    deductible: Optional[Decimal] = Field(None, ge=0)
    premium_amount: Optional[Decimal] = Field(None, ge=0)
    premium_frequency: Optional[str] = None
    next_premium_date: Optional[date] = None
    beneficiary: Optional[str] = Field(None, max_length=200)
    agent_name: Optional[str] = Field(None, max_length=200)
    agent_contact: Optional[str] = Field(None, max_length=200)
    notes: Optional[str] = Field(None, max_length=2000)


class AssetInsuranceResponse(AssetInsuranceBase, BaseResponseSchema, CompanyScopedMixin):
    """Schema for insurance policy responses"""
    covered_assets: List[FixedAssetResponse] = Field(default_factory=list)
    total_insured_value: Decimal = Field(default=Decimal('0'), description="Total insured value of assets")
    days_to_expiry: int = Field(default=0, description="Days until policy expires")

    model_config = ConfigDict(from_attributes=True)


# ==================== FILTER PARAMETERS ====================

class AssetClassFilterParams(PaginationParams):
    """Filter parameters for asset class queries"""
    category: Optional[AssetCategory] = None
    is_active: Optional[bool] = None
    parent_class_id: Optional[int] = None


class AssetLocationFilterParams(PaginationParams):
    """Filter parameters for asset location queries"""
    location_type: Optional[str] = None
    is_active: Optional[bool] = None
    parent_location_id: Optional[int] = None


class FixedAssetFilterParams(PaginationParams):
    """Filter parameters for fixed asset queries"""
    asset_class_id: Optional[int] = None
    category: Optional[AssetCategory] = None
    status: Optional[AssetStatus] = None
    location_id: Optional[int] = None
    department_id: Optional[int] = None
    custodian_id: Optional[int] = None
    vendor_id: Optional[int] = None
    acquisition_date_from: Optional[date] = None
    acquisition_date_to: Optional[date] = None
    cost_from: Optional[Decimal] = None
    cost_to: Optional[Decimal] = None
    search: Optional[str] = None
    is_fully_depreciated: Optional[bool] = None


class DepreciationRunFilterParams(PaginationParams):
    """Filter parameters for depreciation run queries"""
    fiscal_year: Optional[int] = None
    fiscal_period: Optional[int] = None
    status: Optional[str] = None


class AssetTransferFilterParams(PaginationParams):
    """Filter parameters for asset transfer queries"""
    transfer_type: Optional[str] = None
    status: Optional[str] = None
    transfer_date_from: Optional[date] = None
    transfer_date_to: Optional[date] = None


class AssetDisposalFilterParams(PaginationParams):
    """Filter parameters for asset disposal queries"""
    disposal_method: Optional[DisposalMethod] = None
    status: Optional[str] = None
    disposal_date_from: Optional[date] = None
    disposal_date_to: Optional[date] = None


class AssetMaintenanceFilterParams(PaginationParams):
    """Filter parameters for maintenance queries"""
    maintenance_type: Optional[MaintenanceType] = None
    status: Optional[MaintenanceStatus] = None
    maintenance_date_from: Optional[date] = None
    maintenance_date_to: Optional[date] = None


class AssetInsuranceFilterParams(PaginationParams):
    """Filter parameters for insurance queries"""
    status: Optional[InsuranceStatus] = None
    insurance_company: Optional[str] = None
    expiring_within_days: Optional[int] = None


# ==================== LIST RESPONSES ====================

class AssetClassListResponse(ListResponseBase):
    """List response for asset classes"""
    items: List[AssetClassResponse]


class AssetLocationListResponse(ListResponseBase):
    """List response for asset locations"""
    items: List[AssetLocationResponse]


class FixedAssetListResponse(ListResponseBase):
    """List response for fixed assets"""
    items: List[FixedAssetResponse]


class DepreciationScheduleListResponse(ListResponseBase):
    """List response for depreciation schedules"""
    items: List[DepreciationScheduleResponse]


class DepreciationRunListResponse(ListResponseBase):
    """List response for depreciation runs"""
    items: List[DepreciationRunResponse]


class AssetTransferListResponse(ListResponseBase):
    """List response for asset transfers"""
    items: List[AssetTransferResponse]


class AssetDisposalListResponse(ListResponseBase):
    """List response for asset disposals"""
    items: List[AssetDisposalResponse]


class AssetRevaluationListResponse(ListResponseBase):
    """List response for asset revaluations"""
    items: List[AssetRevaluationResponse]


class AssetImpairmentListResponse(ListResponseBase):
    """List response for asset impairments"""
    items: List[AssetImpairmentResponse]


class AssetMaintenanceListResponse(ListResponseBase):
    """List response for maintenance records"""
    items: List[AssetMaintenanceResponse]


class AssetInsuranceListResponse(ListResponseBase):
    """List response for insurance policies"""
    items: List[AssetInsuranceResponse]


# ==================== ANALYTICS RESPONSES ====================

class AssetStatisticsResponse(BaseModel):
    """Asset module statistics"""
    total_assets: int = 0
    active_assets: int = 0
    total_original_cost: Decimal = Decimal('0')
    total_accumulated_depreciation: Decimal = Decimal('0')
    total_net_book_value: Decimal = Decimal('0')
    fully_depreciated_assets: int = 0
    impaired_assets: int = 0
    assets_under_construction: int = 0
    held_for_sale_assets: int = 0
    
    # By category
    assets_by_category: Dict[str, int] = Field(default_factory=dict)
    value_by_category: Dict[str, Decimal] = Field(default_factory=dict)
    
    # By status
    assets_by_status: Dict[str, int] = Field(default_factory=dict)
    
    # By location
    top_locations_by_value: List[Dict[str, Any]] = Field(default_factory=list)
    
    # Depreciation
    depreciation_this_period: Decimal = Decimal('0')
    depreciation_ytd: Decimal = Decimal('0')
    
    # Recent activity
    acquisitions_this_month: int = 0
    disposals_this_month: int = 0
    transfers_this_month: int = 0
    
    # Insurance
    total_insured_value: Decimal = Decimal('0')
    expiring_insurance_policies: int = 0
    
    # Maintenance
    pending_maintenance: int = 0
    overdue_maintenance: int = 0
    maintenance_cost_ytd: Decimal = Decimal('0')


class DepreciationForecastResponse(BaseModel):
    """Depreciation forecast for planning"""
    periods: List[Dict[str, Any]] = Field(default_factory=list)
    total_forecast_depreciation: Decimal = Decimal('0')
    assets_included: int = 0
    forecast_start_date: date
    forecast_end_date: date


class AssetRollforwardResponse(BaseModel):
    """Asset rollforward report data"""
    period_start: date
    period_end: date
    category: Optional[str] = None
    
    beginning_balance: Decimal = Decimal('0')
    additions: Decimal = Decimal('0')
    disposals: Decimal = Decimal('0')
    transfers_in: Decimal = Decimal('0')
    transfers_out: Decimal = Decimal('0')
    revaluations: Decimal = Decimal('0')
    impairments: Decimal = Decimal('0')
    depreciation: Decimal = Decimal('0')
    ending_balance: Decimal = Decimal('0')
    
    details: List[Dict[str, Any]] = Field(default_factory=list)