from __future__ import annotations

from typing import Any, Literal

from pydantic import BaseModel, ConfigDict, Field


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


PerformanceSource = Literal["postfinance", "truewealth", "crypto"]
TrackingMode = Literal["transactions", "managed_total_value", "confirmed_start_snapshot"]


class PerformanceSourceActivationPreviewRequest(StrictModel):
    source: PerformanceSource
    tracking_mode: TrackingMode
    period_from: str
    period_to: str
    evidence_reference: str = Field(min_length=1, max_length=500)
    confirmed_start_date: str | None = None
    attest_complete_external_flows: bool


class PerformanceSourceActivationPreviewResponse(PerformanceSourceActivationPreviewRequest):
    preview_id: str
    input_fingerprint: str
    preview_created_at: str
    account_ids: list[str]
    create_crypto_scope: bool
    evidence: dict[str, Any]
    local_input_revision: str
    blockers: list[str]
    can_confirm: bool
    planned_changes: dict[str, Any]


class PerformanceSourceActivationConfirmRequest(PerformanceSourceActivationPreviewRequest):
    preview_id: str
    input_fingerprint: str
    confirmation_id: str = Field(min_length=1, max_length=160)
    confirm: Literal[True]


class PerformanceSourceActivationConfirmResponse(StrictModel):
    confirmation_id: str
    idempotent: bool
    audit_id: str
    changed: bool


class PerformanceBackfillPreviewRequest(StrictModel):
    source: PerformanceSource
    period_from: str
    period_to: str


class PerformanceBackfillPreviewResponse(StrictModel):
    preview_id: str
    input_fingerprint: str
    preview_created_at: str
    source: PerformanceSource
    period_from: str
    period_to: str
    candidate_days: int = Field(ge=0)
    already_complete_days: int = Field(ge=0)
    days_to_materialize: int = Field(ge=0)
    missing_from: str | None
    missing_to: str | None
    blockers: list[str]
    can_confirm: bool
    required_input: str


class PerformanceBackfillConfirmRequest(PerformanceBackfillPreviewRequest):
    preview_id: str
    input_fingerprint: str
    confirmation_id: str = Field(min_length=1, max_length=160)
    confirm: Literal[True]
    note: str = Field(default="Confirmed performance valuation backfill", min_length=1, max_length=500)


class PerformanceBackfillRun(StrictModel):
    run_id: str
    as_of: str
    status: str
    valuation_stored: int = Field(ge=0)
    idempotent: bool


class PerformanceBackfillConfirmResponse(StrictModel):
    confirmation_id: str
    source: PerformanceSource
    idempotent: bool
    runs: list[PerformanceBackfillRun]
    audit_id: str
    completed: bool
    remaining_days: int = Field(ge=0)


class DailyValuationSourceStatus(StrictModel):
    source_key: str
    label: str
    source_enabled: bool
    operational_status: Literal["active", "paused", "partial", "failed"]
    last_confirmed_date: str | None
    last_successful_at: str | None
    last_run_at: str | None
    status: str
    reason_codes: list[str]
    price_as_of: str | None
    price_age_seconds: int | None = Field(default=None, ge=0)
    price_provider: str | None
    price_currency: str | None
    fx_provider: str | None
    valued_assets: int = Field(ge=0)
    missing_assets: int = Field(ge=0)
    total_value_chf: str | None
    next_action: str


class DailyValuationJobStatus(StrictModel):
    job_key: str
    configured: bool
    enabled: bool
    activation_required: bool
    schedule: str
    next_run: str | None
    sources: list[DailyValuationSourceStatus]


class PerformanceSetupValue(StrictModel):
    date: str
    value_chf: str


class PerformanceSetupDiagnostics(StrictModel):
    reason_codes: list[str]
    valuation_dates: int = Field(ge=0)
    position_dates: int = Field(ge=0)
    reclassification_status: str | None
    component_status: str | None


class PerformanceSetupSource(StrictModel):
    source: PerformanceSource
    label: str
    status: Literal["not_ready", "review_inputs", "ready"]
    earliest_possible_start: str | None
    opening_value: PerformanceSetupValue | None
    closing_value: PerformanceSetupValue | None
    cashflow_coverage: str
    next_action: str
    available_metrics: list[str]
    diagnostics: PerformanceSetupDiagnostics


class PerformanceSetupResponse(StrictModel):
    status: Literal["not_ready", "review_inputs", "ready"]
    source_order: list[PerformanceSource]
    sources: list[PerformanceSetupSource]
    timer_enabled: bool


class PerformanceReclassificationPreviewRequest(StrictModel):
    source: PerformanceSource
    period_from: str
    period_to: str


class PerformanceReclassificationPreviewResponse(StrictModel):
    source: PerformanceSource
    period_from: str
    period_to: str
    rows: list[dict[str, Any]]
    activity_count: int = Field(ge=0)
    unclear_count: int = Field(ge=0)
    can_activate: bool
    reason_codes: list[str]
    input_fingerprint: str


class TrueWealthCashflowEntry(StrictModel):
    date: str
    direction: Literal["deposit", "withdrawal", "einzahlung", "auszahlung", "external_deposit", "external_withdrawal"]
    amount: str
    currency: str = Field(min_length=3, max_length=3)
    amount_chf: str | None = None
    fx_source: str | None = Field(default=None, max_length=160)
    evidence_reference: str | None = Field(default=None, max_length=500)


class TrueWealthCashflowPreviewRequest(StrictModel):
    mode: Literal["external_cashflows", "no_external_flows"]
    coverage_from: str
    coverage_to: str
    entries: list[TrueWealthCashflowEntry] = Field(default_factory=list, max_length=500)
    csv_text: str | None = Field(default=None, max_length=200_000)
    attestation: str = Field(min_length=12, max_length=1_000)


class TrueWealthCashflowPreviewResponse(StrictModel):
    preview_id: str
    input_fingerprint: str
    account_id: str
    mode: Literal["external_cashflows", "no_external_flows"]
    coverage_from: str
    coverage_to: str
    entries: list[dict[str, Any]]
    entries_to_write: list[dict[str, Any]]
    entry_count: int = Field(ge=0)
    duplicate_count: int = Field(ge=0)
    effective_coverage_from: str
    effective_coverage_to: str
    attestation: str
    expected_changes: dict[str, int]
    status: str
    reason_codes: list[str]


class TrueWealthCashflowConfirmRequest(TrueWealthCashflowPreviewRequest):
    preview_id: str
    input_fingerprint: str
    confirmation_id: str = Field(min_length=1, max_length=160)
    confirm: Literal[True]


class TrueWealthCashflowConfirmResponse(StrictModel):
    confirmation_id: str
    input_fingerprint: str
    confirmation_request_fingerprint: str | None = None
    account_id: str
    mode: Literal["external_cashflows", "no_external_flows"]
    coverage_from: str
    coverage_to: str
    written_cashflows: int = Field(ge=0)
    valuation_snapshots_written: int = Field(default=0, ge=0)
    idempotent: bool


class TrueWealthBankPaymentPreviewRequest(StrictModel):
    period_from: str
    period_to: str
    recipient_name: str = Field(default="", max_length=240)
    recipient_account_identity: str | None = Field(default=None, max_length=240)
    counterparty_hashes: list[str] = Field(default_factory=list, max_length=20)
    reference_tokens: list[str] = Field(default_factory=list, max_length=20)
    collision_decisions: dict[str, Literal["link_existing", "record_distinct"]] = Field(default_factory=dict)
    attestation: str = Field(min_length=12, max_length=1_000)


class TrueWealthBankPaymentCandidate(StrictModel):
    bank_transaction_id: str
    booking_date: str
    value_date: str
    date_basis: Literal["bank_value_date_proxy"]
    amount: str
    currency: str
    overall_wealth_treatment: str
    truewealth_scope_treatment: str
    household_treatment: str
    match_quality: Literal["secure", "uncertain", "excluded"]
    recognition_reasons: list[str]
    disposition: Literal["new", "existing", "duplicate", "unclear"] | None = None
    existing_cashflow_id: str | None = None


class TrueWealthBankPaymentCounts(StrictModel):
    secure: int
    uncertain: int
    excluded: int
    new: int
    existing: int
    duplicates: int


class TrueWealthDetectedAmountChange(StrictModel):
    detected: bool
    amounts: list[str]
    rule_uses_amount: Literal[False]


class TrueWealthCoveredPeriod(StrictModel):
    from_: str = Field(alias="from")
    to: str


class TrueWealthBankPaymentPlannedChanges(StrictModel):
    recipient_rule_audit: int
    cashflow_transactions: int
    coverage_records: Literal[0]
    rule_activations: Literal[0]
    valuation_snapshots: Literal[0]


class TrueWealthBankPaymentPreviewResponse(StrictModel):
    preview_id: str
    input_fingerprint: str
    account_id: str
    period_from: str
    period_to: str
    rule_fingerprint: str
    rule_status: Literal["preview_only_not_activated"]
    candidates: list[TrueWealthBankPaymentCandidate]
    secure_candidates: list[TrueWealthBankPaymentCandidate]
    uncertain_candidates: list[TrueWealthBankPaymentCandidate]
    excluded_candidates: list[TrueWealthBankPaymentCandidate]
    cashflows_to_write: list[TrueWealthBankPaymentCandidate]
    counts: TrueWealthBankPaymentCounts
    detected_amount_change: TrueWealthDetectedAmountChange
    covered_period: TrueWealthCoveredPeriod
    can_confirm: bool
    planned_changes: TrueWealthBankPaymentPlannedChanges
    reason_codes: list[str]


class TrueWealthBankPaymentConfirmRequest(TrueWealthBankPaymentPreviewRequest):
    preview_id: str
    input_fingerprint: str
    confirmation_id: str = Field(min_length=1, max_length=160)
    confirm: Literal[True]


class TrueWealthBankPaymentConfirmResponse(StrictModel):
    confirmation_id: str
    input_fingerprint: str
    rule_fingerprint: str
    account_id: str
    period_from: str
    period_to: str
    written_cashflows: int = Field(ge=0)
    coverage_activated: Literal[False]
    rule_activated: Literal[False]
    audit_id: str
    idempotent: bool


class TrueWealthRecipientRuleActivationRequest(StrictModel):
    activation_id: str = Field(min_length=1, max_length=160)
    rule_fingerprint: str = Field(min_length=64, max_length=64)
    confirm: Literal[True]


class TrueWealthRecipientRuleActivationResponse(StrictModel):
    activation_id: str
    rule_fingerprint: str
    active: Literal[True]
    audit_id: str
    idempotent: bool


class TrueWealthActivationPackagePreviewRequest(TrueWealthBankPaymentPreviewRequest):
    performance_from: str
    performance_to: str
    model_as_of: str


class TrueWealthPerformancePoint(StrictModel):
    date: str
    value_chf: str
    kind: Literal["confirmed", "modelled"]
    source: str
    anchor: bool


class TrueWealthPerformancePeriod(StrictModel):
    from_: str = Field(alias="from", serialization_alias="from")
    to: str


class TrueWealthPerformanceViewResponse(StrictModel):
    scope: Literal["truewealth"]
    requested_period: TrueWealthPerformancePeriod
    available_period: TrueWealthPerformancePeriod | None
    earliest_source_date: str | None
    first_performance_anchor: str | None
    points: list[TrueWealthPerformancePoint]
    latest_confirmed_value: TrueWealthPerformancePoint | None
    latest_modelled_value: TrueWealthPerformancePoint | None
    status: Literal["available", "not_available"]
    reason_codes: list[str]


class TrueWealthLatestModelledValue(StrictModel):
    valuation_at: str
    value_original: str
    source: Literal["truewealth_modelled_daily"]
    quality_status: str


class TrueWealthModelPreviewResponse(StrictModel):
    as_of: str
    account_id: str
    status: Literal["ready", "blocked"]
    quality_status: str | None = None
    reason_codes: list[str]
    modelled_value_chf: str | None
    anchor_date: str | None
    net_external_cashflows_chf: str | None
    latest_price_fx_date: str | None
    latest_modelled_value: TrueWealthLatestModelledValue | None
    input_fingerprint: str


class TrueWealthActivationPerformancePeriod(StrictModel):
    requested_from: str
    requested_to: str
    actual_to: str | None


class TrueWealthActivationCashflow(StrictModel):
    cashflow_ref: str
    value_date: str
    amount: str
    currency: Literal["CHF"]
    disposition: Literal["pending_confirmation", "existing_confirmed"]


class TrueWealthActivationPerformance(StrictModel):
    period: TrueWealthActivationPerformancePeriod
    opening_value_chf: str | None
    opening_date: str | None
    closing_value_chf: str | None
    closing_date: str | None
    deposits: list[TrueWealthActivationCashflow]
    deposit_total_chf: str
    withdrawals: list[TrueWealthActivationCashflow]
    withdrawal_total_chf: str
    investment_result_chf: str | None
    xirr_readiness: Literal[
        "ready_after_cashflow_confirmation",
        "confirmed_cashflows_require_separate_coverage_confirmation",
        "not_ready",
    ]
    ttwror_readiness: Literal["unavailable"]
    ttwror_quality: Literal["requires_reliable_flow_boundary_valuations"]
    reason_codes: list[str]
    input_fingerprint: str


class TrueWealthRecipientRulePackage(StrictModel):
    required: Literal[True]
    input_fingerprint: str
    historical_cashflows: int
    activates_future_automation: Literal[False]


class TrueWealthFutureRulePackage(StrictModel):
    required_separately: Literal[True]
    enabled_in_this_preview: Literal[False]


class TrueWealthCoveragePackage(StrictModel):
    from_: str = Field(alias="from", serialization_alias="from")
    to: str
    status_after_confirmation: Literal["unchanged_requires_separate_coverage_confirmation"]


class TrueWealthModelledDailyPackage(StrictModel):
    enabled_in_this_preview: Literal[False]
    expected_path: Literal[
        "confirmed anchor positions + exact-date prices/FX + unassigned confirmed external cash"
    ]


class TrueWealthActivationPackage(StrictModel):
    recipient_rule_confirmation: TrueWealthRecipientRulePackage
    future_rule_activation: TrueWealthFutureRulePackage
    cashflow_coverage: TrueWealthCoveragePackage
    modelled_daily_valuation: TrueWealthModelledDailyPackage
    production_writes: Literal[0]


class TrueWealthActivationPackagePreviewResponse(StrictModel):
    package_version: Literal["truewealth_productization_v1"]
    bank_payments: TrueWealthBankPaymentPreviewResponse
    performance: TrueWealthActivationPerformance
    modelled_valuation: TrueWealthModelPreviewResponse
    activation_package: TrueWealthActivationPackage
    input_fingerprint: str
