CREATE TABLE user_username_history (
  period PERIOD_LOWER NOT NULL,
  user_id USER_ID NOT NULL,
  username USERNAME NOT NULL,
  created_by USER_ID NOT NULL,
  deleted_by USER_ID NULL,
  PRIMARY KEY (period, user_id),
  CHECK ((UPPER(period) IS NULL) = (deleted_by IS NULL)),
  CONSTRAINT user_username__user__fk FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT user_username__created_by__fk FOREIGN KEY (created_by) REFERENCES users(user_id) ON DELETE RESTRICT ON UPDATE CASCADE,
  CONSTRAINT user_username__deleted_by__fk FOREIGN KEY (deleted_by) REFERENCES users(user_id) ON DELETE RESTRICT ON UPDATE CASCADE,
  EXCLUDE USING gist (username WITH =, period WITH &&),
  EXCLUDE USING gist (user_id WITH =, period WITH &&)
);

WITH usernames_agg AS (
  SELECT user_id, username, range_agg(period) AS period
  FROM users_history
  GROUP BY user_id, username
),
usernames AS (
  SELECT unnest(period) AS period, user_id, username
  FROM usernames_agg
),
usernames_matched AS (
  SELECT u.period, u.user_id, u.username, c.updated_by AS created_by, d.updated_by AS deleted_by
  FROM usernames AS u
         LEFT OUTER JOIN users_history AS c ON (u.user_id = c.user_id AND LOWER(u.period) = LOWER(c.period))
         LEFT OUTER JOIN users_history AS d ON (d.user_id = c.user_id AND UPPER(u.period) = LOWER(d.period))
  WHERE u.username IS NOT NULL
)
INSERT INTO user_username_history(period, user_id, username, created_by, deleted_by)
SELECT period, user_id, username, created_by, deleted_by
FROM usernames_matched;

DROP VIEW users_current;

ALTER TABLE users_history DROP COLUMN username;

ALTER TABLE users
ADD COLUMN period PERIOD_LOWER NULL,
ADD COLUMN deleted_by USER_ID NULL,
ADD CONSTRAINT users__deleted_by__fk FOREIGN KEY (deleted_by) REFERENCES users(user_id) ON DELETE RESTRICT ON UPDATE CASCADE;

UPDATE users
SET period = PERIOD(created_at, NULL);
