-- IHF Phase 1 Schema
-- Hub, Widget, WidgetVersion, InteractionEvent, Annotation
-- See workplans/IHUB-WP-0001-ihf-phase1-minimal-interaction-core.md

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

-- Users (T10 — authentication)
CREATE TABLE users (
    id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
    email TEXT NOT NULL UNIQUE,
    password_hash TEXT NOT NULL,
    name TEXT NOT NULL,
    locked_at TIMESTAMP WITH TIME ZONE DEFAULT NULL,
    failed_login_attempts INT NOT NULL DEFAULT 0,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
);

-- Hubs — bounded domains of responsibility
CREATE TABLE hubs (
    id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
    slug TEXT NOT NULL UNIQUE,
    name TEXT NOT NULL,
    domain TEXT NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
);

-- Widgets — smallest semantically governable interaction units
CREATE TABLE widgets (
    id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
    hub_id UUID NOT NULL REFERENCES hubs(id) ON DELETE RESTRICT,
    name TEXT NOT NULL,
    widget_type TEXT NOT NULL,
    capability_ref TEXT,
    view_context TEXT,
    policy_scope TEXT NOT NULL DEFAULT 'internal',
    status TEXT NOT NULL DEFAULT 'active',
    version INT NOT NULL DEFAULT 1,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
);

-- Widget version history
CREATE TABLE widget_versions (
    id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
    widget_id UUID NOT NULL REFERENCES widgets(id) ON DELETE CASCADE,
    version INT NOT NULL,
    schema_snapshot JSONB NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL,
    UNIQUE (widget_id, version)
);

-- Interaction events — append-only capture
CREATE TABLE interaction_events (
    id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
    widget_id UUID NOT NULL REFERENCES widgets(id) ON DELETE CASCADE,
    event_type TEXT NOT NULL,
    actor_id UUID,
    actor_type TEXT NOT NULL DEFAULT 'user',
    view_context_ref TEXT,
    metadata JSONB DEFAULT '{}' NOT NULL,
    occurred_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
);

CREATE INDEX interaction_events_widget_id_idx ON interaction_events (widget_id);
CREATE INDEX interaction_events_occurred_at_idx ON interaction_events (occurred_at DESC);

-- Enforce append-only on interaction_events
CREATE OR REPLACE FUNCTION prevent_interaction_event_mutation()
RETURNS TRIGGER AS $$
BEGIN
    RAISE EXCEPTION 'interaction_events is append-only: UPDATE and DELETE are not permitted';
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER interaction_events_no_update
    BEFORE UPDATE ON interaction_events
    FOR EACH ROW EXECUTE FUNCTION prevent_interaction_event_mutation();

CREATE TRIGGER interaction_events_no_delete
    BEFORE DELETE ON interaction_events
    FOR EACH ROW EXECUTE FUNCTION prevent_interaction_event_mutation();

-- Annotations — structured commentary, also append-only by convention
CREATE TABLE annotations (
    id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
    widget_id UUID NOT NULL REFERENCES widgets(id) ON DELETE CASCADE,
    parent_id UUID REFERENCES annotations(id) ON DELETE CASCADE,
    body TEXT NOT NULL,
    category TEXT NOT NULL DEFAULT 'friction',
    actor_id UUID,
    actor_type TEXT NOT NULL DEFAULT 'user',
    widget_state_ref TEXT,
    retracted_at TIMESTAMP WITH TIME ZONE DEFAULT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
);

CREATE INDEX annotations_widget_id_idx ON annotations (widget_id);
