"""Tests for /networth and /networth/history.""" from __future__ import annotations from collections.abc import AsyncIterator from datetime import date from decimal import Decimal import pytest_asyncio from httpx import ASGITransport, AsyncClient from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, async_sessionmaker from fire_planner.api.dependencies import get_session from fire_planner.app import app from fire_planner.db import AccountSnapshot @pytest_asyncio.fixture async def client(engine: AsyncEngine, session: AsyncSession) -> AsyncIterator[AsyncClient]: factory = async_sessionmaker(engine, expire_on_commit=False) async def _override() -> AsyncIterator[AsyncSession]: async with factory() as s: yield s app.dependency_overrides[get_session] = _override transport = ASGITransport(app=app) async with AsyncClient(transport=transport, base_url="http://test") as ac: yield ac app.dependency_overrides.clear() async def _seed_snapshots(session: AsyncSession) -> None: rows = [ AccountSnapshot( external_id="wealthfolio:isa:2026-04-23", snapshot_date=date(2026, 4, 23), account_id="isa", account_name="ISA", account_type="ISA", currency="GBP", market_value=Decimal("280000"), market_value_gbp=Decimal("280000"), ), AccountSnapshot( external_id="wealthfolio:schwab:2026-04-23", snapshot_date=date(2026, 4, 23), account_id="schwab", account_name="Schwab", account_type="BROKERAGE", currency="USD", market_value=Decimal("780000"), market_value_gbp=Decimal("615000"), ), AccountSnapshot( external_id="wealthfolio:isa:2026-04-25", snapshot_date=date(2026, 4, 25), account_id="isa", account_name="ISA", account_type="ISA", currency="GBP", market_value=Decimal("300000"), market_value_gbp=Decimal("300000"), ), AccountSnapshot( external_id="wealthfolio:schwab:2026-04-25", snapshot_date=date(2026, 4, 25), account_id="schwab", account_name="Schwab", account_type="BROKERAGE", currency="USD", market_value=Decimal("800000"), market_value_gbp=Decimal("640000"), ), ] for r in rows: session.add(r) await session.commit() async def test_get_networth_returns_latest(client: AsyncClient, session: AsyncSession) -> None: await _seed_snapshots(session) resp = await client.get("/networth") assert resp.status_code == 200 body = resp.json() assert body["snapshot_date"] == "2026-04-25" assert Decimal(body["total_gbp"]) == Decimal("940000") by_id = {a["account_id"]: a for a in body["accounts"]} assert Decimal(by_id["isa"]["market_value_gbp"]) == Decimal("300000") assert Decimal(by_id["schwab"]["market_value_gbp"]) == Decimal("640000") async def test_get_networth_empty_when_no_snapshots(client: AsyncClient) -> None: resp = await client.get("/networth") assert resp.status_code == 200 body = resp.json() assert body["accounts"] == [] assert Decimal(body["total_gbp"]) == Decimal("0") async def test_networth_history_returns_per_date(client: AsyncClient, session: AsyncSession) -> None: await _seed_snapshots(session) resp = await client.get("/networth/history") assert resp.status_code == 200 points = resp.json()["points"] assert len(points) == 2 by_date = {p["snapshot_date"]: p for p in points} assert Decimal(by_date["2026-04-23"]["total_gbp"]) == Decimal("895000") assert Decimal(by_date["2026-04-25"]["total_gbp"]) == Decimal("940000") assert Decimal(by_date["2026-04-25"]["by_account"]["ISA"]) == Decimal("300000") async def test_networth_history_respects_days_filter( client: AsyncClient, session: AsyncSession, ) -> None: await _seed_snapshots(session) resp = await client.get("/networth/history?days=1") assert resp.status_code == 200 # days=1 ⇒ only the latest 1 distinct date assert len(resp.json()["points"]) == 1