-- M9 P3: agent node registry and heartbeat metadata.
-- Node tokens are stored as SHA-256 digests and are only returned at create /
-- rotation time. Heartbeat payloads are bounded metadata, not task content.

CREATE TABLE IF NOT EXISTS gateway.agent_nodes (
    id uuid PRIMARY KEY,
    code text NOT NULL UNIQUE CHECK (length(code) BETWEEN 1 AND 128),
    name text NOT NULL CHECK (length(name) BETWEEN 1 AND 128),
    description text NOT NULL DEFAULT '' CHECK (length(description) <= 4000),
    endpoint text NOT NULL DEFAULT '' CHECK (length(endpoint) <= 512),
    node_type text NOT NULL DEFAULT 'worker' CHECK (node_type IN ('worker', 'gateway', 'executor')),
    pool_type text NOT NULL DEFAULT 'private' CHECK (pool_type IN ('public', 'private')),
    pool_code text NOT NULL DEFAULT 'default' CHECK (length(pool_code) BETWEEN 1 AND 64),
    enabled boolean NOT NULL DEFAULT true,
    token_prefix text NOT NULL CHECK (length(token_prefix) BETWEEN 4 AND 32),
    token_hash bytea NOT NULL CHECK (octet_length(token_hash) = 32),
    version text NOT NULL DEFAULT '' CHECK (length(version) <= 128),
    capabilities jsonb NOT NULL DEFAULT '{}'::jsonb CHECK (jsonb_typeof(capabilities) = 'object'),
    metadata jsonb NOT NULL DEFAULT '{}'::jsonb CHECK (jsonb_typeof(metadata) = 'object'),
    last_heartbeat_at timestamptz,
    last_heartbeat_ip inet,
    last_error text NOT NULL DEFAULT '' CHECK (length(last_error) <= 4000),
    created_by uuid REFERENCES gateway.admin_accounts(id),
    created_at timestamptz NOT NULL DEFAULT clock_timestamp(),
    updated_at timestamptz NOT NULL DEFAULT clock_timestamp()
);

CREATE INDEX IF NOT EXISTS agent_nodes_pool_idx
    ON gateway.agent_nodes (pool_type, pool_code, enabled, updated_at DESC);
CREATE INDEX IF NOT EXISTS agent_nodes_heartbeat_idx
    ON gateway.agent_nodes (last_heartbeat_at DESC NULLS LAST, enabled);
