-- Portable schema for Direct-mode (non-stored-procedure) operation.
-- Plain CREATE TABLE statements only, no functions/triggers, using types
-- understood by SQLite (and portable to MySQL). Used by Direct-mode tests
-- and as a reference for deployments without Postgres.

CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    username VARCHAR(255) NOT NULL UNIQUE,
    email VARCHAR(255) NOT NULL UNIQUE,
    password VARCHAR(255),
    user_level INTEGER DEFAULT 0,
    roles VARCHAR(500),
    is_active BOOLEAN DEFAULT 1,
    created_at TIMESTAMP,
    updated_at TIMESTAMP,
    last_login_at TIMESTAMP,
    program_user_id INTEGER DEFAULT 0,
    program_user_table VARCHAR(255) DEFAULT '',
    remote_id VARCHAR(255),
    auth_provider VARCHAR(50),
    totp_secret VARCHAR(255),
    totp_enabled BOOLEAN DEFAULT 0,
    totp_enabled_at TIMESTAMP
);

CREATE TABLE IF NOT EXISTS user_sessions (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    session_token VARCHAR(500) NOT NULL UNIQUE,
    user_id INTEGER NOT NULL,
    expires_at TIMESTAMP NOT NULL,
    created_at TIMESTAMP,
    last_activity_at TIMESTAMP,
    ip_address VARCHAR(45),
    user_agent TEXT,
    access_token TEXT,
    refresh_token TEXT,
    token_type VARCHAR(50) DEFAULT 'Bearer',
    auth_provider VARCHAR(50)
);

CREATE INDEX IF NOT EXISTS idx_session_token ON user_sessions(session_token);
CREATE INDEX IF NOT EXISTS idx_user_id ON user_sessions(user_id);
CREATE INDEX IF NOT EXISTS idx_expires_at ON user_sessions(expires_at);
CREATE INDEX IF NOT EXISTS idx_refresh_token ON user_sessions(refresh_token);

CREATE TABLE IF NOT EXISTS token_blacklist (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    token VARCHAR(500) NOT NULL,
    user_id INTEGER,
    expires_at TIMESTAMP NOT NULL,
    created_at TIMESTAMP
);

CREATE TABLE IF NOT EXISTS user_totp_backup_codes (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id INTEGER NOT NULL,
    code_hash VARCHAR(64) NOT NULL,
    used BOOLEAN DEFAULT 0,
    used_at TIMESTAMP,
    created_at TIMESTAMP
);

CREATE INDEX IF NOT EXISTS idx_totp_user_id ON user_totp_backup_codes(user_id);
CREATE INDEX IF NOT EXISTS idx_totp_code_hash ON user_totp_backup_codes(code_hash);

CREATE TABLE IF NOT EXISTS user_passkey_credentials (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id INTEGER NOT NULL,
    credential_id TEXT NOT NULL UNIQUE, -- base64 text (Direct mode), not native bytea
    public_key TEXT NOT NULL,           -- base64 text
    attestation_type VARCHAR(50) DEFAULT 'none',
    aaguid TEXT,                        -- base64 text
    sign_count INTEGER DEFAULT 0,
    clone_warning BOOLEAN DEFAULT 0,
    transports TEXT,                    -- JSON-encoded []string
    backup_eligible BOOLEAN DEFAULT 0,
    backup_state BOOLEAN DEFAULT 0,
    name VARCHAR(255),
    created_at TIMESTAMP,
    last_used_at TIMESTAMP
);

CREATE INDEX IF NOT EXISTS idx_passkey_user_id ON user_passkey_credentials(user_id);
CREATE INDEX IF NOT EXISTS idx_passkey_credential_id ON user_passkey_credentials(credential_id);

CREATE TABLE IF NOT EXISTS user_password_resets (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id INTEGER NOT NULL,
    token_hash VARCHAR(64) NOT NULL UNIQUE,
    expires_at TIMESTAMP NOT NULL,
    created_at TIMESTAMP,
    used BOOLEAN DEFAULT 0,
    used_at TIMESTAMP
);

CREATE TABLE IF NOT EXISTS oauth_clients (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    client_id VARCHAR(255) NOT NULL UNIQUE,
    redirect_uris TEXT NOT NULL,   -- JSON-encoded []string
    client_name VARCHAR(255),
    grant_types TEXT,              -- JSON-encoded []string
    allowed_scopes TEXT,           -- JSON-encoded []string
    client_secret_hash TEXT,       -- sha256 hex of the confidential-client secret; NULL for public clients
    token_endpoint_auth_method VARCHAR(30) DEFAULT 'none',
    is_active BOOLEAN DEFAULT 1,
    created_at TIMESTAMP
);

CREATE TABLE IF NOT EXISTS oauth_codes (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    code VARCHAR(255) NOT NULL UNIQUE,
    client_id VARCHAR(255) NOT NULL,
    redirect_uri TEXT NOT NULL,
    client_state TEXT,
    code_challenge VARCHAR(255) NOT NULL,
    code_challenge_method VARCHAR(10) DEFAULT 'S256',
    session_token TEXT NOT NULL,
    refresh_token TEXT,
    scopes TEXT,                   -- JSON-encoded []string
    expires_at TIMESTAMP NOT NULL,
    created_at TIMESTAMP
);

CREATE INDEX IF NOT EXISTS idx_oauth_codes_code ON oauth_codes(code);
CREATE INDEX IF NOT EXISTS idx_oauth_codes_expires ON oauth_codes(expires_at);

CREATE TABLE IF NOT EXISTS user_keys (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id INTEGER NOT NULL,
    key_type VARCHAR(50) NOT NULL,
    key_hash VARCHAR(64) NOT NULL UNIQUE,
    name VARCHAR(255) NOT NULL DEFAULT '',
    scopes TEXT,                   -- JSON-encoded []string
    meta TEXT,                     -- JSON-encoded map
    expires_at TIMESTAMP,
    created_at TIMESTAMP,
    last_used_at TIMESTAMP,
    is_active BOOLEAN DEFAULT 1
);

CREATE INDEX IF NOT EXISTS idx_user_keys_user_id  ON user_keys(user_id);
CREATE INDEX IF NOT EXISTS idx_user_keys_key_hash ON user_keys(key_hash);
CREATE INDEX IF NOT EXISTS idx_user_keys_key_type ON user_keys(key_type);
