CREATE TABLE IF NOT EXISTS raw_mqtt_events (
    id BIGSERIAL PRIMARY KEY,
    received_at TIMESTAMPTZ NOT NULL DEFAULT now(),

    source_system TEXT NOT NULL,
    network_name TEXT,
    modem_preset TEXT,

    broker_host TEXT,
    broker_port INTEGER,

    topic TEXT NOT NULL,
    qos INTEGER,
    retain BOOLEAN,

    payload_raw BYTEA,
    payload_text TEXT,
    payload_json JSONB,

    parse_status TEXT NOT NULL DEFAULT 'raw',
    parser_error TEXT
);

CREATE INDEX IF NOT EXISTS idx_raw_mqtt_events_received_at
    ON raw_mqtt_events(received_at DESC);

CREATE INDEX IF NOT EXISTS idx_raw_mqtt_events_source_received
    ON raw_mqtt_events(source_system, received_at DESC);

CREATE INDEX IF NOT EXISTS idx_raw_mqtt_events_topic
    ON raw_mqtt_events(topic);

CREATE TABLE IF NOT EXISTS normalized_events (
    id BIGSERIAL PRIMARY KEY,
    raw_event_id BIGINT REFERENCES raw_mqtt_events(id) ON DELETE CASCADE,

    event_time TIMESTAMPTZ NOT NULL DEFAULT now(),
    source_system TEXT NOT NULL,
    network_name TEXT,
    modem_preset TEXT,
    topic TEXT NOT NULL,

    from_node_id TEXT,
    to_node_id TEXT,
    message_type TEXT,
    text_body TEXT,

    rssi NUMERIC,
    snr NUMERIC,

    payload JSONB
);

CREATE INDEX IF NOT EXISTS idx_normalized_events_event_time
    ON normalized_events(event_time DESC);

CREATE INDEX IF NOT EXISTS idx_normalized_events_source_time
    ON normalized_events(source_system, event_time DESC);

CREATE INDEX IF NOT EXISTS idx_normalized_events_from_node
    ON normalized_events(source_system, from_node_id);

CREATE INDEX IF NOT EXISTS idx_normalized_events_message_type
    ON normalized_events(message_type);

CREATE TABLE IF NOT EXISTS nodes_seen (
    id BIGSERIAL PRIMARY KEY,
    source_system TEXT NOT NULL,
    node_id TEXT NOT NULL,
    first_seen TIMESTAMPTZ NOT NULL DEFAULT now(),
    last_seen TIMESTAMPTZ NOT NULL DEFAULT now(),
    metadata JSONB,
    UNIQUE(source_system, node_id)
);

CREATE INDEX IF NOT EXISTS idx_nodes_seen_last_seen
    ON nodes_seen(last_seen DESC);

CREATE OR REPLACE VIEW v_packets_per_hour AS
SELECT
    date_trunc('hour', event_time) AS hour,
    source_system,
    network_name,
    modem_preset,
    COUNT(*) AS packets
FROM normalized_events
GROUP BY 1, 2, 3, 4
ORDER BY 1 DESC;

CREATE OR REPLACE VIEW v_text_messages_per_day AS
SELECT
    date_trunc('day', event_time) AS day,
    source_system,
    network_name,
    modem_preset,
    COUNT(*) AS text_messages
FROM normalized_events
WHERE message_type = 'text'
GROUP BY 1, 2, 3, 4
ORDER BY 1 DESC;

CREATE OR REPLACE VIEW v_unique_nodes_per_day AS
SELECT
    date_trunc('day', event_time) AS day,
    source_system,
    network_name,
    modem_preset,
    COUNT(DISTINCT from_node_id) AS unique_nodes
FROM normalized_events
WHERE from_node_id IS NOT NULL
GROUP BY 1, 2, 3, 4
ORDER BY 1 DESC;

CREATE OR REPLACE VIEW v_utilization_hourly AS
SELECT
    date_trunc('hour', event_time) AS hour,
    CASE
        WHEN source_system = 'meshtastic' AND modem_preset IS NOT NULL AND modem_preset <> ''
            THEN 'Meshtastic ' || modem_preset
        WHEN source_system = 'meshtastic'
            THEN 'Meshtastic'
        WHEN source_system = 'meshcore'
            THEN 'MeshCore'
        ELSE source_system
    END AS network,
    COUNT(*) AS packets,
    COUNT(*) FILTER (WHERE message_type = 'text') AS text_messages,
    COUNT(DISTINCT from_node_id) AS unique_nodes
FROM normalized_events
GROUP BY 1, 2
ORDER BY 1 DESC;

CREATE OR REPLACE VIEW v_top_talkers_24h AS
SELECT
    source_system,
    network_name,
    modem_preset,
    from_node_id,
    COUNT(*) AS packets,
    COUNT(*) FILTER (WHERE message_type = 'text') AS text_messages,
    MAX(event_time) AS last_seen
FROM normalized_events
WHERE event_time >= now() - interval '24 hours'
  AND from_node_id IS NOT NULL
GROUP BY 1, 2, 3, 4
ORDER BY packets DESC;
