-- Balance sheet — détail par titre (Bilan Étape 2) — Migration v14
-- Created: 2026-06-06
-- Issue: #210 (Bilan détail #1 — schema & migrations v14/v15 + types)
--
-- Purely additive: two new tables enabling a single account to hold many
-- securities at a given snapshot date instead of one denormalized value.
-- Conventions aligned with balance_schema.sql / consolidated_schema.sql:
--   - INTEGER PRIMARY KEY AUTOINCREMENT
--   - REAL for monetary amounts / quantities (matches transactions.amount)
--   - snake_case
--   - FK with explicit ON DELETE policies
--   - DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP for timestamps
--
-- Design notes (spec-decisions-bilan-detail-titres.md + review caveats):
--   - balance_securities.symbol is the natural key, normalized upper/trim by
--     the service layer; COLLATE NOCASE UNIQUE prevents case-duplicates
--     ('aapl' vs 'AAPL') at the SQL level (SEC/ARCH review caveat).
--   - balance_snapshot_holdings references balance_snapshot_lines(id) rather
--     than (snapshot_id, account_id): the lines table already guarantees one
--     row per (snapshot, account) via UNIQUE(snapshot_id, account_id), so the
--     line id uniquely identifies that pair (ARCH review: keep the line FK).
--   - value is denormalized (= quantity * unit_price) so reports stay
--     reproducible without re-fetching prices — same rationale as
--     balance_snapshot_lines.value.


-- =========================================================================
-- balance_securities — catalogue of investable instruments (stock | crypto)
-- =========================================================================
-- One row per security/coin the user holds in a detailed account. `symbol` is
-- stored normalized (upper/trim) with COLLATE NOCASE so duplicates differing
-- only by case are impossible. `asset_type` mirrors balance_categories so the
-- price-fetch flow can route per security.
CREATE TABLE IF NOT EXISTS balance_securities (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    symbol TEXT NOT NULL COLLATE NOCASE UNIQUE,
    name TEXT,
    currency TEXT NOT NULL DEFAULT 'CAD',
    asset_type TEXT NOT NULL CHECK (asset_type IN ('stock','crypto')),
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);


-- =========================================================================
-- balance_snapshot_holdings — one row per (snapshot line, security)
-- =========================================================================
-- The per-title breakdown of a detailed account's snapshot line. CASCADE on
-- snapshot_line_id wipes holdings when the parent line is removed; RESTRICT on
-- security_id blocks deleting a security still referenced by history. `value`
-- is stored denormalized (= quantity * unit_price) for reproducible reports.
CREATE TABLE IF NOT EXISTS balance_snapshot_holdings (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    snapshot_line_id INTEGER NOT NULL REFERENCES balance_snapshot_lines(id) ON DELETE CASCADE,
    security_id INTEGER NOT NULL REFERENCES balance_securities(id) ON DELETE RESTRICT,
    quantity REAL NOT NULL,
    unit_price REAL NOT NULL,
    value REAL NOT NULL,
    book_cost REAL,
    price_source TEXT,
    price_fetched_at DATETIME,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    UNIQUE (snapshot_line_id, security_id)
);

CREATE INDEX IF NOT EXISTS idx_balance_snapshot_holdings_line ON balance_snapshot_holdings(snapshot_line_id);
CREATE INDEX IF NOT EXISTS idx_balance_snapshot_holdings_security ON balance_snapshot_holdings(security_id);
