"""Pydantic schemas for receipts API."""

import json
from datetime import datetime, date
from decimal import Decimal
from typing import Optional, List, Any, Union
from pydantic import BaseModel, Field, ConfigDict, field_validator

from backend.modules.data_entry.db.models.receipt import ReceiptType, ReceiptDirection, ReceiptStatus, ProcessingStatus
from backend.modules.data_entry.db.models.accounting_entry import EntryType


# ============ Accounting Entry Schemas ============

class AccountingEntryBase(BaseModel):
    """Base schema for accounting entry."""
    entry_type: EntryType
    account_code: str = Field(max_length=20)
    account_name: Optional[str] = Field(default=None, max_length=200)
    amount: Decimal
    partner_id: Optional[int] = None
    cost_center_id: Optional[int] = None


class AccountingEntryCreate(AccountingEntryBase):
    """Schema for creating an accounting entry."""
    pass


class AccountingEntryUpdate(BaseModel):
    """Schema for updating an accounting entry."""
    entry_type: Optional[EntryType] = None
    account_code: Optional[str] = Field(default=None, max_length=20)
    account_name: Optional[str] = Field(default=None, max_length=200)
    amount: Optional[Decimal] = None
    partner_id: Optional[int] = None
    cost_center_id: Optional[int] = None


class AccountingEntryResponse(AccountingEntryBase):
    """Schema for accounting entry response."""
    model_config = ConfigDict(from_attributes=True)

    id: int
    receipt_id: int
    is_auto_generated: bool
    modified_by: Optional[str] = None
    modified_at: Optional[datetime] = None
    sort_order: int


# ============ Attachment Schemas ============

class AttachmentResponse(BaseModel):
    """Schema for attachment response."""
    model_config = ConfigDict(from_attributes=True)

    id: int
    receipt_id: int
    filename: str
    stored_filename: str
    file_path: str
    file_size: int
    mime_type: str
    uploaded_at: datetime


# ============ TVA Schema ============

class TvaEntrySchema(BaseModel):
    """Single TVA entry with code, percentage and amount."""
    code: Optional[str] = Field(default=None, description="TVA code: A, B, C, D")
    percent: int = Field(description="TVA percentage: 0, 5, 9, 19, 21")
    amount: Decimal = Field(description="TVA amount for this rate")


class PaymentMethodSchema(BaseModel):
    """Payment method entry (CARD/NUMERAR)."""
    method: str = Field(description="Payment method: CARD or NUMERAR")
    amount: Decimal = Field(description="Amount paid with this method")


# ============ Receipt Schemas ============

class ReceiptBase(BaseModel):
    """Base schema for receipt."""
    receipt_type: ReceiptType = ReceiptType.BON_FISCAL
    direction: ReceiptDirection = ReceiptDirection.CHELTUIALA
    receipt_number: Optional[str] = Field(default=None, max_length=50)
    receipt_series: Optional[str] = Field(default=None, max_length=20)
    receipt_date: date
    amount: Decimal = Field(gt=0)
    description: Optional[str] = Field(default=None, max_length=500)
    # TVA info (multiple entries support)
    tva_breakdown: Optional[List[TvaEntrySchema]] = Field(default=None, description="List of TVA entries")
    tva_total: Optional[Decimal] = Field(default=None, description="Total TVA amount")
    items_count: Optional[int] = Field(default=None, description="Number of items")
    vendor_address: Optional[str] = Field(default=None, max_length=500, description="Vendor address")
    # Other fields
    expense_type_code: Optional[str] = Field(default=None, max_length=20)
    company_id: int
    # partner_id removed - supplier data is text-only (partner_name, cui)
    partner_name: Optional[str] = Field(default=None, max_length=200)
    cui: Optional[str] = Field(default=None, max_length=20, description="Fiscal code (CUI) from OCR")
    ocr_raw_text: Optional[str] = Field(default=None, description="Raw OCR text for debugging")
    payment_methods: Optional[List[PaymentMethodSchema]] = Field(default=None, description="Payment methods from OCR")
    cash_register_id: Optional[int] = None
    cash_register_name: Optional[str] = Field(default=None, max_length=100)
    cash_register_account: Optional[str] = Field(default=None, max_length=20)
    payment_mode: Optional[str] = Field(default=None, description="Payment mode: casa/banca/avans_decontare")


class ReceiptCreate(ReceiptBase):
    """Schema for creating a receipt."""
    pass


class ReceiptUpdate(BaseModel):
    """Schema for updating a receipt (DRAFT only)."""
    receipt_type: Optional[ReceiptType] = None
    direction: Optional[ReceiptDirection] = None
    receipt_number: Optional[str] = Field(default=None, max_length=50)
    receipt_series: Optional[str] = Field(default=None, max_length=20)
    receipt_date: Optional[date] = None
    amount: Optional[Decimal] = Field(default=None, gt=0)
    description: Optional[str] = Field(default=None, max_length=500)
    # TVA info (multiple entries support)
    tva_breakdown: Optional[List[TvaEntrySchema]] = Field(default=None, description="List of TVA entries")
    tva_total: Optional[Decimal] = Field(default=None, description="Total TVA amount")
    items_count: Optional[int] = Field(default=None, description="Number of items")
    vendor_address: Optional[str] = Field(default=None, max_length=500, description="Vendor address")
    # Other fields
    expense_type_code: Optional[str] = Field(default=None, max_length=20)
    # partner_id removed - supplier data is text-only (partner_name, cui)
    partner_name: Optional[str] = Field(default=None, max_length=200)
    cui: Optional[str] = Field(default=None, max_length=20, description="Fiscal code (CUI) from OCR")
    ocr_raw_text: Optional[str] = Field(default=None, description="Raw OCR text for debugging")
    payment_methods: Optional[List[PaymentMethodSchema]] = Field(default=None, description="Payment methods from OCR")
    cash_register_id: Optional[int] = None
    cash_register_name: Optional[str] = Field(default=None, max_length=100)
    cash_register_account: Optional[str] = Field(default=None, max_length=20)
    payment_mode: Optional[str] = Field(default=None, description="Payment mode: casa/banca/avans_decontare")


class ReceiptResponse(ReceiptBase):
    """Schema for receipt response with all fields."""
    model_config = ConfigDict(from_attributes=True)

    id: int
    # Override amount to allow zero values in response (validation is on input, not output)
    amount: Decimal
    status: ReceiptStatus
    created_by: str
    created_at: datetime
    updated_at: datetime
    submitted_at: Optional[datetime] = None
    reviewed_by: Optional[str] = None
    reviewed_at: Optional[datetime] = None
    rejection_reason: Optional[str] = None
    oracle_synced_at: Optional[datetime] = None
    oracle_act_id: Optional[int] = None
    oracle_error: Optional[str] = None

    # Bulk upload batch tracking (US-012)
    batch_id: Optional[str] = None
    processing_status: Optional[str] = None
    processing_error: Optional[str] = None
    file_hash: Optional[str] = None
    processing_started_at: Optional[datetime] = None
    processing_completed_at: Optional[datetime] = None

    # Relationships (optional, loaded when needed)
    attachments: List[AttachmentResponse] = []
    entries: List[AccountingEntryResponse] = []

    @field_validator('tva_breakdown', mode='before')
    @classmethod
    def parse_tva_breakdown(cls, v: Any) -> Optional[List[dict]]:
        """Deserialize tva_breakdown from JSON string if needed."""
        if v is None:
            return None
        if isinstance(v, str):
            try:
                return json.loads(v)
            except (json.JSONDecodeError, TypeError):
                return None
        if isinstance(v, list):
            return v
        return None

    @field_validator('payment_methods', mode='before')
    @classmethod
    def parse_payment_methods(cls, v: Any) -> Optional[List[dict]]:
        """Deserialize payment_methods from JSON string if needed."""
        if v is None:
            return None
        if isinstance(v, str):
            try:
                return json.loads(v)
            except (json.JSONDecodeError, TypeError):
                return None
        if isinstance(v, list):
            return v
        return None


class ProcessingStats(BaseModel):
    """Statistics for bulk upload processing status (US-012)."""
    pending_count: int = 0
    processing_count: int = 0
    completed_count: int = 0
    failed_count: int = 0


class ReceiptListResponse(BaseModel):
    """Schema for paginated receipt list response."""
    items: List[ReceiptResponse]
    total: int
    page: int
    page_size: int
    pages: int
    # Processing stats for bulk upload filtering (US-012)
    processing_stats: Optional[ProcessingStats] = None


class ReceiptFilter(BaseModel):
    """Schema for filtering receipts."""
    status: Optional[ReceiptStatus] = None
    direction: Optional[ReceiptDirection] = None
    company_id: Optional[int] = None
    created_by: Optional[str] = None
    date_from: Optional[date] = None
    date_to: Optional[date] = None
    search: Optional[str] = None  # Search in description, partner_name
    # Bulk upload filters (US-012)
    processing_status: Optional[str] = None  # ProcessingStatus enum value
    batch_id: Optional[str] = None  # Filter by batch_id
    sort_by: Optional[str] = None  # Sort field (e.g., "processing_started_at")
    # Pagination
    page: int = Field(default=1, ge=1)
    page_size: int = Field(default=20, ge=1, le=100)


# ============ Workflow Schemas ============

class WorkflowAction(BaseModel):
    """Schema for workflow action response."""
    success: bool
    message: str
    receipt: Optional[ReceiptResponse] = None


class RejectRequest(BaseModel):
    """Schema for rejection request."""
    reason: str = Field(min_length=5, max_length=500)


class EntriesUpdateRequest(BaseModel):
    """Schema for bulk updating accounting entries."""
    entries: List[AccountingEntryCreate]


# ============ Nomenclature Schemas ============

class PartnerOption(BaseModel):
    """Schema for partner dropdown option (used for autocomplete assistance)."""
    name: str
    fiscal_code: Optional[str] = None
    address: Optional[str] = None
    source: str = "oracle"  # 'oracle' (synced) or 'local'


class AccountOption(BaseModel):
    """Schema for account dropdown option."""
    code: str
    name: str


class CashRegisterOption(BaseModel):
    """Schema for cash register dropdown option."""
    id: int
    name: str
    account_code: str  # 5311, 5121, etc.


class ExpenseTypeOption(BaseModel):
    """Schema for expense type dropdown option."""
    code: str
    name: str
    account_code: str
    has_vat: bool
    vat_percent: Decimal = Decimal("19")


# ============ Bulk Delete Schemas (US-024) ============

class BulkDeleteRequest(BaseModel):
    """Request schema for bulk delete endpoint."""
    ids: List[int] = Field(..., min_length=1, description="List of receipt IDs to delete")


class BulkDeleteFailure(BaseModel):
    """Schema for a single failed deletion."""
    id: int
    error: str


class BulkDeleteResponse(BaseModel):
    """Response schema for bulk delete with partial success support."""
    deleted: List[int] = Field(default_factory=list, description="IDs of successfully deleted receipts")
    failed: List[BulkDeleteFailure] = Field(default_factory=list, description="IDs that failed with error messages")
