from datetime import date, datetime
from decimal import Decimal
from typing import Any

from pydantic import BaseModel, Field

from app.domain.enums import (
    CustomReportField,
    CustomReportMetric,
    CustomReportModule,
    CustomReportSort,
    DeptReportCompareWith,
    DeptReportSort,
    DeptReportView,
    ReportType,
    TxnReportPaymentStatus,
    TxnReportReferenceType,
    TxnReportTrendGranularity,
    TxnReportType,
)


class ReportLineItem(BaseModel):
    account_id: str | None = None
    account_code: str
    account_name: str
    account_type: str | None = None
    debit: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    credit: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    balance: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    metadata: dict[str, Any] = Field(default_factory=dict)


class FinancialReport(BaseModel):
    id: str | None = None
    company_id: str
    report_type: ReportType
    report_title: str
    from_date: date | None = None
    to_date: date | None = None
    report_date: date
    account_id: str | None = None
    account_code: str | None = None
    line_items: list[ReportLineItem] = Field(default_factory=list)
    totals: dict[str, Decimal] = Field(default_factory=dict)
    generated_at: datetime = Field(default_factory=datetime.utcnow)
    parameters: dict[str, Any] = Field(default_factory=dict)

    model_config = {"from_attributes": True}


class TxnReportKpi(BaseModel):
    current: Decimal = Field(default=Decimal("0"))
    previous: Decimal = Field(default=Decimal("0"))
    change_percent: Decimal | None = None


class TxnReportRow(BaseModel):
    id: str
    txn_date: date
    txn_at: datetime | None = None
    transaction_type: TxnReportType
    reference_no: str
    reference_type: TxnReportReferenceType
    party_id: str | None = None
    party_name: str | None = None
    warehouse_id: str | None = None
    warehouse_name: str | None = None
    total_amount: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    paid_amount: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    due_amount: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    payment_status: TxnReportPaymentStatus
    created_by_id: str | None = None
    created_by_name: str | None = None


class TxnReportTrendPoint(BaseModel):
    date: date
    total_amount: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    count: int = 0


class TxnReportSlice(BaseModel):
    key: str
    label: str
    count: int = 0
    total_amount: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    percent_of_total: Decimal = Field(default=Decimal("0.00"), decimal_places=2)


class TransactionReport(BaseModel):
    from_date: date
    to_date: date
    previous_from_date: date
    previous_to_date: date
    trend_granularity: TxnReportTrendGranularity = TxnReportTrendGranularity.DAILY
    total_transactions: TxnReportKpi
    total_amount: TxnReportKpi
    total_received: TxnReportKpi
    total_paid: TxnReportKpi
    pending_amount: TxnReportKpi
    rows: list[TxnReportRow] = Field(default_factory=list)
    rows_total: int = 0
    page: int = 1
    page_size: int = 10
    total_pages: int = 1
    trend: list[TxnReportTrendPoint] = Field(default_factory=list)
    by_type: list[TxnReportSlice] = Field(default_factory=list)
    by_payment_status: list[TxnReportSlice] = Field(default_factory=list)


class DeptReportRow(BaseModel):
    department_id: str
    department_code: str | None = None
    department_name: str
    transactions_count: int = 0
    issued_amount: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    received_amount: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    net_value: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    total_value: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    percent_of_total: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    change_percent: Decimal | None = None


class DeptReportDetailRow(BaseModel):
    id: str
    txn_date: date
    direction: str
    reference_no: str
    department_id: str
    department_code: str | None = None
    department_name: str
    warehouse_id: str | None = None
    warehouse_name: str | None = None
    amount: Decimal = Field(default=Decimal("0.00"), decimal_places=2)


class DeptReportComboPoint(BaseModel):
    department_id: str
    department_name: str
    transactions_count: int = 0
    total_amount: Decimal = Field(default=Decimal("0.00"), decimal_places=2)


class DeptReportIssuedReceived(BaseModel):
    department_id: str
    department_name: str
    issued_amount: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    received_amount: Decimal = Field(default=Decimal("0.00"), decimal_places=2)


class DepartmentReport(BaseModel):
    from_date: date
    to_date: date
    previous_from_date: date
    previous_to_date: date
    report_view: DeptReportView = DeptReportView.SUMMARY
    compare_with: DeptReportCompareWith = DeptReportCompareWith.PREVIOUS_PERIOD
    total_departments: TxnReportKpi
    total_transactions: TxnReportKpi
    total_value: TxnReportKpi
    total_issued: TxnReportKpi
    total_received: TxnReportKpi
    rows: list[DeptReportRow] = Field(default_factory=list)
    details: list[DeptReportDetailRow] = Field(default_factory=list)
    rows_total: int = 0
    page: int = 1
    page_size: int = 8
    total_pages: int = 1
    top_by_value: list[TxnReportSlice] = Field(default_factory=list)
    by_department: list[DeptReportComboPoint] = Field(default_factory=list)
    issued_vs_received: list[DeptReportIssuedReceived] = Field(default_factory=list)
    contribution: list[TxnReportSlice] = Field(default_factory=list)


class CustomReportConfig(BaseModel):
    module: CustomReportModule = CustomReportModule.TRANSACTIONS
    fields: list[CustomReportField] = Field(default_factory=list)
    metrics: list[CustomReportMetric] = Field(default_factory=list)
    from_date: date | None = None
    to_date: date | None = None
    transaction_types: list[TxnReportType] = Field(default_factory=list)
    warehouse_id: str | None = None
    department_id: str | None = None
    payment_status: TxnReportPaymentStatus | None = None
    party: str | None = None
    group_by: CustomReportField = CustomReportField.TRANSACTION_TYPE
    then_by: CustomReportField | None = None
    sort_by: CustomReportSort = CustomReportSort.TOTAL_AMOUNT
    sort_dir: str = "desc"


class CustomReport(BaseModel):
    id: str | None = None
    company_id: str
    name: str
    module: CustomReportModule = CustomReportModule.TRANSACTIONS
    description: str | None = None
    configuration: CustomReportConfig
    is_template: bool = False
    created_by: str | None = None
    created_at: datetime = Field(default_factory=datetime.utcnow)
    updated_at: datetime = Field(default_factory=datetime.utcnow)

    model_config = {"from_attributes": True}


class CustomReportResultRow(BaseModel):
    group_key: str
    group_label: str
    then_key: str | None = None
    then_label: str | None = None
    total_transactions: int = 0
    total_quantity: Decimal = Field(default=Decimal("0.0000"), decimal_places=4)
    total_amount: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    avg_amount: Decimal = Field(default=Decimal("0.00"), decimal_places=2)


class CustomReportTotals(BaseModel):
    total_transactions: int = 0
    total_quantity: Decimal = Field(default=Decimal("0.0000"), decimal_places=4)
    total_amount: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    avg_amount: Decimal = Field(default=Decimal("0.00"), decimal_places=2)


class CustomReportResult(BaseModel):
    module: CustomReportModule = CustomReportModule.TRANSACTIONS
    configuration: CustomReportConfig
    rows: list[CustomReportResultRow] = Field(default_factory=list)
    totals: CustomReportTotals = Field(default_factory=CustomReportTotals)
    rows_total: int = 0
    page: int = 1
    page_size: int = 50
    total_pages: int = 1
    trend: list[TxnReportTrendPoint] = Field(default_factory=list)
    top_parties: list[TxnReportSlice] = Field(default_factory=list)
    by_type: list[TxnReportSlice] = Field(default_factory=list)
    by_payment_status: list[TxnReportSlice] = Field(default_factory=list)
