"""
IFRS-Compliant Financial Statement Schemas
Comprehensive schemas for all financial statements according to IFRS standards
"""

from typing import List, Dict, Optional, Any, Union
from pydantic import BaseModel, Field, field_validator
from datetime import date, datetime
from decimal import Decimal
from enum import Enum


class ReportPeriodType(str, Enum):
    """Report period types"""
    MONTHLY = "monthly"
    QUARTERLY = "quarterly"
    ANNUALLY = "annually"
    CUSTOM = "custom"


class CurrencyCode(str, Enum):
    """Supported currency codes"""
    BWP = "BWP"  # Botswana Pula
    USD = "USD"  # US Dollar
    EUR = "EUR"  # Euro
    GBP = "GBP"  # British Pound
    ZAR = "ZAR"  # South African Rand


class IFRSStandard(str, Enum):
    """IFRS Standards referenced in reports"""
    IAS_1 = "IAS 1 - Presentation of Financial Statements"
    IAS_7 = "IAS 7 - Statement of Cash Flows"
    IFRS_9 = "IFRS 9 - Financial Instruments"
    IFRS_15 = "IFRS 15 - Revenue from Contracts with Customers"
    IFRS_16 = "IFRS 16 - Leases"


class ReportMetadata(BaseModel):
    """Common metadata for all financial reports"""
    report_id: str = Field(..., description="Unique report identifier")
    report_type: str = Field(..., description="Type of financial report")
    company_name: str = Field(..., description="Company name")
    reporting_date: date = Field(..., description="Report date")
    period_start: date = Field(..., description="Period start date")
    period_end: date = Field(..., description="Period end date")
    period_type: ReportPeriodType = Field(..., description="Period type")

    # Currency and compliance
    presentation_currency: CurrencyCode = Field(CurrencyCode.BWP, description="Presentation currency")
    functional_currency: CurrencyCode = Field(CurrencyCode.BWP, description="Functional currency")
    ifrs_standards: List[IFRSStandard] = Field(..., description="Applicable IFRS standards")

    # Preparation details
    prepared_by: str = Field(..., description="Report prepared by")
    prepared_at: datetime = Field(..., description="Preparation timestamp")
    reviewed_by: Optional[str] = Field(None, description="Report reviewed by")
    reviewed_at: Optional[datetime] = Field(None, description="Review timestamp")
    approved_by: Optional[str] = Field(None, description="Report approved by")
    approved_at: Optional[datetime] = Field(None, description="Approval timestamp")

    # Status and version
    status: str = Field("draft", description="Report status")
    version: str = Field("1.0", description="Report version")
    notes: Optional[str] = Field(None, description="Report notes")


class AccountLineItem(BaseModel):
    """Individual account line item in financial statements"""
    account_code: str = Field(..., description="Account code")
    account_name: str = Field(..., description="Account name")
    account_type: str = Field(..., description="Account type")
    ifrs_category: str = Field(..., description="IFRS category")
    cash_flow_group: Optional[str] = Field(None, description="Cash flow grouping such as Revenue Collections, Operating Payments, Financing Sources")
    flow_direction: Optional[str] = Field(None, description="Inflow or Outflow based on sign of cash movement")
    current_period: Decimal = Field(..., description="Current period amount")
    prior_period: Optional[Decimal] = Field(None, description="Prior period amount")
    variance: Optional[Decimal] = Field(None, description="Variance amount")
    variance_percentage: Optional[Decimal] = Field(None, description="Variance percentage")
    notes: Optional[str] = Field(None, description="Line item notes")


class FinancialStatementSection(BaseModel):
    """Section within a financial statement"""
    section_name: str = Field(..., description="Section name")
    section_code: str = Field(..., description="Section code")
    line_items: List[AccountLineItem] = Field(..., description="Line items in section")
    subtotal: Decimal = Field(..., description="Section subtotal")
    notes: Optional[str] = Field(None, description="Section notes")


# Balance Sheet (Statement of Financial Position) - IAS 1
class BalanceSheetAssets(BaseModel):
    """Balance sheet assets section"""
    current_assets: FinancialStatementSection = Field(..., description="Current assets")
    non_current_assets: FinancialStatementSection = Field(..., description="Non-current assets")
    total_assets: Decimal = Field(..., description="Total assets")


class BalanceSheetLiabilitiesAndEquity(BaseModel):
    """Balance sheet liabilities and equity section"""
    current_liabilities: FinancialStatementSection = Field(..., description="Current liabilities")
    non_current_liabilities: FinancialStatementSection = Field(..., description="Non-current liabilities")
    total_liabilities: Decimal = Field(..., description="Total liabilities")
    equity: FinancialStatementSection = Field(..., description="Equity")
    total_equity: Decimal = Field(..., description="Total equity")
    total_liabilities_and_equity: Decimal = Field(..., description="Total liabilities and equity")


class BalanceSheet(BaseModel):
    """IFRS-compliant Balance Sheet (Statement of Financial Position)"""
    metadata: ReportMetadata = Field(..., description="Report metadata")
    assets: BalanceSheetAssets = Field(..., description="Assets section")
    liabilities_and_equity: BalanceSheetLiabilitiesAndEquity = Field(..., description="Liabilities and equity")

    @field_validator('liabilities_and_equity')
    @classmethod
    def validate_balance_sheet_equation(cls, v, info):
        """Validate that Assets = Liabilities + Equity"""
        if hasattr(info, 'data') and 'assets' in info.data:
            assets_total = info.data['assets'].total_assets
            liab_equity_total = v.total_liabilities_and_equity
            difference = abs(assets_total - liab_equity_total)

            # Allow small rounding differences (up to 1 cent per thousand in assets)
            tolerance = max(Decimal('0.01'), assets_total * Decimal('0.000001'))

            if difference > tolerance:
                # Log detailed warning with the specific imbalance
                print(f"WARNING: Balance sheet imbalance detected:")
                print(f"  Assets: {assets_total}")
                print(f"  Liabilities + Equity: {liab_equity_total}")
                print(f"  Difference: {difference}")
                print(f"  This may indicate data entry errors or incomplete transactions.")

                # For production systems, consider:
                # - Raising ValidationError if difference is large
                # - Triggering alerts to accounting team
                # - Preventing report generation until resolved
                # raise ValueError(f"Balance sheet does not balance. Difference: {difference}")

        return v


# Income Statement (Statement of Profit or Loss) - IAS 1
class IncomeStatementRevenue(BaseModel):
    """Income statement revenue section"""
    operating_revenue: FinancialStatementSection = Field(..., description="Operating revenue")
    other_revenue: FinancialStatementSection = Field(..., description="Other revenue")
    total_revenue: Decimal = Field(..., description="Total revenue")


class IncomeStatementExpenses(BaseModel):
    """Income statement expenses section"""
    cost_of_sales: FinancialStatementSection = Field(..., description="Cost of sales")
    operating_expenses: FinancialStatementSection = Field(..., description="Operating expenses")
    finance_costs: FinancialStatementSection = Field(..., description="Finance costs")
    other_expenses: FinancialStatementSection = Field(..., description="Other expenses")
    total_expenses: Decimal = Field(..., description="Total expenses")


class IncomeStatement(BaseModel):
    """IFRS-compliant Income Statement (Statement of Profit or Loss)"""
    metadata: ReportMetadata = Field(..., description="Report metadata")
    revenue: IncomeStatementRevenue = Field(..., description="Revenue section")
    expenses: IncomeStatementExpenses = Field(..., description="Expenses section")

    # Calculated fields
    gross_profit: Decimal = Field(..., description="Gross profit")
    operating_profit: Decimal = Field(..., description="Operating profit")
    profit_before_tax: Decimal = Field(..., description="Profit before tax")
    tax_expense: Decimal = Field(..., description="Tax expense")
    profit_after_tax: Decimal = Field(..., description="Profit after tax")

    # Per share information (if applicable)
    basic_earnings_per_share: Optional[Decimal] = Field(None, description="Basic earnings per share")
    diluted_earnings_per_share: Optional[Decimal] = Field(None, description="Diluted earnings per share")


# Cash Flow Statement - IAS 7
class CashFlowActivity(BaseModel):
    """Cash flow activity section"""
    line_items: List[AccountLineItem] = Field(..., description="Cash flow line items")
    net_cash_flow: Decimal = Field(..., description="Net cash flow from activity")
    inflows_total: Decimal = Field(Decimal('0.00'), description="Total gross cash inflows")
    outflows_total: Decimal = Field(Decimal('0.00'), description="Total gross cash outflows")


class CashFlowStatement(BaseModel):
    """IFRS-compliant Cash Flow Statement"""
    metadata: ReportMetadata = Field(..., description="Report metadata")

    # Cash flow activities
    operating_activities: CashFlowActivity = Field(..., description="Operating activities")
    investing_activities: CashFlowActivity = Field(..., description="Investing activities")
    financing_activities: CashFlowActivity = Field(..., description="Financing activities")

    # Summary
    net_increase_in_cash: Decimal = Field(..., description="Net increase in cash")
    cash_at_beginning: Decimal = Field(..., description="Cash at beginning of period")
    cash_at_end: Decimal = Field(..., description="Cash at end of period")

    @field_validator('cash_at_end')
    @classmethod
    def validate_cash_reconciliation(cls, v, info):
        """Validate cash reconciliation"""
        if hasattr(info, 'data') and all(key in info.data for key in ['net_increase_in_cash', 'cash_at_beginning']):
            calculated_end = info.data['cash_at_beginning'] + info.data['net_increase_in_cash']
            if abs(v - calculated_end) > Decimal('0.01'):
                raise ValueError(f"Cash reconciliation error: {v} != {calculated_end}")
        return v


# Statement of Changes in Equity - IAS 1
class EquityMovement(BaseModel):
    """Equity movement for a specific component"""
    component_name: str = Field(..., description="Equity component name")
    opening_balance: Decimal = Field(..., description="Opening balance")
    profit_loss: Decimal = Field(..., description="Profit or loss")
    other_comprehensive_income: Decimal = Field(..., description="Other comprehensive income")
    transactions_with_owners: Decimal = Field(..., description="Transactions with owners")
    net_movement: Decimal = Field(..., description="Net movement for the period")
    closing_balance: Decimal = Field(..., description="Closing balance")


class StatementOfChangesInEquity(BaseModel):
    """IFRS-compliant Statement of Changes in Equity"""
    metadata: ReportMetadata = Field(..., description="Report metadata")
    equity_movements: List[EquityMovement] = Field(..., description="Equity movements")
    total_equity_opening: Decimal = Field(..., description="Total equity opening")
    total_profit_loss: Decimal = Field(..., description="Total profit or loss allocated to equity")
    total_other_comprehensive_income: Decimal = Field(..., description="Total other comprehensive income")
    total_transactions_with_owners: Decimal = Field(..., description="Total transactions with owners (dividends/issues)")
    total_equity_closing: Decimal = Field(..., description="Total equity closing")


# Trial Balance
class TrialBalanceAccount(BaseModel):
    """Trial balance account entry"""
    account_code: str = Field(..., description="Account code")
    account_name: str = Field(..., description="Account name")
    account_type: str = Field(..., description="Account type")
    debit_balance: Decimal = Field(..., description="Debit balance")
    credit_balance: Decimal = Field(..., description="Credit balance")
    net_balance: Decimal = Field(..., description="Net balance")


class TrialBalance(BaseModel):
    """IFRS-compliant Trial Balance"""
    metadata: ReportMetadata = Field(..., description="Report metadata")
    accounts: List[TrialBalanceAccount] = Field(..., description="Trial balance accounts")
    total_debits: Decimal = Field(..., description="Total debits")
    total_credits: Decimal = Field(..., description="Total credits")

    @field_validator('total_credits')
    @classmethod
    def validate_trial_balance(cls, v, info):
        """Validate that total debits equal total credits"""
        if hasattr(info, 'data') and 'total_debits' in info.data:
            if abs(info.data['total_debits'] - v) > Decimal('0.01'):
                # Log warning but don't raise error for unbalanced trial balance
                import logging
                logger = logging.getLogger(__name__)
                logger.warning(f"Trial balance does not balance: Debits {info.data['total_debits']} != Credits {v}")
        return v


# Aging Reports
class AgingBucket(BaseModel):
    """Aging bucket for debtors/creditors aging"""
    bucket_name: str = Field(..., description="Bucket name (e.g., '0-30 days')")
    amount: Decimal = Field(..., description="Amount in bucket")
    percentage: Decimal = Field(..., description="Percentage of total")


class AgingReportEntry(BaseModel):
    """Individual entry in aging report"""
    entity_id: str = Field(..., description="Customer/Supplier ID")
    entity_name: str = Field(..., description="Customer/Supplier name")
    total_amount: Decimal = Field(..., description="Total outstanding amount")
    aging_buckets: List[AgingBucket] = Field(..., description="Aging buckets")
    last_transaction_date: Optional[date] = Field(None, description="Last transaction date")


class AgingReport(BaseModel):
    """Debtors/Creditors Aging Report"""
    metadata: ReportMetadata = Field(..., description="Report metadata")
    report_subtype: str = Field(..., description="debtors or creditors")
    entries: List[AgingReportEntry] = Field(..., description="Aging entries")
    summary_buckets: List[AgingBucket] = Field(..., description="Summary aging buckets")
    total_outstanding: Decimal = Field(..., description="Total outstanding amount")


# Comprehensive Financial Report Package
class FinancialReportPackage(BaseModel):
    """Complete set of IFRS financial statements"""
    metadata: ReportMetadata = Field(..., description="Package metadata")
    balance_sheet: BalanceSheet = Field(..., description="Balance sheet")
    income_statement: IncomeStatement = Field(..., description="Income statement")
    cash_flow_statement: CashFlowStatement = Field(..., description="Cash flow statement")
    changes_in_equity: StatementOfChangesInEquity = Field(..., description="Changes in equity")
    trial_balance: TrialBalance = Field(..., description="Trial balance")
    debtors_aging: AgingReport = Field(..., description="Debtors aging")
    creditors_aging: AgingReport = Field(..., description="Creditors aging")

    # Additional analysis
    financial_ratios: Optional[Dict[str, Decimal]] = Field(None, description="Financial ratios")
    notes_to_statements: Optional[List[str]] = Field(None, description="Notes to financial statements")


# Export formats
class ExportFormat(str, Enum):
    """Export format options"""
    PDF = "pdf"
    EXCEL = "excel"
    CSV = "csv"
    JSON = "json"


class ReportExportRequest(BaseModel):
    """Request for exporting financial reports"""
    report_type: str = Field(..., description="Type of report to export")
    format: ExportFormat = Field(..., description="Export format")
    include_logo: bool = Field(True, description="Include company logo")
    include_watermark: bool = Field(True, description="Include watermark")
    watermark_text: Optional[str] = Field(None, description="Custom watermark text")
    include_notes: bool = Field(True, description="Include notes")
    detailed_view: bool = Field(False, description="Include detailed view")


# API Response schemas
class FinancialReportResponse(BaseModel):
    """Standard response for financial report APIs"""
    success: bool = Field(..., description="Request success status")
    data: Union[BalanceSheet, IncomeStatement, CashFlowStatement, StatementOfChangesInEquity, TrialBalance, AgingReport, FinancialReportPackage] = Field(..., description="Report data")
    metadata: ReportMetadata = Field(..., description="Report metadata")
    ifrs_standards: List[IFRSStandard] = Field(..., description="Applicable IFRS standards")
    generated_at: datetime = Field(..., description="Generation timestamp")
    errors: Optional[List[str]] = Field(None, description="Any errors encountered")
    warnings: Optional[List[str]] = Field(None, description="Any warnings")
