-- PDS database schema (initial)

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pgcrypto";

-- =====================================================
-- users
-- =====================================================
CREATE TABLE users (
    did            TEXT PRIMARY KEY,                     -- did:plc:...
    handle         TEXT NOT NULL UNIQUE,                 -- alice.maarcadetweet.local
    email          TEXT,                                 -- nullable for did:web
    password_hash  TEXT,                                 -- argon2id; nullable
    signing_key    BYTEA NOT NULL,                       -- compressed secp256k1 pubkey
    rotation_key   BYTEA NOT NULL,                       -- for PLC rotation ops
    created_at     TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at     TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX users_handle_idx ON users (LOWER(handle));

-- =====================================================
-- repos
-- =====================================================
CREATE TABLE repos (
    did            TEXT PRIMARY KEY REFERENCES users(did) ON DELETE CASCADE,
    rev            TEXT NOT NULL,                        -- TID-encoded revision counter
    head_cid       BYTEA NOT NULL,                       -- CID of latest commit
    head_commit    BYTEA NOT NULL,                       -- CBOR block of latest commit
    prev_commit    BYTEA,                                -- for fast linear back-link
    indexed_at     TIMESTAMPTZ NOT NULL DEFAULT now()
);

-- =====================================================
-- repo blocks (MST nodes + records)
-- =====================================================
CREATE TABLE repo_blocks (
    did            TEXT NOT NULL,
    cid            BYTEA NOT NULL,
    block          BYTEA NOT NULL,
    size           INTEGER NOT NULL,
    created_at     TIMESTAMPTZ NOT NULL DEFAULT now(),
    PRIMARY KEY (did, cid)
);
CREATE INDEX repo_blocks_did_idx ON repo_blocks (did);

-- =====================================================
-- blobs
-- =====================================================
CREATE TABLE blobs (
    cid            TEXT PRIMARY KEY,                     -- bafy...
    did            TEXT NOT NULL,
    mime_type      TEXT NOT NULL,
    size           BIGINT NOT NULL,
    storage_key    TEXT NOT NULL,                        -- S3 object key
    created_at     TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX blobs_did_idx ON blobs (did);

-- =====================================================
-- sessions
-- =====================================================
CREATE TABLE sessions (
    id             UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    did            TEXT NOT NULL REFERENCES users(did) ON DELETE CASCADE,
    access_jwt     TEXT NOT NULL,                        -- ES256K signed
    refresh_jwt    TEXT NOT NULL,                        -- ES256 signed (different key)
    access_expires_at  TIMESTAMPTZ NOT NULL,
    refresh_expires_at TIMESTAMPTZ NOT NULL,
    created_at     TIMESTAMPTZ NOT NULL DEFAULT now(),
    revoked_at     TIMESTAMPTZ
);
CREATE INDEX sessions_did_idx ON sessions (did);

-- =====================================================
-- plc operations (audit log of submitted ops)
-- =====================================================
CREATE TABLE plc_ops (
    id             BIGSERIAL PRIMARY KEY,
    did            TEXT NOT NULL,
    prev           TEXT,                                 -- CID of previous op, or null for create
    op_cid         TEXT NOT NULL,
    signed_op      BYTEA NOT NULL,                       -- DAG-CBOR
    submitted      BOOLEAN NOT NULL DEFAULT FALSE,
    created_at     TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX plc_ops_did_idx ON plc_ops (did);

-- =====================================================
-- update trigger for users.updated_at
-- =====================================================
CREATE OR REPLACE FUNCTION touch_updated_at() RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = now();
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER users_touch BEFORE UPDATE ON users
    FOR EACH ROW EXECUTE FUNCTION touch_updated_at();
