"""
Point-in-time financial statement tables (spec §12, §44 / docs/DATA_MODEL.md). Never updated in
place — a restatement is a new row with a later `filing_date`, not a mutation of the original.

`financial_periods` is the parent row; each statement table is 1:1 with it via
`financial_period_id`. This split (rather than one wide table) keeps each statement's columns
independently nullable/auditable and mirrors how providers deliver them.
"""
from __future__ import annotations

from datetime import date
from typing import Optional

from sqlalchemy import Date, ForeignKey, String, UniqueConstraint
from sqlalchemy.orm import Mapped, mapped_column, relationship

from app.models.base import Base, TimestampMixin, uuid_pk


class FinancialPeriod(Base, TimestampMixin):
    __tablename__ = "financial_periods"
    __table_args__ = (
        UniqueConstraint("security_id", "period_end", "period_type", "filing_date", name="uq_financial_period"),
    )

    id: Mapped[str] = uuid_pk()
    security_id: Mapped[str] = mapped_column(ForeignKey("securities.id"), index=True)
    period_end: Mapped[date] = mapped_column(Date, index=True)
    period_type: Mapped[str] = mapped_column(String(8))  # FY | Q1 | Q2 | Q3 | Q4 | TTM
    filing_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True, index=True)
    published_at: Mapped[Optional[date]] = mapped_column(Date, nullable=True)
    retrieved_at: Mapped[Optional[date]] = mapped_column(Date, nullable=True)
    currency: Mapped[str] = mapped_column(String(3))
    source_id: Mapped[Optional[str]] = mapped_column(ForeignKey("sources.id"), nullable=True)
    methodology_version: Mapped[str] = mapped_column(String(16), default="v1")

    income_statement: Mapped[Optional["IncomeStatement"]] = relationship(back_populates="period", uselist=False)
    balance_sheet: Mapped[Optional["BalanceSheet"]] = relationship(back_populates="period", uselist=False)
    cash_flow: Mapped[Optional["CashFlow"]] = relationship(back_populates="period", uselist=False)
    shares: Mapped[Optional["Shares"]] = relationship(back_populates="period", uselist=False)


def _fk_period():
    return mapped_column(ForeignKey("financial_periods.id"), unique=True, index=True)


class IncomeStatement(Base, TimestampMixin):
    __tablename__ = "income_statements"

    id: Mapped[str] = uuid_pk()
    financial_period_id: Mapped[str] = _fk_period()

    revenue: Mapped[Optional[float]] = mapped_column(nullable=True)
    cogs: Mapped[Optional[float]] = mapped_column(nullable=True)
    gross_profit: Mapped[Optional[float]] = mapped_column(nullable=True)
    operating_income: Mapped[Optional[float]] = mapped_column(nullable=True)
    ebit: Mapped[Optional[float]] = mapped_column(nullable=True)
    ebitda: Mapped[Optional[float]] = mapped_column(nullable=True)
    net_income: Mapped[Optional[float]] = mapped_column(nullable=True)
    eps_basic: Mapped[Optional[float]] = mapped_column(nullable=True)
    eps_diluted: Mapped[Optional[float]] = mapped_column(nullable=True)
    tax_expense: Mapped[Optional[float]] = mapped_column(nullable=True)
    pretax_income: Mapped[Optional[float]] = mapped_column(nullable=True)
    interest_expense: Mapped[Optional[float]] = mapped_column(nullable=True)
    depreciation_and_amortization: Mapped[Optional[float]] = mapped_column(nullable=True)
    stock_based_compensation: Mapped[Optional[float]] = mapped_column(nullable=True)
    adjusted_net_income: Mapped[Optional[float]] = mapped_column(nullable=True)

    period: Mapped["FinancialPeriod"] = relationship(back_populates="income_statement")


class BalanceSheet(Base, TimestampMixin):
    __tablename__ = "balance_sheets"

    id: Mapped[str] = uuid_pk()
    financial_period_id: Mapped[str] = _fk_period()

    cash_and_equivalents: Mapped[Optional[float]] = mapped_column(nullable=True)
    short_term_investments: Mapped[Optional[float]] = mapped_column(nullable=True)
    total_debt: Mapped[Optional[float]] = mapped_column(nullable=True)
    short_term_debt: Mapped[Optional[float]] = mapped_column(nullable=True)
    long_term_debt: Mapped[Optional[float]] = mapped_column(nullable=True)
    lease_liabilities: Mapped[Optional[float]] = mapped_column(nullable=True)
    total_assets: Mapped[Optional[float]] = mapped_column(nullable=True)
    current_assets: Mapped[Optional[float]] = mapped_column(nullable=True)
    current_liabilities: Mapped[Optional[float]] = mapped_column(nullable=True)
    shareholders_equity: Mapped[Optional[float]] = mapped_column(nullable=True)
    minority_interest: Mapped[Optional[float]] = mapped_column(nullable=True)
    preferred_equity: Mapped[Optional[float]] = mapped_column(nullable=True)
    goodwill: Mapped[Optional[float]] = mapped_column(nullable=True)
    intangible_assets: Mapped[Optional[float]] = mapped_column(nullable=True)
    receivables: Mapped[Optional[float]] = mapped_column(nullable=True)
    inventory: Mapped[Optional[float]] = mapped_column(nullable=True)
    working_capital: Mapped[Optional[float]] = mapped_column(nullable=True)

    period: Mapped["FinancialPeriod"] = relationship(back_populates="balance_sheet")


class CashFlow(Base, TimestampMixin):
    __tablename__ = "cash_flows"

    id: Mapped[str] = uuid_pk()
    financial_period_id: Mapped[str] = _fk_period()

    operating_cash_flow: Mapped[Optional[float]] = mapped_column(nullable=True)
    capital_expenditure: Mapped[Optional[float]] = mapped_column(nullable=True)
    free_cash_flow: Mapped[Optional[float]] = mapped_column(nullable=True)  # cached; recomputed, not authoritative
    dividends_paid: Mapped[Optional[float]] = mapped_column(nullable=True)
    buybacks: Mapped[Optional[float]] = mapped_column(nullable=True)
    stock_issuance: Mapped[Optional[float]] = mapped_column(nullable=True)

    period: Mapped["FinancialPeriod"] = relationship(back_populates="cash_flow")


class Shares(Base, TimestampMixin):
    __tablename__ = "shares"

    id: Mapped[str] = uuid_pk()
    financial_period_id: Mapped[str] = _fk_period()

    shares_outstanding: Mapped[Optional[float]] = mapped_column(nullable=True)
    diluted_shares: Mapped[Optional[float]] = mapped_column(nullable=True)

    period: Mapped["FinancialPeriod"] = relationship(back_populates="shares")


class Dividend(Base, TimestampMixin):
    __tablename__ = "dividends"

    id: Mapped[str] = uuid_pk()
    security_id: Mapped[str] = mapped_column(ForeignKey("securities.id"), index=True)
    ex_date: Mapped[date] = mapped_column(Date, index=True)
    pay_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True)
    amount_per_share: Mapped[float] = mapped_column()
    currency: Mapped[str] = mapped_column(String(3))
    is_special: Mapped[bool] = mapped_column(default=False)
    source_id: Mapped[Optional[str]] = mapped_column(ForeignKey("sources.id"), nullable=True)


class Buyback(Base, TimestampMixin):
    __tablename__ = "buybacks"

    id: Mapped[str] = uuid_pk()
    security_id: Mapped[str] = mapped_column(ForeignKey("securities.id"), index=True)
    period_end: Mapped[date] = mapped_column(Date, index=True)
    gross_amount: Mapped[Optional[float]] = mapped_column(nullable=True)
    shares_repurchased: Mapped[Optional[float]] = mapped_column(nullable=True)
    source_id: Mapped[Optional[str]] = mapped_column(ForeignKey("sources.id"), nullable=True)


class Estimate(Base, TimestampMixin):
    """Forward analyst consensus estimates — always ESTIMATED, never VERIFIED."""

    __tablename__ = "estimates"
    __table_args__ = (UniqueConstraint("security_id", "period_end", "metric", "as_of_date", name="uq_estimate"),)

    id: Mapped[str] = uuid_pk()
    security_id: Mapped[str] = mapped_column(ForeignKey("securities.id"), index=True)
    period_end: Mapped[date] = mapped_column(Date, index=True)
    metric: Mapped[str] = mapped_column(String(32))  # "eps" | "revenue" | ...
    consensus_value: Mapped[Optional[float]] = mapped_column(nullable=True)
    num_analysts: Mapped[Optional[int]] = mapped_column(nullable=True)
    as_of_date: Mapped[date] = mapped_column(Date, index=True)
    source_id: Mapped[Optional[str]] = mapped_column(ForeignKey("sources.id"), nullable=True)


class Guidance(Base, TimestampMixin):
    __tablename__ = "guidance"

    id: Mapped[str] = uuid_pk()
    security_id: Mapped[str] = mapped_column(ForeignKey("securities.id"), index=True)
    period_end: Mapped[date] = mapped_column(Date, index=True)
    metric: Mapped[str] = mapped_column(String(32))
    low: Mapped[Optional[float]] = mapped_column(nullable=True)
    high: Mapped[Optional[float]] = mapped_column(nullable=True)
    issued_date: Mapped[date] = mapped_column(Date, index=True)
    revision_direction: Mapped[Optional[str]] = mapped_column(String(8), nullable=True)  # UP | DOWN | MAINTAINED
    source_id: Mapped[Optional[str]] = mapped_column(ForeignKey("sources.id"), nullable=True)
