-- ============================================================================
-- Water Project Database Schema
-- PostgreSQL Migration Script
-- ============================================================================

-- Enable required extensions
CREATE EXTENSION IF NOT EXISTS "pgcrypto";

-- ============================================================================
-- TRIGGER FUNCTION: Auto-update updated_at timestamp
-- ============================================================================
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = CURRENT_TIMESTAMP;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- ============================================================================
-- ENUM TYPES
-- ============================================================================
CREATE TYPE role_name AS ENUM ('ADMIN', 'OPERATOR', 'VIEWER');
CREATE TYPE project_status AS ENUM ('ACTIVE', 'INACTIVE', 'COMPLETED');
CREATE TYPE device_status AS ENUM ('ACTIVE', 'INACTIVE', 'OFFLINE', 'MAINTENANCE', 'ERROR');
CREATE TYPE meter_type AS ENUM ('WATER', 'GAS', 'ELECTRIC');
CREATE TYPE reading_type AS ENUM ('AUTOMATIC', 'MANUAL', 'SCHEDULED');

-- ============================================================================
-- TABLE 1: roles
-- ============================================================================
CREATE TABLE roles (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name role_name NOT NULL UNIQUE,
    description TEXT,
    permissions JSONB NOT NULL DEFAULT '{}',
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_roles_name ON roles(name);

CREATE TRIGGER trigger_roles_updated_at
    BEFORE UPDATE ON roles
    FOR EACH ROW
    EXECUTE FUNCTION update_updated_at_column();

COMMENT ON TABLE roles IS 'User roles with associated permissions';

-- ============================================================================
-- TABLE 2: users
-- ============================================================================
CREATE TABLE users (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    email VARCHAR(255) NOT NULL UNIQUE,
    password_hash VARCHAR(255) NOT NULL,
    name VARCHAR(255) NOT NULL,
    avatar_url TEXT,
    role_id UUID NOT NULL REFERENCES roles(id) ON DELETE RESTRICT,
    is_active BOOLEAN NOT NULL DEFAULT TRUE,
    last_login TIMESTAMP WITH TIME ZONE,
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_role_id ON users(role_id);
CREATE INDEX idx_users_is_active ON users(is_active);

CREATE TRIGGER trigger_users_updated_at
    BEFORE UPDATE ON users
    FOR EACH ROW
    EXECUTE FUNCTION update_updated_at_column();

COMMENT ON TABLE users IS 'Application users with authentication credentials';

-- ============================================================================
-- TABLE 3: projects
-- ============================================================================
CREATE TABLE projects (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name VARCHAR(255) NOT NULL,
    description TEXT,
    area_name VARCHAR(255),
    location TEXT,
    status project_status NOT NULL DEFAULT 'ACTIVE',
    created_by UUID NOT NULL REFERENCES users(id) ON DELETE RESTRICT,
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_projects_status ON projects(status);
CREATE INDEX idx_projects_created_by ON projects(created_by);
CREATE INDEX idx_projects_name ON projects(name);

CREATE TRIGGER trigger_projects_updated_at
    BEFORE UPDATE ON projects
    FOR EACH ROW
    EXECUTE FUNCTION update_updated_at_column();

COMMENT ON TABLE projects IS 'Water monitoring projects';

-- ============================================================================
-- TABLE 4: concentrators
-- ============================================================================
CREATE TABLE concentrators (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    serial_number VARCHAR(100) NOT NULL UNIQUE,
    name VARCHAR(255) NOT NULL,
    project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
    location TEXT,
    status device_status NOT NULL DEFAULT 'ACTIVE',
    ip_address INET,
    firmware_version VARCHAR(50),
    last_communication TIMESTAMP WITH TIME ZONE,
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_concentrators_serial_number ON concentrators(serial_number);
CREATE INDEX idx_concentrators_project_id ON concentrators(project_id);
CREATE INDEX idx_concentrators_status ON concentrators(status);

CREATE TRIGGER trigger_concentrators_updated_at
    BEFORE UPDATE ON concentrators
    FOR EACH ROW
    EXECUTE FUNCTION update_updated_at_column();

COMMENT ON TABLE concentrators IS 'Data concentrators that aggregate gateway communications';

-- ============================================================================
-- TABLE 5: gateways
-- ============================================================================
CREATE TABLE gateways (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    gateway_id VARCHAR(100) NOT NULL UNIQUE,
    name VARCHAR(255) NOT NULL,
    project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
    concentrator_id UUID REFERENCES concentrators(id) ON DELETE SET NULL,
    location TEXT,
    status device_status NOT NULL DEFAULT 'ACTIVE',
    tts_gateway_id VARCHAR(255),
    tts_status VARCHAR(50),
    tts_last_seen TIMESTAMP WITH TIME ZONE,
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_gateways_gateway_id ON gateways(gateway_id);
CREATE INDEX idx_gateways_project_id ON gateways(project_id);
CREATE INDEX idx_gateways_concentrator_id ON gateways(concentrator_id);
CREATE INDEX idx_gateways_status ON gateways(status);

CREATE TRIGGER trigger_gateways_updated_at
    BEFORE UPDATE ON gateways
    FOR EACH ROW
    EXECUTE FUNCTION update_updated_at_column();

COMMENT ON TABLE gateways IS 'LoRaWAN gateways for device communication';

-- ============================================================================
-- TABLE 6: devices
-- ============================================================================
CREATE TABLE devices (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    dev_eui VARCHAR(16) NOT NULL UNIQUE,
    name VARCHAR(255) NOT NULL,
    device_type VARCHAR(100),
    project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
    gateway_id UUID REFERENCES gateways(id) ON DELETE SET NULL,
    status device_status NOT NULL DEFAULT 'ACTIVE',
    tts_device_id VARCHAR(255),
    tts_status VARCHAR(50),
    tts_last_seen TIMESTAMP WITH TIME ZONE,
    app_key VARCHAR(32),
    join_eui VARCHAR(16),
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_devices_dev_eui ON devices(dev_eui);
CREATE INDEX idx_devices_project_id ON devices(project_id);
CREATE INDEX idx_devices_gateway_id ON devices(gateway_id);
CREATE INDEX idx_devices_status ON devices(status);
CREATE INDEX idx_devices_device_type ON devices(device_type);

CREATE TRIGGER trigger_devices_updated_at
    BEFORE UPDATE ON devices
    FOR EACH ROW
    EXECUTE FUNCTION update_updated_at_column();

COMMENT ON TABLE devices IS 'LoRaWAN end devices (sensors/transmitters)';

-- ============================================================================
-- TABLE 7: meters
-- ============================================================================
CREATE TABLE meters (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    serial_number VARCHAR(100) NOT NULL UNIQUE,
    name VARCHAR(255) NOT NULL,
    project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
    device_id UUID REFERENCES devices(id) ON DELETE SET NULL,
    area_name VARCHAR(255),
    location TEXT,
    meter_type meter_type NOT NULL DEFAULT 'WATER',
    status device_status NOT NULL DEFAULT 'ACTIVE',
    last_reading_value NUMERIC(15, 4),
    last_reading_at TIMESTAMP WITH TIME ZONE,
    installation_date DATE,
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_meters_serial_number ON meters(serial_number);
CREATE INDEX idx_meters_project_id ON meters(project_id);
CREATE INDEX idx_meters_device_id ON meters(device_id);
CREATE INDEX idx_meters_status ON meters(status);
CREATE INDEX idx_meters_meter_type ON meters(meter_type);
CREATE INDEX idx_meters_area_name ON meters(area_name);

CREATE TRIGGER trigger_meters_updated_at
    BEFORE UPDATE ON meters
    FOR EACH ROW
    EXECUTE FUNCTION update_updated_at_column();

COMMENT ON TABLE meters IS 'Physical water meters associated with devices';

-- ============================================================================
-- TABLE 8: meter_readings
-- ============================================================================
CREATE TABLE meter_readings (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    meter_id UUID NOT NULL REFERENCES meters(id) ON DELETE CASCADE,
    device_id UUID REFERENCES devices(id) ON DELETE SET NULL,
    reading_value NUMERIC(15, 4) NOT NULL,
    reading_type reading_type NOT NULL DEFAULT 'AUTOMATIC',
    battery_level SMALLINT,
    signal_strength SMALLINT,
    raw_payload TEXT,
    received_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_meter_readings_meter_id ON meter_readings(meter_id);
CREATE INDEX idx_meter_readings_device_id ON meter_readings(device_id);
CREATE INDEX idx_meter_readings_received_at ON meter_readings(received_at);
CREATE INDEX idx_meter_readings_meter_id_received_at ON meter_readings(meter_id, received_at DESC);

COMMENT ON TABLE meter_readings IS 'Historical meter reading values';

-- ============================================================================
-- TABLE 9: tts_uplink_logs
-- ============================================================================
CREATE TABLE tts_uplink_logs (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    device_id UUID REFERENCES devices(id) ON DELETE SET NULL,
    dev_eui VARCHAR(16) NOT NULL,
    raw_payload JSONB NOT NULL,
    decoded_payload JSONB,
    gateway_ids TEXT[],
    rssi SMALLINT,
    snr NUMERIC(5, 2),
    processed BOOLEAN NOT NULL DEFAULT FALSE,
    error_message TEXT,
    received_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_tts_uplink_logs_device_id ON tts_uplink_logs(device_id);
CREATE INDEX idx_tts_uplink_logs_dev_eui ON tts_uplink_logs(dev_eui);
CREATE INDEX idx_tts_uplink_logs_received_at ON tts_uplink_logs(received_at);
CREATE INDEX idx_tts_uplink_logs_processed ON tts_uplink_logs(processed);
CREATE INDEX idx_tts_uplink_logs_raw_payload ON tts_uplink_logs USING GIN (raw_payload);

COMMENT ON TABLE tts_uplink_logs IS 'The Things Stack uplink message logs';

-- ============================================================================
-- TABLE 10: refresh_tokens
-- ============================================================================
CREATE TABLE refresh_tokens (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    token_hash VARCHAR(255) NOT NULL UNIQUE,
    expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
    revoked_at TIMESTAMP WITH TIME ZONE
);

CREATE INDEX idx_refresh_tokens_user_id ON refresh_tokens(user_id);
CREATE INDEX idx_refresh_tokens_token_hash ON refresh_tokens(token_hash);
CREATE INDEX idx_refresh_tokens_expires_at ON refresh_tokens(expires_at);

COMMENT ON TABLE refresh_tokens IS 'JWT refresh tokens for user sessions';

-- ============================================================================
-- VIEW: meter_stats_by_project
-- ============================================================================
CREATE OR REPLACE VIEW meter_stats_by_project AS
SELECT
    p.id AS project_id,
    p.name AS project_name,
    p.status AS project_status,
    COUNT(m.id) AS total_meters,
    COUNT(CASE WHEN m.status = 'ACTIVE' THEN 1 END) AS active_meters,
    COUNT(CASE WHEN m.status = 'INACTIVE' THEN 1 END) AS inactive_meters,
    COUNT(CASE WHEN m.status = 'OFFLINE' THEN 1 END) AS offline_meters,
    COUNT(CASE WHEN m.status = 'MAINTENANCE' THEN 1 END) AS maintenance_meters,
    COUNT(CASE WHEN m.status = 'ERROR' THEN 1 END) AS error_meters,
    ROUND(AVG(m.last_reading_value)::NUMERIC, 2) AS avg_last_reading,
    MAX(m.last_reading_at) AS most_recent_reading,
    COUNT(DISTINCT m.area_name) AS unique_areas
FROM projects p
LEFT JOIN meters m ON p.id = m.project_id
GROUP BY p.id, p.name, p.status;

COMMENT ON VIEW meter_stats_by_project IS 'Aggregated meter statistics per project';

-- ============================================================================
-- VIEW: device_status_summary
-- ============================================================================
CREATE OR REPLACE VIEW device_status_summary AS
SELECT
    p.id AS project_id,
    p.name AS project_name,
    'concentrator' AS device_category,
    c.status,
    COUNT(*) AS count
FROM projects p
LEFT JOIN concentrators c ON p.id = c.project_id
WHERE c.id IS NOT NULL
GROUP BY p.id, p.name, c.status

UNION ALL

SELECT
    p.id AS project_id,
    p.name AS project_name,
    'gateway' AS device_category,
    g.status,
    COUNT(*) AS count
FROM projects p
LEFT JOIN gateways g ON p.id = g.project_id
WHERE g.id IS NOT NULL
GROUP BY p.id, p.name, g.status

UNION ALL

SELECT
    p.id AS project_id,
    p.name AS project_name,
    'device' AS device_category,
    d.status,
    COUNT(*) AS count
FROM projects p
LEFT JOIN devices d ON p.id = d.project_id
WHERE d.id IS NOT NULL
GROUP BY p.id, p.name, d.status

UNION ALL

SELECT
    p.id AS project_id,
    p.name AS project_name,
    'meter' AS device_category,
    m.status,
    COUNT(*) AS count
FROM projects p
LEFT JOIN meters m ON p.id = m.project_id
WHERE m.id IS NOT NULL
GROUP BY p.id, p.name, m.status;

COMMENT ON VIEW device_status_summary IS 'Summary of device statuses across all device types per project';

-- ============================================================================
-- SEED DATA: Default Roles
-- ============================================================================
INSERT INTO roles (name, description, permissions) VALUES
(
    'ADMIN',
    'Full system administrator with all permissions',
    '{
        "users": {"create": true, "read": true, "update": true, "delete": true},
        "projects": {"create": true, "read": true, "update": true, "delete": true},
        "devices": {"create": true, "read": true, "update": true, "delete": true},
        "meters": {"create": true, "read": true, "update": true, "delete": true},
        "readings": {"create": true, "read": true, "update": true, "delete": true},
        "settings": {"create": true, "read": true, "update": true, "delete": true},
        "reports": {"create": true, "read": true, "export": true}
    }'::JSONB
),
(
    'OPERATOR',
    'Operator with management permissions but no system settings',
    '{
        "users": {"create": false, "read": true, "update": false, "delete": false},
        "projects": {"create": true, "read": true, "update": true, "delete": false},
        "devices": {"create": true, "read": true, "update": true, "delete": false},
        "meters": {"create": true, "read": true, "update": true, "delete": false},
        "readings": {"create": true, "read": true, "update": false, "delete": false},
        "settings": {"create": false, "read": true, "update": false, "delete": false},
        "reports": {"create": true, "read": true, "export": true}
    }'::JSONB
),
(
    'VIEWER',
    'Read-only access to view data and reports',
    '{
        "users": {"create": false, "read": false, "update": false, "delete": false},
        "projects": {"create": false, "read": true, "update": false, "delete": false},
        "devices": {"create": false, "read": true, "update": false, "delete": false},
        "meters": {"create": false, "read": true, "update": false, "delete": false},
        "readings": {"create": false, "read": true, "update": false, "delete": false},
        "settings": {"create": false, "read": false, "update": false, "delete": false},
        "reports": {"create": false, "read": true, "export": false}
    }'::JSONB
);

-- ============================================================================
-- SEED DATA: Default Admin User
-- Password: [REDACTED] (bcrypt hashed)
-- ============================================================================
INSERT INTO users (email, password_hash, name, role_id, is_active)
SELECT
    'admin@waterproject.com',
    '$2b$12$RrlEdRsUiiQYxtUmjOjX.uZU/IpXUFsXsWxDcMny1RUl6RFc.etDm',
    'System Administrator',
    r.id,
    TRUE
FROM roles r
WHERE r.name = 'ADMIN';

-- ============================================================================
-- END OF SCHEMA
-- ============================================================================
