from __future__ import annotations

from typing import Literal

from pydantic import BaseModel, ConfigDict, Field


class PerformanceQuality(BaseModel):
    model_config = ConfigDict(extra="forbid")

    status: Literal["complete", "partial", "unavailable"]
    reason_codes: list[str]
    coverage_from: str | None = None
    coverage_to: str | None = None


class PerformanceQualitySet(BaseModel):
    overall: PerformanceQuality
    ttwror: PerformanceQuality
    xirr: PerformanceQuality
    twr: PerformanceQuality
    mwr: PerformanceQuality
    cost_basis: PerformanceQuality
    pnl: PerformanceQuality


class PerformancePeriod(BaseModel):
    model_config = ConfigDict(extra="forbid", populate_by_name=True)

    from_: str = Field(alias="from")
    to: str


class PerformanceScope(BaseModel):
    model_config = ConfigDict(extra="forbid")

    kind: Literal["portfolio", "account"]
    account_id: str | None = None


class PerformanceSummary(BaseModel):
    model_config = ConfigDict(extra="forbid")

    opening_value: str | None
    closing_value: str | None
    net_external_cashflows: str | None
    fees: str | None
    taxes: str | None
    ttwror_cumulative: str | None
    ttwror_annualized: str | None
    xirr_annualized: str | None
    investment_result: str | None
    twr: str | None
    mwr: str | None
    realized_pnl: str | None
    unrealized_pnl: str | None
    remaining_cost_basis: str | None


class PerformancePoint(BaseModel):
    at: str
    value: str


class PerformanceCashflow(BaseModel):
    at: str
    kind: Literal["external_deposit", "external_withdrawal"]
    amount: str


class PerformanceAttribution(BaseModel):
    model_config = ConfigDict(extra="forbid")

    market_price: str | None
    fx: str | None
    dividends_and_interest: str | None
    fees: str | None
    taxes: str | None
    other_effects: str | None
    unattributed_residual: str | None
    investment_result: str | None
    tolerance_chf: str
    status: Literal["complete", "partial", "unavailable"]
    reason_codes: list[str]


class CostBasisSummary(BaseModel):
    method: Literal["fifo_v1"]
    remaining_quantity: str | None
    remaining_cost_basis: str | None
    realized_pnl: str | None
    unrealized_pnl: str | None
    lineage_count: int


class PerformanceCoverageRow(BaseModel):
    scope: Literal["portfolio", "postfinance", "truewealth", "crypto"]
    label: str
    reliable_from: str | None
    valuation_from: str | None
    valuation_to: str | None
    valuation_dates: int
    position_dates: int
    ttwror_status: Literal["complete", "partial", "unavailable"]
    xirr_status: Literal["complete", "partial", "unavailable"]
    attribution_status: Literal["complete", "partial", "unavailable"]
    reason_codes: list[str]


class PerformanceCoverageResponse(BaseModel):
    decision_version: Literal["investment_performance_scope_v1"]
    expected_scopes: list[Literal["postfinance", "truewealth", "crypto"]]
    status: Literal["complete", "partial", "unavailable"]
    rows: list[PerformanceCoverageRow]


class PortfolioPerformanceResponse(BaseModel):
    model_config = ConfigDict(extra="forbid")

    period: PerformancePeriod
    scope: PerformanceScope
    method: Literal["twr", "mwr", "both"]
    base_currency: Literal["CHF", "EUR", "USD"]
    valuation_as_of: str | None
    data_cutoff: str
    engine_version: str
    ttwror_version: Literal["ttwror_daily_v1"]
    xirr_version: Literal["xirr_v1"]
    attribution_version: Literal["performance_attribution_chf_v1"]
    cost_basis_version: Literal["fifo_v1"]
    input_fingerprint: str
    quality: PerformanceQualitySet
    summary: PerformanceSummary
    time_series: list[PerformancePoint]
    ttwror_series: list[PerformancePoint]
    cumulative_external_cashflows: list[PerformancePoint]
    external_cashflows: list[PerformanceCashflow]
    attribution: PerformanceAttribution
    cost_basis: CostBasisSummary
    sources: list[str]
