-- IHF Phase 9 — External API Surface and Consumer SDKs
-- IHUB-WP-0010-T01: api_consumers, api_keys, webhook_subscriptions,
--                   webhook_deliveries, api_request_log

-- api_consumers: external systems that authenticate against /api/v2/
-- hub_capability_manifest_id is set when the consumer is a domain hub;
-- NULL for third-party tools that authenticate without a manifest.
CREATE TABLE api_consumers (
    id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
    name TEXT NOT NULL,
    description TEXT,
    hub_capability_manifest_id UUID REFERENCES hub_capability_manifests(id),
    rate_limit_per_minute INTEGER NOT NULL DEFAULT 60,
    quota_per_day INTEGER NOT NULL DEFAULT 10000,
    quota_resets_at TIMESTAMP WITH TIME ZONE NOT NULL
        DEFAULT (date_trunc('day', NOW() AT TIME ZONE 'UTC') + interval '1 day'),
    is_active BOOLEAN NOT NULL DEFAULT TRUE,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL
);

CREATE INDEX api_consumers_manifest_idx ON api_consumers (hub_capability_manifest_id);

-- api_keys: bearer tokens for consumer authentication
-- key_hash stores SHA-256 hex of the full key; key_prefix (first 8 hex chars)
-- is shown in UI for identification. The full key is never stored.
-- token_type: 'static' for admin-created keys, 'oauth' for tokens from /api/v2/token
CREATE TABLE api_keys (
    id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
    api_consumer_id UUID NOT NULL REFERENCES api_consumers(id) ON DELETE CASCADE,
    key_prefix TEXT NOT NULL,
    key_hash TEXT NOT NULL,
    scopes TEXT NOT NULL DEFAULT '',
    token_type TEXT NOT NULL DEFAULT 'static'
        CHECK (token_type IN ('static', 'oauth')),
    expires_at TIMESTAMP WITH TIME ZONE,
    revoked_at TIMESTAMP WITH TIME ZONE,
    last_used_at TIMESTAMP WITH TIME ZONE,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL
);

CREATE UNIQUE INDEX api_keys_prefix_idx ON api_keys (key_prefix);
CREATE INDEX api_keys_consumer_idx ON api_keys (api_consumer_id);
CREATE INDEX api_keys_hash_idx ON api_keys (key_hash);

-- webhook_subscriptions: consumer subscriptions to framework lifecycle events.
-- event_topic uses framework-level event names (distinct from widget interaction
-- event_type_registry which stores user interaction types like 'clicked', 'viewed').
CREATE TABLE webhook_subscriptions (
    id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
    api_consumer_id UUID NOT NULL REFERENCES api_consumers(id) ON DELETE CASCADE,
    event_type TEXT NOT NULL CHECK (event_type IN (
        'interaction_event.created',
        'annotation.created',
        'requirement_candidate.created',
        'decision_record.created',
        'deployment_record.created',
        'outcome_signal.created'
    )),
    target_url TEXT NOT NULL,
    secret TEXT NOT NULL,
    is_active BOOLEAN NOT NULL DEFAULT TRUE,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL
);

CREATE INDEX webhook_subs_consumer_idx ON webhook_subscriptions (api_consumer_id);
CREATE INDEX webhook_subs_event_type_idx ON webhook_subscriptions (event_type);

-- webhook_deliveries: delivery attempt log (append-only)
CREATE TABLE webhook_deliveries (
    id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
    webhook_subscription_id UUID NOT NULL REFERENCES webhook_subscriptions(id),
    payload JSONB NOT NULL,
    attempted_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,
    status TEXT NOT NULL CHECK (status IN ('pending', 'delivered', 'failed')),
    response_code INTEGER,
    latency_ms INTEGER,
    error_message TEXT
);

CREATE INDEX webhook_deliveries_sub_idx
    ON webhook_deliveries (webhook_subscription_id, attempted_at DESC);

-- Append-only trigger for webhook_deliveries
CREATE OR REPLACE FUNCTION webhook_deliveries_no_update()
    RETURNS TRIGGER LANGUAGE plpgsql AS $$
BEGIN
    RAISE EXCEPTION 'webhook_deliveries is append-only';
END; $$;
CREATE TRIGGER webhook_deliveries_no_update
    BEFORE UPDATE ON webhook_deliveries
    FOR EACH ROW EXECUTE FUNCTION webhook_deliveries_no_update();

CREATE OR REPLACE FUNCTION webhook_deliveries_no_delete()
    RETURNS TRIGGER LANGUAGE plpgsql AS $$
BEGIN
    RAISE EXCEPTION 'webhook_deliveries is append-only';
END; $$;
CREATE TRIGGER webhook_deliveries_no_delete
    BEFORE DELETE ON webhook_deliveries
    FOR EACH ROW EXECUTE FUNCTION webhook_deliveries_no_delete();

-- api_request_log: usage tracking for dashboard and rate limiting
CREATE TABLE api_request_log (
    id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
    api_consumer_id UUID REFERENCES api_consumers(id),
    endpoint TEXT NOT NULL,
    method TEXT NOT NULL,
    status_code INTEGER NOT NULL,
    latency_ms INTEGER,
    requested_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL
);

CREATE INDEX api_request_log_consumer_time_idx
    ON api_request_log (api_consumer_id, requested_at DESC);
