CREATE TABLE users (
    id          BLOB NOT NULL UNIQUE PRIMARY KEY, -- UUIDv7 as bytes
    handle      TEXT NOT NULL UNIQUE COLLATE NOCASE,
    password    TEXT, -- hashed, nullable in case of OAuth2-only login
    prof_pic    TEXT  -- serialized ProfilePic
);
CREATE TABLE sessions (
    id          BLOB NOT NULL UNIQUE PRIMARY KEY, -- UUIDv7 as bytes
    token       BLOB NOT NULL UNIQUE,
    user_id     BLOB NOT NULL REFERENCES users(id), -- UUIDv7 bytes (userID)
    expiry      TEXT NOT NULL, -- RFC3339 into DateTime<Utc>
    revoked     INTEGER NOT NULL DEFAULT 0, -- bool (int 0 or int 1)
    revoked_at  TEXT DEFAULT NULL, -- RFC3339 into DateTime<Utc>
    revoked_by  BLOB DEFAULT NULL REFERENCES users(id)  -- UUIDv7 bytes (userID)

    CHECK(
        (revoked = 0 AND revoked_at IS NULL AND revoked_by IS NULL) OR
        (revoked = 1 AND revoked_at IS NOT NULL AND revoked_by IS NOT NULL)
    )
);
CREATE INDEX sessions_by_userid ON sessions(user_id);
CREATE TABLE user_permissions (
    user_id     BLOB NOT NULL REFERENCES users(id), -- UUIDv7 as bytes
    permission  TEXT NOT NULL, -- serialized name
    PRIMARY KEY (user_id, permission)
) WITHOUT ROWID;

CREATE TABLE quotes (
    id          BLOB NOT NULL UNIQUE PRIMARY KEY, -- UUIDv7 as bytes
    timestamp   TEXT NOT NULL, -- RFC3339 into DateTime<FixedOffset>
    location    TEXT,
    context     TEXT,
    created_by  BLOB NOT NULL REFERENCES users(id), -- UUIDv7 as bytes
    public      INTEGER NOT NULL DEFAULT 0 -- bool (int 0 or int 1)
    -- this is to be followed by a bigger role-based viewership scoping mechanism
);
CREATE INDEX quotes_by_creation_user ON quotes(created_by);
CREATE TABLE persons (
    id          BLOB NOT NULL UNIQUE PRIMARY KEY, -- UUIDv7 as bytes
    created_by  BLOB NOT NULL REFERENCES users(id), -- UUIDv7 as bytes
    bio         TEXT,
    prof_pic    TEXT -- link probably
);
CREATE TABLE names (
    id          BLOB NOT NULL UNIQUE PRIMARY KEY, -- UUIDv7 as bytes
    is_primary  INTEGER NOT NULL DEFAULT 0,
    person_id   BLOB NOT NULL REFERENCES persons(id),
    created_by  BLOB NOT NULL REFERENCES users(id),
    name        TEXT NOT NULL
);
CREATE INDEX names_by_personid ON names(person_id);
CREATE UNIQUE INDEX no_name_duplicate_for_same_person ON names(person_id, name);
CREATE UNIQUE INDEX primary_name_uniqueness ON names(person_id) WHERE is_primary = 1;
CREATE TABLE lines (
    id          BLOB NOT NULL UNIQUE PRIMARY KEY, -- UUIDv7 as bytes
    quote_id    BLOB NOT NULL REFERENCES quotes(id), -- UUIDv7 as bytes
    name_id     BLOB NOT NULL REFERENCES names(id), -- UUIDv7 as bytes
    ordering    INTEGER NOT NULL,
    content     TEXT NOT NULL
);
CREATE INDEX lines_by_quoteid ON lines(quote_id);
CREATE INDEX lines_by_nameid ON lines(name_id);
CREATE UNIQUE INDEX lines_unique_ordering ON lines(quote_id, ordering);

CREATE TABLE tags (
    id          BLOB NOT NULL UNIQUE PRIMARY KEY, -- UUIDv7 as bytes
    tagname     TEXT NOT NULL UNIQUE COLLATE NOCASE
);

CREATE TABLE user_quote_likes (
    quote_id    BLOB NOT NULL REFERENCES quotes(id), -- UUIDv7 as bytes
    user_id     BLOB NOT NULL REFERENCES users(id), -- UUIDv7 as bytes
    PRIMARY KEY (quote_id, user_id)
) WITHOUT ROWID;
CREATE INDEX likes_by_reverse_index ON user_quote_likes(user_id, quote_id);

CREATE TABLE quote_tags (
    quote_id    BLOB NOT NULL REFERENCES quotes(id), -- UUIDv7 as bytes
    tag_id      BLOB NOT NULL REFERENCES tags(id), -- UUIDv7 as bytes
    PRIMARY KEY (quote_id, tag_id)
) WITHOUT ROWID;
CREATE INDEX quote_tags_reverse_index ON quote_tags(tag_id, quote_id);

CREATE TABLE logs (
    id          BLOB NOT NULL UNIQUE PRIMARY KEY, -- UUIDv7 as bytes
    actor       BLOB NOT NULL REFERENCES users(id), -- UUIDv7 as bytes
    -- (userID with special cases: UUID::nil if system, UUID::max if infradmin)
    -- ((infradmin & system shall both be users))
    target      BLOB, -- Option<UUIDv7 as bytes (userID)>
    actiontype  TEXT NOT NULL,
    payload     TEXT
);
CREATE INDEX logs_by_actor ON logs(actor);
CREATE INDEX logs_by_target ON logs(target);

-- all this to be followed by:
-- - a better access scoping mechanism (role-based like discord)
-- - photos just like quotes
-- - OAuth2 login via Steam/GitHub/Discord/Google/Potato/Whatever
-- - comments
