-- Run once as the TimescaleDB superuser (fitdata):
--   psql -h localhost -p 5433 -U fitdata -f schema.sql

CREATE DATABASE energy;

\c energy

CREATE EXTENSION IF NOT EXISTS timescaledb;

CREATE USER energy WITH PASSWORD 'changeme';
GRANT ALL ON DATABASE energy TO energy;
GRANT ALL ON SCHEMA public TO energy;

-- ── Raw hypertables ───────────────────────────────────────────────────────────

-- Written by energy-collector (pvcollect replacement) every 10 s
CREATE TABLE inverter (
    time            TIMESTAMPTZ NOT NULL,
    pv1_power       REAL,   -- W
    pv2_power       REAL,   -- W
    pv_l1_power     REAL,   -- W  (inverter AC output phase 1)
    pv_l2_power     REAL,   -- W
    pv_l3_power     REAL,   -- W
    battery_soc     REAL,   -- %
    grid_import_kwh REAL,   -- kWh cumulative
    grid_export_kwh REAL,   -- kWh cumulative
    pv_energy_kwh   REAL    -- kWh cumulative
);
SELECT create_hypertable('inverter', 'time', chunk_time_interval => INTERVAL '7 days');

-- Written by energy-collector (meter replacement) every 10 s, one row per device
CREATE TABLE power_meter (
    time       TIMESTAMPTZ NOT NULL,
    device     TEXT        NOT NULL,  -- 'house' | 'barn'
    l1_power   REAL,   -- W
    l2_power   REAL,   -- W
    l3_power   REAL,   -- W
    import_kwh REAL,   -- kWh cumulative
    export_kwh REAL    -- kWh cumulative
);
SELECT create_hypertable('power_meter', 'time', chunk_time_interval => INTERVAL '7 days');
CREATE INDEX ON power_meter (device, time DESC);

GRANT ALL ON ALL TABLES IN SCHEMA public TO energy;

-- ── Continuous aggregates ─────────────────────────────────────────────────────

-- 10-minute buckets — live chart (1 h, 6 h, 24 h ranges)
CREATE MATERIALIZED VIEW inverter_10m
WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
SELECT time_bucket('10 minutes', time) AS bucket,
       AVG(pv1_power + pv2_power)      AS pv_power,
       AVG(battery_soc)                AS battery_soc
FROM inverter
GROUP BY bucket;

CREATE MATERIALIZED VIEW power_meter_10m
WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
SELECT time_bucket('10 minutes', time)      AS bucket,
       device,
       AVG(l1_power + l2_power + l3_power) AS total_power
FROM power_meter
GROUP BY bucket, device;

-- 1-hour buckets — live chart (7 d range), built on 10 m (hierarchical)
CREATE MATERIALIZED VIEW inverter_1h
WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
SELECT time_bucket('1 hour', bucket) AS bucket,
       AVG(pv_power)                 AS pv_power,
       AVG(battery_soc)              AS battery_soc
FROM inverter_10m
GROUP BY 1;

CREATE MATERIALIZED VIEW power_meter_1h
WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
SELECT time_bucket('1 hour', bucket)  AS bucket,
       device,
       AVG(total_power)               AS total_power
FROM power_meter_10m
GROUP BY 1, device;

-- Daily last-value snapshots — basis for bar-chart energy deltas
-- Query with LAG() to get per-period consumption.
CREATE MATERIALIZED VIEW inverter_daily
WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
SELECT time_bucket('1 day', time)       AS bucket,
       last(grid_import_kwh, time)      AS grid_import_kwh,
       last(grid_export_kwh, time)      AS grid_export_kwh,
       last(pv_energy_kwh,   time)      AS pv_energy_kwh
FROM inverter
GROUP BY bucket;

CREATE MATERIALIZED VIEW power_meter_daily
WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
SELECT time_bucket('1 day', time) AS bucket,
       device,
       last(import_kwh, time)     AS import_kwh
FROM power_meter
GROUP BY bucket, device;

-- ── Retention — keep 30 days of raw data; aggregates stay forever ─────────────

SELECT add_retention_policy('inverter',    INTERVAL '30 days');
SELECT add_retention_policy('power_meter', INTERVAL '30 days');

-- ── Refresh policies ──────────────────────────────────────────────────────────

SELECT add_continuous_aggregate_policy('inverter_10m',
    start_offset      => INTERVAL '1 hour',
    end_offset        => INTERVAL '10 minutes',
    schedule_interval => INTERVAL '10 minutes');

SELECT add_continuous_aggregate_policy('power_meter_10m',
    start_offset      => INTERVAL '1 hour',
    end_offset        => INTERVAL '10 minutes',
    schedule_interval => INTERVAL '10 minutes');

SELECT add_continuous_aggregate_policy('inverter_1h',
    start_offset      => INTERVAL '3 hours',
    end_offset        => INTERVAL '1 hour',
    schedule_interval => INTERVAL '1 hour');

SELECT add_continuous_aggregate_policy('power_meter_1h',
    start_offset      => INTERVAL '3 hours',
    end_offset        => INTERVAL '1 hour',
    schedule_interval => INTERVAL '1 hour');

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

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

-- Grant SELECT on all tables and views (including continuous aggregates) to energy.
-- Run after all views are created so the grant covers them.
GRANT SELECT ON ALL TABLES IN SCHEMA public TO energy;
