-- dd0c/route V1 — TimescaleDB schema (telemetry)

-- Request events (the core telemetry table)
CREATE TABLE request_events (
    time TIMESTAMPTZ NOT NULL DEFAULT now(),
    org_id UUID NOT NULL,
    original_model TEXT NOT NULL,
    routed_model TEXT NOT NULL,
    provider TEXT NOT NULL,
    strategy TEXT NOT NULL,
    latency_ms INT NOT NULL,
    status_code SMALLINT NOT NULL,
    is_streaming BOOLEAN NOT NULL DEFAULT false,
    prompt_tokens INT NOT NULL DEFAULT 0,
    completion_tokens INT NOT NULL DEFAULT 0,
    cost_original NUMERIC(10, 6),
    cost_actual NUMERIC(10, 6),
    cost_saved NUMERIC(10, 6)
);

-- Convert to hypertable (7-day chunks)
SELECT create_hypertable('request_events', 'time', chunk_time_interval => INTERVAL '7 days');

-- Indexes for dashboard queries
CREATE INDEX idx_events_org_time ON request_events (org_id, time DESC);
CREATE INDEX idx_events_model ON request_events (org_id, original_model, time DESC);

-- Continuous aggregates for dashboard rollups

-- Hourly rollup
CREATE MATERIALIZED VIEW request_events_hourly
WITH (timescaledb.continuous) AS
SELECT
    time_bucket('1 hour', time) AS bucket,
    org_id,
    original_model,
    routed_model,
    provider,
    strategy,
    COUNT(*) AS request_count,
    AVG(latency_ms)::INT AS avg_latency_ms,
    PERCENTILE_CONT(0.99) WITHIN GROUP (ORDER BY latency_ms)::INT AS p99_latency_ms,
    SUM(prompt_tokens) AS total_prompt_tokens,
    SUM(completion_tokens) AS total_completion_tokens,
    SUM(cost_original) AS total_cost_original,
    SUM(cost_actual) AS total_cost_actual,
    SUM(cost_saved) AS total_cost_saved
FROM request_events
GROUP BY bucket, org_id, original_model, routed_model, provider, strategy;

-- Refresh policy: every hour, lag 10 minutes
SELECT add_continuous_aggregate_policy('request_events_hourly',
    start_offset => INTERVAL '2 hours',
    end_offset => INTERVAL '10 minutes',
    schedule_interval => INTERVAL '1 hour');

-- Daily rollup
CREATE MATERIALIZED VIEW request_events_daily
WITH (timescaledb.continuous) AS
SELECT
    time_bucket('1 day', time) AS bucket,
    org_id,
    original_model,
    routed_model,
    COUNT(*) AS request_count,
    SUM(prompt_tokens) AS total_prompt_tokens,
    SUM(completion_tokens) AS total_completion_tokens,
    SUM(cost_original) AS total_cost_original,
    SUM(cost_actual) AS total_cost_actual,
    SUM(cost_saved) AS total_cost_saved
FROM request_events
GROUP BY bucket, org_id, original_model, routed_model;

SELECT add_continuous_aggregate_policy('request_events_daily',
    start_offset => INTERVAL '3 days',
    end_offset => INTERVAL '1 hour',
    schedule_interval => INTERVAL '1 day');

-- Compression policy: compress chunks older than 30 days
ALTER TABLE request_events SET (
    timescaledb.compress,
    timescaledb.compress_segmentby = 'org_id',
    timescaledb.compress_orderby = 'time DESC'
);
SELECT add_compression_policy('request_events', INTERVAL '30 days');

-- Retention policy: drop data older than 1 year (free tier: 30 days via app logic)
SELECT add_retention_policy('request_events', INTERVAL '365 days');
