CREATE EXTENSION IF NOT EXISTS pgcrypto;

-- A user
CREATE TABLE public.users (
  -- User id
  user_id UUID PRIMARY KEY NOT NULL,
  -- User creation time
  ctime TIMESTAMP(0),
  -- Value to use when displaying the user's name. May be different from `username` or `email_address`.
  display_name VARCHAR(64) NOT NULL,
  -- Time of the last change to `display_name`
  display_name_mtime TIMESTAMP(0) NOT NULL,
  -- Encrypted email address (using pgp_sym_encrypt)
  -- This may be `NULL` if the value was never set, or if the value was removed.
  email_address BYTEA NULL,
  -- Time of the last change to `email_address`
  email_address_mtime TIMESTAMP(0) NOT NULL,
  -- Unique username, mainly used for authentication
  -- This may be `NULL` if the value was never set, or if the value was removed.
  username VARCHAR(64) NULL,
  -- Time of the last change to `username`
  username_mtime TIMESTAMP(0) NOT NULL,
  -- Encrypted password hash (hashed with `scrypt`, encrypted with `pgp_sym_encrypt_bytea`)
  password BYTEA NULL,
  -- Time of the last change to `password`
  password_mtime TIMESTAMP(0) NOT NULL,
  -- Flag indicating that this user is an administrator (has elevated permissions)
  is_administrator BOOLEAN NOT NULL,
  CHECK (display_name_mtime >= ctime),
  CHECK (email_address_mtime >= ctime),
  CHECK (username_mtime >= ctime),
  CHECK (password_mtime >= ctime),
  UNIQUE (email_address)
);

-- Table of email verifications: they may be validated or not
CREATE TABLE public.email_verifications (
  -- User id for this email
  user_id UUID NOT NULL,
  -- Encrypted email address (using pgp_sym_encrypt)
  email_address BYTEA NOT NULL,
  -- Date when the verification email was sent
  ctime TIMESTAMP(0) NOT NULL,
  -- Date when the email was validated. `null` if the email was not validated.
  validation_time TIMESTAMP(0) NULL,
  CHECK (validation_time >= ctime),
  CONSTRAINT email_verification__user__fk FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE ON UPDATE CASCADE
);

-- All the user sessions (active or expired)
CREATE TABLE public.sessions (
  -- Session id
  session_id UUID PRIMARY KEY NOT NULL,
  -- Id of the user authenticated by this session
  user_id UUID,
  -- Session creation time
  ctime TIMESTAMP(0) NOT NULL,
  -- Session access time
  atime TIMESTAMP(0) NOT NULL,
  -- Free-form session data
  data JSON NOT NULL,
  CHECK (atime >= ctime),
  CONSTRAINT session__user__fk FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE ON UPDATE CASCADE
);

-- Known Hammerfest servers
CREATE TABLE public.hammerfest_servers (
  -- Domain name for the Hammerfest server
  domain VARCHAR(64) PRIMARY KEY NOT NULL,
  CHECK (domain IN ('hammerfest.fr', 'hfest.net', 'hammerfest.es'))
);

-- Known Hammerfest users
CREATE TABLE public.hammerfest_users (
  -- Hammerfest server
  server VARCHAR(64) NOT NULL,
  -- User ID on the Hammerfest server
  user_id INT NOT NULL,
  -- Hammerfest username
  username VARCHAR(20) NOT NULL,
  PRIMARY KEY (server, user_id),
  CONSTRAINT hammerfest_user__hammerfest_server__fk FOREIGN KEY (server) REFERENCES hammerfest_servers(domain) ON DELETE RESTRICT ON UPDATE CASCADE,
  UNIQUE (server, username)
);

-- Active links between Eternaltwin and Hammerfest users
CREATE TABLE public.hammerfest_user_links (
  -- Eternaltwin user id
  user_id UUID NOT NULL,
  -- Hammerfest server
  hammerfest_server VARCHAR(64) NOT NULL,
  -- User ID on the Hammerfest server
  hammerfest_user_id INT NOT NULL,
  -- Link creation time
  ctime TIMESTAMP(0) NOT NULL,
  PRIMARY KEY (user_id, hammerfest_server, hammerfest_user_id),
  CONSTRAINT hammerfest_user_link__user__fk FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE RESTRICT ON UPDATE CASCADE,
  CONSTRAINT hammerfest_user_link__hammerfest_user__fk FOREIGN KEY (hammerfest_server, hammerfest_user_id) REFERENCES hammerfest_users(server, user_id) ON DELETE RESTRICT ON UPDATE CASCADE
);

INSERT INTO hammerfest_servers("domain")
VALUES
  ('hammerfest.fr'),
  ('hfest.net'),
  ('hammerfest.es');
