-- Append-only audit log. One database == one organization, so there is no org_id.
CREATE TABLE audit_log (
    seq         BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    at          TIMESTAMPTZ NOT NULL DEFAULT now(),
    actor_kind  TEXT  NOT NULL CHECK (actor_kind IN ('user', 'system')),
    actor_id    UUID,
    action      TEXT  NOT NULL CHECK (action IN ('created', 'updated', 'deleted')),
    entity_type TEXT  NOT NULL,
    entity_id   UUID  NOT NULL,
    changes     JSONB NOT NULL DEFAULT '[]'::jsonb,
    CONSTRAINT actor_id_matches_kind CHECK (
        (actor_kind = 'user'   AND actor_id IS NOT NULL) OR
        (actor_kind = 'system' AND actor_id IS NULL)
    )
);

CREATE INDEX audit_log_entity_idx ON audit_log (entity_type, entity_id, seq);

-- Enforce append-only at the database level: reject any UPDATE or DELETE.
CREATE OR REPLACE FUNCTION audit_log_reject_mutation() RETURNS trigger AS $$
BEGIN
    RAISE EXCEPTION 'audit_log is append-only; % is not permitted', TG_OP;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER audit_log_immutable
    BEFORE UPDATE OR DELETE ON audit_log
    FOR EACH ROW EXECUTE FUNCTION audit_log_reject_mutation();

CREATE TRIGGER audit_log_no_truncate
    BEFORE TRUNCATE ON audit_log
    FOR EACH STATEMENT EXECUTE FUNCTION audit_log_reject_mutation();
