CREATE TABLE IF NOT EXISTS gateway.departments (
    id uuid PRIMARY KEY,
    tenant_id uuid,
    code text NOT NULL,
    name text NOT NULL,
    active boolean NOT NULL DEFAULT true,
    created_at timestamptz NOT NULL DEFAULT clock_timestamp(),
    updated_at timestamptz NOT NULL DEFAULT clock_timestamp(),
    UNIQUE NULLS NOT DISTINCT (tenant_id, code)
);

CREATE TABLE IF NOT EXISTS gateway.admin_accounts (
    id uuid PRIMARY KEY,
    username varchar(64) NOT NULL,
    password_hash text NOT NULL,
    display_name varchar(64) NOT NULL DEFAULT '',
    role varchar(24) NOT NULL DEFAULT 'operator'
        CHECK (role IN ('superadmin', 'operator', 'auditor')),
    active boolean NOT NULL DEFAULT true,
    failed_logins integer NOT NULL DEFAULT 0 CHECK (failed_logins >= 0),
    locked_until timestamptz,
    last_login timestamptz,
    encrypted_totp_secret bytea,
    totp_kek_version integer,
    totp_enabled boolean NOT NULL DEFAULT false,
    totp_last_step bigint,
    totp_backup_codes jsonb NOT NULL DEFAULT '[]'::jsonb,
    totp_confirmed_at timestamptz,
    created_at timestamptz NOT NULL DEFAULT clock_timestamp(),
    updated_at timestamptz NOT NULL DEFAULT clock_timestamp()
);

CREATE UNIQUE INDEX IF NOT EXISTS admin_accounts_username_lower_idx
    ON gateway.admin_accounts (lower(username));

CREATE TABLE IF NOT EXISTS gateway.portal_users (
    id uuid PRIMARY KEY,
    tenant_id uuid,
    account varchar(128) NOT NULL,
    name varchar(64) NOT NULL DEFAULT '',
    department_id uuid REFERENCES gateway.departments(id),
    password_hash text,
    auth_source varchar(24) NOT NULL DEFAULT 'local'
        CHECK (auth_source IN ('local', 'feishu', 'oidc', 'saml')),
    external_subject text,
    active boolean NOT NULL DEFAULT true,
    provisioning_status varchar(24) NOT NULL DEFAULT 'active'
        CHECK (provisioning_status IN ('active', 'pending', 'rejected')),
    failed_logins integer NOT NULL DEFAULT 0 CHECK (failed_logins >= 0),
    locked_until timestamptz,
    last_login timestamptz,
    encrypted_totp_secret bytea,
    totp_kek_version integer,
    totp_enabled boolean NOT NULL DEFAULT false,
    totp_last_step bigint,
    totp_backup_codes jsonb NOT NULL DEFAULT '[]'::jsonb,
    totp_confirmed_at timestamptz,
    deleted_name_snapshot varchar(128) NOT NULL DEFAULT '',
    created_at timestamptz NOT NULL DEFAULT clock_timestamp(),
    updated_at timestamptz NOT NULL DEFAULT clock_timestamp()
);

CREATE UNIQUE INDEX IF NOT EXISTS portal_users_account_lower_idx
    ON gateway.portal_users (lower(account));
CREATE INDEX IF NOT EXISTS portal_users_department_idx
    ON gateway.portal_users (department_id, active);
CREATE UNIQUE INDEX IF NOT EXISTS portal_users_external_subject_idx
    ON gateway.portal_users (auth_source, external_subject)
    WHERE external_subject IS NOT NULL;

ALTER TABLE gateway.api_keys
    ADD COLUMN IF NOT EXISTS user_id uuid REFERENCES gateway.portal_users(id),
    ADD COLUMN IF NOT EXISTS department_id uuid REFERENCES gateway.departments(id);

ALTER TABLE gateway.providers
    ADD COLUMN IF NOT EXISTS created_by uuid REFERENCES gateway.admin_accounts(id);

COMMENT ON COLUMN gateway.admin_accounts.password_hash IS
    'PBKDF2-SHA256 self-describing hash; compatible with the Python gateway format.';
COMMENT ON TABLE gateway.portal_users IS
    'Portal identities. Runtime API keys remain separate credentials.';

