-- Agreements
-- DROP TABLE IF EXISTS public.agreement CASCADE;
CREATE TABLE public.agreement (
    id                  BIGSERIAL PRIMARY KEY,
    user_id             BIGINT REFERENCES public.user(id),
    version             SMALLINT NOT NULL,
    parent              TEXT NOT NULL,
    agreement_id_uuid   UUID UNIQUE NOT NULL,
    created             BIGINT NOT NULL,
    created_as_ts       TIMESTAMPTZ NOT NULL,
    created_ts          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_ts          TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx__public__agreement__user_id           ON public.agreement (user_id);
CREATE INDEX idx__public__agreement__version           ON public.agreement (version);
CREATE INDEX idx__public__agreement__parent            ON public.agreement (parent);
CREATE INDEX idx__public__agreement__agreement_id_uuid ON public.agreement (agreement_id_uuid);
CREATE INDEX idx__public__agreement__created           ON public.agreement (created);
CREATE INDEX idx__public__agreement__created_as_ts     ON public.agreement (created_as_ts);
CREATE INDEX idx__public__agreement__created_ts        ON public.agreement (created_ts);
CREATE INDEX idx__public__agreement__updated_ts        ON public.agreement (updated_ts);

-- DROP TABLE IF EXISTS public.agreement_required_id CASCADE;
CREATE TABLE public.agreement_required_id (
    id                  BIGSERIAL PRIMARY KEY,
    user_id             BIGINT NOT NULL REFERENCES public.user(id),
    agreement_id        BIGINT NOT NULL REFERENCES public.agreement(id),
    required_id         TEXT NOT NULL,
    created_ts          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_ts          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    CONSTRAINT uniq__agreement_required_id UNIQUE (user_id, agreement_id, required_id)
);
CREATE INDEX idx__public__agreement_required_id__user_id        ON public.agreement_required_id (user_id);
CREATE INDEX idx__public__agreement_required_id__agreement_id   ON public.agreement_required_id (agreement_id);
CREATE INDEX idx__public__agreement_required_id__created_ts     ON public.agreement_required_id (created_ts);
CREATE INDEX idx__public__agreement_required_id__updated_ts     ON public.agreement_required_id (updated_ts);

-- DROP TABLE IF EXISTS public.purpose CASCADE;
CREATE TABLE public.purpose (
    id                  BIGSERIAL PRIMARY KEY,
    user_id             BIGINT NOT NULL REFERENCES public.user(id),
    value               TEXT NOT NULL,
    created_ts          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_ts          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    CONSTRAINT uniq__purpose UNIQUE (user_id, value)
);
CREATE INDEX idx__public__purpose__user_id        ON public.purpose (user_id);
CREATE INDEX idx__public__purpose__value          ON public.purpose (value);
CREATE INDEX idx__public__purpose__created_ts     ON public.purpose (created_ts);
CREATE INDEX idx__public__purpose__updated_ts     ON public.purpose (updated_ts);

-- DROP TABLE IF EXISTS public.agreement_purpose CASCADE;
CREATE TABLE public.agreement_purpose (
    id                  BIGSERIAL PRIMARY KEY,
    user_id             BIGINT NOT NULL REFERENCES public.user(id),
    agreement_id        BIGINT NOT NULL REFERENCES public.agreement(id),
    purpose_id          BIGINT NOT NULL REFERENCES public.purpose(id),
    created_ts          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_ts          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    CONSTRAINT uniq__agreement_purpose UNIQUE (user_id, agreement_id, purpose_id)
);
CREATE INDEX idx__public__agreement_purpose__user_id        ON public.agreement_purpose (user_id);
CREATE INDEX idx__public__agreement_purpose__agreement_id   ON public.agreement_purpose (agreement_id);
CREATE INDEX idx__public__agreement_purpose__purpose_id     ON public.agreement_purpose (purpose_id);
CREATE INDEX idx__public__agreement_purpose__created_ts     ON public.agreement_purpose (created_ts);
CREATE INDEX idx__public__agreement_purpose__updated_ts     ON public.agreement_purpose (updated_ts);

-- DROP TABLE IF EXISTS public.caveat CASCADE;
CREATE TABLE public.caveat (
    id                  BIGSERIAL PRIMARY KEY,
    user_id             BIGINT NOT NULL REFERENCES public.user(id),
    value               TEXT NOT NULL,
    created_ts          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_ts          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    CONSTRAINT uniq__caveat UNIQUE (user_id, value)
);
CREATE INDEX idx__public__caveat__user_id        ON public.caveat (user_id);
CREATE INDEX idx__public__caveat__value          ON public.caveat (value);
CREATE INDEX idx__public__caveat__created_ts     ON public.caveat (created_ts);
CREATE INDEX idx__public__caveat__updated_ts     ON public.caveat (updated_ts);

-- DROP TABLE IF EXISTS public.agreement_caveat CASCADE;
CREATE TABLE public.agreement_caveat (
    id                  BIGSERIAL PRIMARY KEY,
    user_id             BIGINT NOT NULL REFERENCES public.user(id),
    agreement_id        BIGINT NOT NULL REFERENCES public.agreement(id),
    caveat_id           BIGINT NOT NULL REFERENCES public.caveat(id),
    created_ts          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_ts          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    CONSTRAINT uniq__agreement_caveat UNIQUE (user_id, agreement_id, caveat_id)
);
CREATE INDEX idx__public__agreement_caveat__user_id        ON public.agreement_caveat (user_id);
CREATE INDEX idx__public__agreement_caveat__agreement_id   ON public.agreement_caveat (agreement_id);
CREATE INDEX idx__public__agreement_caveat__caveat_id      ON public.agreement_caveat (caveat_id);
CREATE INDEX idx__public__agreement_caveat__created_ts     ON public.agreement_caveat (created_ts);
CREATE INDEX idx__public__agreement_caveat__updated_ts     ON public.agreement_caveat (updated_ts);

-- DROP TABLE IF EXISTS public.role CASCADE;
CREATE TABLE public.role (
    id                  BIGSERIAL PRIMARY KEY,
    user_id             BIGINT NOT NULL REFERENCES public.user(id),
    value               TEXT NOT NULL,
    created_ts          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_ts          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    CONSTRAINT uniq__role UNIQUE (user_id, value)
);
CREATE INDEX idx__public__role__user_id        ON public.role (user_id);
CREATE INDEX idx__public__role__value          ON public.role (value);
CREATE INDEX idx__public__role__created_ts     ON public.role (created_ts);
CREATE INDEX idx__public__role__updated_ts     ON public.role (updated_ts);

-- DROP TABLE IF EXISTS public.agreement_role CASCADE;
CREATE TABLE public.agreement_role (
    id                  BIGSERIAL PRIMARY KEY,
    user_id             BIGINT NOT NULL REFERENCES public.user(id),
    agreement_id        BIGINT NOT NULL REFERENCES public.agreement(id),
    role_id             BIGINT NOT NULL REFERENCES public.role(id),
    created_ts          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_ts          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    CONSTRAINT uniq__agreement_role UNIQUE (user_id, agreement_id, role_id)
);
CREATE INDEX idx__public__agreement_role__user_id        ON public.agreement_role (user_id);
CREATE INDEX idx__public__agreement_role__agreement_id   ON public.agreement_role (agreement_id);
CREATE INDEX idx__public__agreement_role__role_id        ON public.agreement_role (role_id);
CREATE INDEX idx__public__agreement_role__created_ts     ON public.agreement_role (created_ts);
CREATE INDEX idx__public__agreement_role__updated_ts     ON public.agreement_role (updated_ts);


-- Events
-- DROP TABLE IF EXISTS public.event_type CASCADE;
CREATE TABLE public.event_type (
    id                  BIGSERIAL PRIMARY KEY,
    value               TEXT NOT NULL,
    created_ts          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_ts          TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx__public__event_type__value          ON public.event_type (value);
CREATE INDEX idx__public__event_type__created_ts     ON public.event_type (created_ts);
CREATE INDEX idx__public__event_type__updated_ts     ON public.event_type (updated_ts);

INSERT INTO public.event_type (value) VALUES ('data');

-- DROP TABLE IF EXISTS public.event CASCADE;
CREATE TABLE public.event (
    id                  BIGSERIAL PRIMARY KEY,
    user_id             BIGINT NOT NULL REFERENCES public.user(id),
    version             SMALLINT NOT NULL,
    event_id_uuid       UUID UNIQUE NOT NULL,
    event_type_id       BIGINT NOT NULL REFERENCES public.event_type(id),
    agreement_id        BIGINT NOT NULL REFERENCES public.agreement(id),
    sender_id           TEXT NOT NULL,
    recipient_id        TEXT NOT NULL,
    created             BIGINT NOT NULL,
    created_as_ts       TIMESTAMPTZ NOT NULL,
    created_ts          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_ts          TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx__public__event__user_id        ON public.event (user_id);
CREATE INDEX idx__public__event__version        ON public.event (version);
CREATE INDEX idx__public__event__event_id_uuid  ON public.event (event_id_uuid);
CREATE INDEX idx__public__event__event_type_id  ON public.event (event_type_id);
CREATE INDEX idx__public__event__agreement_id   ON public.event (agreement_id);
CREATE INDEX idx__public__event__sender_id      ON public.event (sender_id);
CREATE INDEX idx__public__event__recipient_id   ON public.event (recipient_id);
CREATE INDEX idx__public__event__created_ts     ON public.event (created_ts);
CREATE INDEX idx__public__event__updated_ts     ON public.event (updated_ts);

-- DROP TABLE IF EXISTS public.event_data CASCADE;
-- DROP SEQUENCE IF EXISTS seq__event_data__id;
-- CREATE SEQUENCE seq__event_data__id;
-- CREATE TABLE public.event_data (
--     id                  BIGINT NOT NULL DEFAULT nextval('seq__event_data__id'),
--     user_id             BIGINT NOT NULL REFERENCES public.user(id),
--     event_id            BIGINT NOT NULL REFERENCES public.event(id),
--     data                TEXT NOT NULL,
--     created_ts          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
--     updated_ts          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
--     PRIMARY KEY (user_id, id)
-- ) PARTITION BY LIST (user_id);
CREATE TABLE public.event_data (
    id                  BIGSERIAL PRIMARY KEY,
    user_id             BIGINT NOT NULL REFERENCES public.user(id),
    event_id            BIGINT NOT NULL REFERENCES public.event(id),
    data                TEXT NOT NULL,
    created_ts          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_ts          TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx__public__event_data__event_id       ON public.event_data (event_id);
CREATE INDEX idx__public__event_data__user_id        ON public.event_data (user_id);
CREATE INDEX idx__public__event_data__created_ts     ON public.event_data (created_ts);
CREATE INDEX idx__public__event_data__updated_ts     ON public.event_data (updated_ts);

-- Signatures
-- DROP TABLE IF EXISTS public.signature CASCADE;
CREATE TABLE public.signature (
    id                  BIGSERIAL PRIMARY KEY,
    user_id             BIGINT NOT NULL REFERENCES public.user(id),
    version             SMALLINT NOT NULL,
    signer_id           TEXT NOT NULL,
    signed_on           BIGINT NOT NULL,
    type                TEXT NOT NULL,
    jws                 TEXT NOT NULL,
    role_id             BIGINT REFERENCES public.role(id),
    agreement_id        BIGINT REFERENCES public.agreement(id),
    event_id            BIGINT REFERENCES public.event(id),
    signed_on_as_ts     TIMESTAMPTZ NOT NULL,
    created_ts          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_ts          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    CONSTRAINT uniq__signature__agreement UNIQUE (user_id, signer_id, agreement_id),
    CONSTRAINT uniq__signature__event UNIQUE (user_id, signer_id, event_id)
);
CREATE INDEX idx__public__signature__user_id         ON public.signature (user_id);
CREATE INDEX idx__public__signature__version         ON public.signature (version);
CREATE INDEX idx__public__signature__signed_on       ON public.signature (signed_on);
CREATE INDEX idx__public__signature__role_id         ON public.signature (role_id);
CREATE INDEX idx__public__signature__agreement_id    ON public.signature (agreement_id);
CREATE INDEX idx__public__signature__event_id        ON public.signature (event_id);
CREATE INDEX idx__public__signature__signed_on_as_ts ON public.signature (signed_on_as_ts);
CREATE INDEX idx__public__signature__created_ts      ON public.signature (created_ts);
CREATE INDEX idx__public__signature__updated_ts      ON public.signature (updated_ts);
