START TRANSACTION;

CREATE DOMAIN short_text AS text CHECK (length(value) <= 128);
CREATE DOMAIN positive_integer AS integer CHECK (value > 0);

CREATE TABLE person (
  id		  bigserial PRIMARY KEY,
  login   short_text NOT NULL UNIQUE
);

CREATE TABLE dispenser_admin (
  person_id   bigint PRIMARY KEY REFERENCES person(id) ON UPDATE CASCADE ON DELETE CASCADE
);

CREATE TYPE yandex_group_type AS ENUM ('DEPARTMENT', 'SERVICE', 'SERVICEROLE', 'WIKI');

CREATE TABLE yandex_group (
  id                    bigserial PRIMARY KEY,
  url_acceptable_key    short_text NOT NULL UNIQUE,
  group_type  yandex_group_type NOT NULL
);

CREATE TABLE project (
  id              bigserial PRIMARY KEY,
  key             short_text NOT NULL,
  person_id       bigint REFERENCES person(id) ON UPDATE CASCADE,
  short_name      short_text NOT NULL,
  description     text NOT NULL,
  parent_id		    bigint REFERENCES project(id) ON UPDATE CASCADE ON DELETE CASCADE,
  abc_service_id  positive_integer,
  removed         boolean NOT NULL DEFAULT FALSE,
  UNIQUE (key, person_id),
  UNIQUE (short_name, person_id)
);

CREATE UNIQUE INDEX ON project (key) WHERE person_id IS NULL;
CREATE UNIQUE INDEX ON project (short_name) WHERE person_id IS NULL;

INSERT INTO project (key, short_name, description) VALUES ('yandex', 'Яндекс', 'Корневой проект');

CREATE TYPE membership_role AS ENUM ('MEMBER', 'RESPONSIBLE');

CREATE TABLE person_membership (
  person_id     bigint NOT NULL REFERENCES person(id) ON UPDATE CASCADE ON DELETE CASCADE,
  project_id    bigint NOT NULL REFERENCES project(id) ON UPDATE CASCADE ON DELETE CASCADE,
  role          membership_role,
  PRIMARY KEY (person_id, project_id, role)
);

CREATE TABLE yandex_group_membership (
  yandex_group_id   bigint NOT NULL REFERENCES yandex_group(id) ON UPDATE CASCADE ON DELETE CASCADE,
  project_id        bigint NOT NULL REFERENCES project(id) ON UPDATE CASCADE ON DELETE CASCADE,
  role              membership_role,
  PRIMARY KEY (yandex_group_id, project_id, role)
);

CREATE TABLE service (
  id    bigserial PRIMARY KEY,
  key   short_text NOT NULL UNIQUE,
  name  short_text NOT NULL UNIQUE,
  abc_service_id  positive_integer
);

CREATE TABLE service_admin (
  person_id   bigint NOT NULL REFERENCES person(id) ON UPDATE CASCADE ON DELETE CASCADE,
  service_id  bigint NOT NULL REFERENCES service(id) ON UPDATE CASCADE ON DELETE CASCADE,
  PRIMARY KEY (person_id, service_id)
);

CREATE TABLE service_trustee (
  person_id   bigint NOT NULL REFERENCES person(id) ON UPDATE CASCADE ON DELETE CASCADE,
  service_id  bigint NOT NULL REFERENCES service(id) ON UPDATE CASCADE ON DELETE CASCADE,
  PRIMARY KEY (person_id, service_id)
);

CREATE TABLE project_service_meta (
  project_id  bigint NOT NULL REFERENCES project(id) ON UPDATE CASCADE ON DELETE CASCADE,
  service_id  bigint NOT NULL REFERENCES service(id) ON UPDATE CASCADE ON DELETE CASCADE,
  data        jsonb NOT NULL,
  PRIMARY KEY (project_id, service_id)
);

CREATE TYPE resource_type AS ENUM ('ENUMERABLE', 'MEMORY', 'MONEY', 'POWER', 'STORAGE', 'TRAFFIC');

CREATE TYPE quoting_mode AS ENUM ('DEFAULT', 'ENTITIES_ONLY', 'SYNCHRONIZATION');

CREATE TABLE resource (
  id		          bigserial PRIMARY KEY,
  key             short_text NOT NULL,
  service_id		  bigint NOT NULL REFERENCES service(id) ON UPDATE CASCADE ON DELETE CASCADE,
  name			      short_text NOT NULL,
  resource_type   resource_type NOT NULL,
  description		  text,
  quoting_mode    quoting_mode NOT NULL,
  UNIQUE (key, service_id)
);

CREATE TYPE quota_value_type AS ENUM ('ABSOLUTE', 'PERCENT');

CREATE TABLE quota_spec (
  id	          bigserial PRIMARY KEY,
  key           short_text NOT NULL,
  resource_id   bigint NOT NULL REFERENCES resource(id) ON UPDATE CASCADE ON DELETE CASCADE,
  description   text NOT NULL,
  value_type    quota_value_type NOT NULL,
  UNIQUE (key, resource_id)
);

CREATE TABLE quota (
  id		                bigserial PRIMARY KEY,
  quota_spec_id	        bigint NOT NULL REFERENCES quota_spec(id) ON UPDATE CASCADE ON DELETE CASCADE,
  project_id		        bigint NOT NULL REFERENCES project(id) ON UPDATE CASCADE ON DELETE CASCADE,
  max_value				      bigint NOT NULL,
  actual_value			    bigint NOT NULL,
  last_overquoting_ts   timestamp,
  UNIQUE (quota_spec_id, project_id)
);

CREATE TABLE entity_spec (
  id            bigserial PRIMARY KEY,
  key           short_text NOT NULL,
  service_id    bigint NOT NULL REFERENCES service(id) ON UPDATE CASCADE ON DELETE CASCADE,
  description   text NOT NULL,
  tag           short_text NOT NULL DEFAULT 'common',
  expirable     boolean NOT NULL DEFAULT FALSE,
  UNIQUE (key, service_id)
);

CREATE TABLE entity_spec_resource (
  entity_spec_id    bigint NOT NULL REFERENCES entity_spec(id) ON UPDATE CASCADE ON DELETE CASCADE,
  resource_id       bigint NOT NULL REFERENCES resource(id) ON UPDATE CASCADE ON DELETE CASCADE,
  PRIMARY KEY (entity_spec_id, resource_id)
);

--CREATE TABLE entity (
--  id            bigserial PRIMARY KEY,
--  key           short_text NOT NULL,
--  dimensions    jsonb NOT NULL,   -- TODO: add CHECKs
--  UNIQUE (key)                    -- one table for one service
--);
--
--CREATE INDEX entity_dimensions_gin_ix ON entity USING GIN (dimensions jsonb_path_ops);
--
--CREATE TABLE entity_usage (
--  entity_id     bigint REFERENCES entity(id) ON UPDATE CASCADE ON DELETE CASCADE,
--  project_id    bigint REFERENCES project(id) ON UPDATE CASCADE ON DELETE CASCADE,
--  usages        int NOT NULL,
--  PRIMARY KEY (entity_id, project_id)
--);

CREATE TABLE request (
  id                short_text PRIMARY KEY,
  appearance_time   timestamp,
  result            text
);

CREATE TABLE notification (
  project_id        bigint NOT NULL REFERENCES project(id) ON UPDATE CASCADE ON DELETE CASCADE,
  quota_spec_id     bigint NOT NULL REFERENCES quota_spec(id) ON UPDATE CASCADE ON DELETE CASCADE,
  creation_time     timestamp
);

COMMIT;