-- V8__PostgreSQL_History_First_Schema.sql
-- PostgreSQL History-First Operating Model Canonical Database Schema
-- Standard: 3NF Relational Core + JSONB Provenance Payload + Audit Logging

-- 1. Create Schema if not exists
CREATE SCHEMA IF NOT EXISTS quantengine;

-- 2. Market Raw History Time-Series
CREATE TABLE IF NOT EXISTS quantengine.market_raw_history (
    id BIGSERIAL PRIMARY KEY,
    ticker VARCHAR(32) NOT NULL,
    as_of_date VARCHAR(10) NOT NULL,
    open_price NUMERIC(18, 4),
    high_price NUMERIC(18, 4),
    low_price NUMERIC(18, 4),
    close_price NUMERIC(18, 4) NOT NULL,
    volume BIGINT,
    nav_price NUMERIC(18, 4),
    disparate_ratio NUMERIC(10, 6),
    tracking_error NUMERIC(10, 6),
    aum_krw NUMERIC(20, 2),
    raw_payload JSONB NOT NULL,
    provenance JSONB NOT NULL,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    CONSTRAINT uk_market_raw_ticker_date UNIQUE (ticker, as_of_date)
);

CREATE INDEX IF NOT EXISTS idx_market_raw_ticker_date ON quantengine.market_raw_history (ticker, as_of_date DESC);

-- 3. Factor Version & Definition History
CREATE TABLE IF NOT EXISTS quantengine.factor_version_history (
    factor_id VARCHAR(64) PRIMARY KEY,
    formula_name VARCHAR(128) NOT NULL,
    version VARCHAR(32) NOT NULL,
    category VARCHAR(64) NOT NULL,
    calibration_state VARCHAR(32) NOT NULL DEFAULT 'UNTESTED',
    threshold_params JSONB NOT NULL,
    description TEXT,
    updated_at TIMESTAMPTZ DEFAULT NOW()
);

-- 4. Factor Output History (Calculation Store)
CREATE TABLE IF NOT EXISTS quantengine.factor_output_history (
    id BIGSERIAL PRIMARY KEY,
    run_id VARCHAR(64) NOT NULL,
    ticker VARCHAR(32) NOT NULL,
    as_of_date VARCHAR(10) NOT NULL,
    factor_id VARCHAR(64) NOT NULL,
    score NUMERIC(10, 4),
    calculation_state VARCHAR(32) NOT NULL,
    provenance JSONB NOT NULL,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    CONSTRAINT fk_factor_version FOREIGN KEY (factor_id) REFERENCES quantengine.factor_version_history (factor_id) ON DELETE CASCADE
);

CREATE INDEX IF NOT EXISTS idx_factor_output_run_ticker ON quantengine.factor_output_history (run_id, ticker);

-- 5. Decision Result History (Signal & Risk Engine Output)
CREATE TABLE IF NOT EXISTS quantengine.decision_result_history (
    id BIGSERIAL PRIMARY KEY,
    run_id VARCHAR(64) NOT NULL UNIQUE,
    as_of_date VARCHAR(10) NOT NULL,
    market_regime VARCHAR(32) NOT NULL,
    portfolio_health VARCHAR(32) NOT NULL,
    rebalance_required BOOLEAN NOT NULL DEFAULT FALSE,
    mid_check_required BOOLEAN NOT NULL DEFAULT FALSE,
    total_asset_krw NUMERIC(20, 2) NOT NULL,
    d2_cash_krw NUMERIC(20, 2) NOT NULL,
    decision_packet_json JSONB NOT NULL,
    created_at TIMESTAMPTZ DEFAULT NOW()
);

-- 6. Order Waterfall Execution History
CREATE TABLE IF NOT EXISTS quantengine.order_waterfall_execution_history (
    id BIGSERIAL PRIMARY KEY,
    run_id VARCHAR(64) NOT NULL,
    ticker VARCHAR(32) NOT NULL,
    sell_priority_rank INT NOT NULL,
    waterfall_stage VARCHAR(64) NOT NULL,
    action VARCHAR(16) NOT NULL,
    target_qty INT NOT NULL,
    executed_qty INT DEFAULT 0,
    target_price NUMERIC(18, 4),
    executed_price NUMERIC(18, 4),
    bid_ask_spread_bps NUMERIC(10, 2),
    slippage_bps NUMERIC(10, 2),
    status VARCHAR(32) NOT NULL,
    rationale TEXT,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    CONSTRAINT fk_decision_waterfall FOREIGN KEY (run_id) REFERENCES quantengine.decision_result_history (run_id) ON DELETE CASCADE
);

-- 7. Shadow Ledger History (Blocked/Gate Orders Audit)
CREATE TABLE IF NOT EXISTS quantengine.shadow_ledger_history (
    id BIGSERIAL PRIMARY KEY,
    run_id VARCHAR(64) NOT NULL,
    ticker VARCHAR(32) NOT NULL,
    blocked_gate VARCHAR(64) NOT NULL,
    blocked_reason TEXT NOT NULL,
    shadow_price NUMERIC(18, 4) NOT NULL,
    shadow_qty INT NOT NULL,
    shadow_tp_price NUMERIC(18, 4),
    shadow_sl_price NUMERIC(18, 4),
    created_at TIMESTAMPTZ DEFAULT NOW(),
    CONSTRAINT fk_decision_shadow FOREIGN KEY (run_id) REFERENCES quantengine.decision_result_history (run_id) ON DELETE CASCADE
);

-- 8. Scheduler State Machine History
CREATE TABLE IF NOT EXISTS quantengine.scheduler_state_history (
    id BIGSERIAL PRIMARY KEY,
    task_name VARCHAR(64) NOT NULL,
    execution_id VARCHAR(64) NOT NULL UNIQUE,
    state VARCHAR(32) NOT NULL,
    started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    finished_at TIMESTAMPTZ,
    error_message TEXT,
    lock_token VARCHAR(64)
);

CREATE INDEX IF NOT EXISTS idx_scheduler_state_task ON quantengine.scheduler_state_history (task_name, state);
