CREATE TABLE IF NOT EXISTS schema_version (
    version INTEGER NOT NULL
);

CREATE TABLE IF NOT EXISTS server_config (
    id                  INTEGER PRIMARY KEY CHECK (id = 1),
    signing_key_enc     BLOB,
    signing_key_nonce   BLOB,
    created_at          TEXT    NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ','now')),
    updated_at          TEXT    NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ','now'))
);

CREATE TABLE IF NOT EXISTS accounts (
    id                  INTEGER PRIMARY KEY,
    uuid                TEXT    NOT NULL UNIQUE,
    username            TEXT    NOT NULL UNIQUE COLLATE NOCASE,
    account_type        TEXT    NOT NULL CHECK (account_type IN ('human','system')),
    password_hash       TEXT,
    status              TEXT    NOT NULL DEFAULT 'active'
                                CHECK (status IN ('active','inactive','deleted')),
    totp_required       INTEGER NOT NULL DEFAULT 0 CHECK (totp_required IN (0,1)),
    totp_secret_enc     BLOB,
    totp_secret_nonce   BLOB,
    created_at          TEXT    NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ','now')),
    updated_at          TEXT    NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ','now')),
    deleted_at          TEXT
);

CREATE INDEX IF NOT EXISTS idx_accounts_username ON accounts (username);
CREATE INDEX IF NOT EXISTS idx_accounts_uuid     ON accounts (uuid);
CREATE INDEX IF NOT EXISTS idx_accounts_status   ON accounts (status);

CREATE TABLE IF NOT EXISTS account_roles (
    id          INTEGER PRIMARY KEY,
    account_id  INTEGER NOT NULL REFERENCES accounts(id) ON DELETE CASCADE,
    role        TEXT    NOT NULL,
    granted_by  INTEGER REFERENCES accounts(id),
    granted_at  TEXT    NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ','now')),
    UNIQUE (account_id, role)
);

CREATE INDEX IF NOT EXISTS idx_account_roles_account ON account_roles (account_id);

CREATE TABLE IF NOT EXISTS token_revocation (
    id            INTEGER PRIMARY KEY,
    jti           TEXT    NOT NULL UNIQUE,
    account_id    INTEGER NOT NULL REFERENCES accounts(id) ON DELETE CASCADE,
    expires_at    TEXT    NOT NULL,
    revoked_at    TEXT,
    revoke_reason TEXT,
    issued_at     TEXT    NOT NULL,
    created_at    TEXT    NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ','now'))
);

CREATE INDEX IF NOT EXISTS idx_token_jti     ON token_revocation (jti);
CREATE INDEX IF NOT EXISTS idx_token_account ON token_revocation (account_id);
CREATE INDEX IF NOT EXISTS idx_token_expires ON token_revocation (expires_at);

CREATE TABLE IF NOT EXISTS system_tokens (
    id          INTEGER PRIMARY KEY,
    account_id  INTEGER NOT NULL UNIQUE REFERENCES accounts(id) ON DELETE CASCADE,
    jti         TEXT    NOT NULL UNIQUE,
    expires_at  TEXT    NOT NULL,
    created_at  TEXT    NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ','now'))
);

CREATE TABLE IF NOT EXISTS pg_credentials (
    id                  INTEGER PRIMARY KEY,
    account_id          INTEGER NOT NULL UNIQUE REFERENCES accounts(id) ON DELETE CASCADE,
    pg_host             TEXT    NOT NULL,
    pg_port             INTEGER NOT NULL DEFAULT 5432,
    pg_database         TEXT    NOT NULL,
    pg_username         TEXT    NOT NULL,
    pg_password_enc     BLOB    NOT NULL,
    pg_password_nonce   BLOB    NOT NULL,
    created_at          TEXT    NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ','now')),
    updated_at          TEXT    NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ','now'))
);

CREATE TABLE IF NOT EXISTS audit_log (
    id          INTEGER PRIMARY KEY,
    event_time  TEXT    NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ','now')),
    event_type  TEXT    NOT NULL,
    actor_id    INTEGER REFERENCES accounts(id),
    target_id   INTEGER REFERENCES accounts(id),
    ip_address  TEXT,
    details     TEXT
);

CREATE INDEX IF NOT EXISTS idx_audit_time  ON audit_log (event_time);
CREATE INDEX IF NOT EXISTS idx_audit_actor ON audit_log (actor_id);
CREATE INDEX IF NOT EXISTS idx_audit_event ON audit_log (event_type);
