-- v0 -> v13 (compatible with v9+): Latest revision
CREATE TABLE "user" (
	bridge_id       TEXT NOT NULL,
	mxid            TEXT NOT NULL,

	management_room TEXT,
	access_token    TEXT,

	PRIMARY KEY (bridge_id, mxid)
);

CREATE TABLE user_login (
	bridge_id   TEXT  NOT NULL,
	user_mxid   TEXT  NOT NULL,
	id          TEXT  NOT NULL,
	remote_name TEXT  NOT NULL,
	space_room  TEXT,
	metadata    jsonb NOT NULL,

	PRIMARY KEY (bridge_id, id),
	CONSTRAINT user_login_user_fkey FOREIGN KEY (bridge_id, user_mxid)
		REFERENCES "user" (bridge_id, mxid)
		ON DELETE CASCADE ON UPDATE CASCADE
);

CREATE TABLE portal (
	bridge_id       TEXT    NOT NULL,
	id              TEXT    NOT NULL,
	receiver        TEXT    NOT NULL,
	mxid            TEXT,

	parent_id       TEXT,
	-- This is not accessed by the bridge, it's only used for the portal parent foreign key.
	-- Parent groups are probably never DMs, so they don't need a receiver.
	parent_receiver TEXT    NOT NULL DEFAULT '',

	relay_bridge_id TEXT,
	relay_login_id  TEXT,

	other_user_id   TEXT,

	name            TEXT    NOT NULL,
	topic           TEXT    NOT NULL,
	avatar_id       TEXT    NOT NULL,
	avatar_hash     TEXT    NOT NULL,
	avatar_mxc      TEXT    NOT NULL,
	name_set        BOOLEAN NOT NULL,
	avatar_set      BOOLEAN NOT NULL,
	topic_set       BOOLEAN NOT NULL,
	in_space        BOOLEAN NOT NULL,
	room_type       TEXT    NOT NULL,
	disappear_type  TEXT,
	disappear_timer BIGINT,
	metadata        jsonb   NOT NULL,

	PRIMARY KEY (bridge_id, id, receiver),
	CONSTRAINT portal_parent_fkey FOREIGN KEY (bridge_id, parent_id, parent_receiver)
		-- Deletes aren't allowed to cascade here:
		-- children should be re-parented or cleaned up manually
		REFERENCES portal (bridge_id, id, receiver) ON UPDATE CASCADE,
	CONSTRAINT portal_relay_fkey FOREIGN KEY (relay_bridge_id, relay_login_id)
		REFERENCES user_login (bridge_id, id)
		ON DELETE SET NULL ON UPDATE CASCADE
);

CREATE TABLE ghost (
	bridge_id        TEXT    NOT NULL,
	id               TEXT    NOT NULL,

	name             TEXT    NOT NULL,
	avatar_id        TEXT    NOT NULL,
	avatar_hash      TEXT    NOT NULL,
	avatar_mxc       TEXT    NOT NULL,
	name_set         BOOLEAN NOT NULL,
	avatar_set       BOOLEAN NOT NULL,
	contact_info_set BOOLEAN NOT NULL,
	is_bot           BOOLEAN NOT NULL,
	identifiers      jsonb   NOT NULL,
	metadata         jsonb   NOT NULL,

	PRIMARY KEY (bridge_id, id)
);

CREATE TABLE message (
	-- Messages have an extra rowid to allow a single relates_to column with ON DELETE SET NULL
	-- If the foreign key used (bridge_id, relates_to), then deleting the target column
	-- would try to set bridge_id to null as well.

	-- only: sqlite (line commented)
--	rowid      INTEGER PRIMARY KEY,
	-- only: postgres
	rowid            BIGINT PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,

	bridge_id        TEXT    NOT NULL,
	id               TEXT    NOT NULL,
	part_id          TEXT    NOT NULL,
	mxid             TEXT    NOT NULL,

	room_id          TEXT    NOT NULL,
	room_receiver    TEXT    NOT NULL,
	sender_id        TEXT    NOT NULL,
	sender_mxid      TEXT    NOT NULL,
	timestamp        BIGINT  NOT NULL,
	edit_count       INTEGER NOT NULL,
	thread_root_id   TEXT,
	reply_to_id      TEXT,
	reply_to_part_id TEXT,
	metadata         jsonb   NOT NULL,

	CONSTRAINT message_room_fkey FOREIGN KEY (bridge_id, room_id, room_receiver)
		REFERENCES portal (bridge_id, id, receiver)
		ON DELETE CASCADE ON UPDATE CASCADE,
	CONSTRAINT message_sender_fkey FOREIGN KEY (bridge_id, sender_id)
		REFERENCES ghost (bridge_id, id)
		ON DELETE CASCADE ON UPDATE CASCADE,
	CONSTRAINT message_real_pkey UNIQUE (bridge_id, room_receiver, id, part_id)
);
CREATE INDEX message_room_idx ON message (bridge_id, room_id, room_receiver);

CREATE TABLE disappearing_message (
	bridge_id    TEXT   NOT NULL,
	mx_room      TEXT   NOT NULL,
	mxid         TEXT   NOT NULL,
	type         TEXT   NOT NULL,
	timer        BIGINT NOT NULL,
	disappear_at BIGINT,

	PRIMARY KEY (bridge_id, mxid)
);

CREATE TABLE reaction (
	bridge_id       TEXT   NOT NULL,
	message_id      TEXT   NOT NULL,
	message_part_id TEXT   NOT NULL,
	sender_id       TEXT   NOT NULL,
	emoji_id        TEXT   NOT NULL,
	room_id         TEXT   NOT NULL,
	room_receiver   TEXT   NOT NULL,
	mxid            TEXT   NOT NULL,

	timestamp       BIGINT NOT NULL,
	emoji           TEXT   NOT NULL,
	metadata        jsonb  NOT NULL,

	PRIMARY KEY (bridge_id, room_receiver, message_id, message_part_id, sender_id, emoji_id),
	CONSTRAINT reaction_room_fkey FOREIGN KEY (bridge_id, room_id, room_receiver)
		REFERENCES portal (bridge_id, id, receiver)
		ON DELETE CASCADE ON UPDATE CASCADE,
	CONSTRAINT reaction_message_fkey FOREIGN KEY (bridge_id, room_receiver, message_id, message_part_id)
		REFERENCES message (bridge_id, room_receiver, id, part_id)
		ON DELETE CASCADE ON UPDATE CASCADE,
	CONSTRAINT reaction_sender_fkey FOREIGN KEY (bridge_id, sender_id)
		REFERENCES ghost (bridge_id, id)
		ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE INDEX reaction_room_idx ON reaction (bridge_id, room_id, room_receiver);

CREATE TABLE user_portal (
	bridge_id       TEXT    NOT NULL,
	user_mxid       TEXT    NOT NULL,
	login_id        TEXT    NOT NULL,
	portal_id       TEXT    NOT NULL,
	portal_receiver TEXT    NOT NULL,
	in_space        BOOLEAN NOT NULL,
	preferred       BOOLEAN NOT NULL,
	last_read       BIGINT,

	PRIMARY KEY (bridge_id, user_mxid, login_id, portal_id, portal_receiver),
	CONSTRAINT user_portal_user_login_fkey FOREIGN KEY (bridge_id, login_id)
		REFERENCES user_login (bridge_id, id)
		ON DELETE CASCADE ON UPDATE CASCADE,
	CONSTRAINT user_portal_portal_fkey FOREIGN KEY (bridge_id, portal_id, portal_receiver)
		REFERENCES portal (bridge_id, id, receiver)
		ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE INDEX user_portal_login_idx ON user_portal (bridge_id, login_id);
CREATE INDEX user_portal_portal_idx ON user_portal (bridge_id, portal_id, portal_receiver);

CREATE TABLE backfill_task (
	bridge_id            TEXT    NOT NULL,
	portal_id            TEXT    NOT NULL,
	portal_receiver      TEXT    NOT NULL,
	user_login_id        TEXT    NOT NULL,

	batch_count          INTEGER NOT NULL,
	is_done              BOOLEAN NOT NULL,
	cursor               TEXT,
	oldest_message_id    TEXT,
	dispatched_at        BIGINT,
	completed_at         BIGINT,
	next_dispatch_min_ts BIGINT  NOT NULL,

	PRIMARY KEY (bridge_id, portal_id, portal_receiver),
	CONSTRAINT backfill_queue_portal_fkey FOREIGN KEY (bridge_id, portal_id, portal_receiver)
		REFERENCES portal (bridge_id, id, receiver)
		ON DELETE CASCADE ON UPDATE CASCADE
);
