CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

-------------------- Publisher
CREATE TABLE publisher (
    publisher_id        UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    publisher_name      TEXT NOT NULL CHECK (octet_length(publisher_name) >= 1),
    publisher_shortname TEXT CHECK (octet_length(publisher_shortname) >= 1),
    publisher_url       TEXT CHECK (publisher_url ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)')
);
-- case-insensitive UNIQ index on publisher_name
CREATE UNIQUE INDEX publisher_uniq_idx ON publisher(lower(publisher_name));

CREATE TABLE imprint (
    imprint_id          UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    publisher_id        UUID NOT NULL REFERENCES publisher(publisher_id) ON DELETE CASCADE,
    imprint_name        TEXT NOT NULL CHECK (octet_length(imprint_name) >= 1),
    imprint_url         TEXT CHECK (imprint_url ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)')
);
-- case-insensitive UNIQ index on imprint_name
CREATE UNIQUE INDEX imprint_uniq_idx ON imprint(lower(imprint_name));

-------------------- Work

CREATE TYPE work_type AS ENUM (
    'book-chapter',
    'monograph',
    'edited-book',
    'textbook',
    'journal-issue',
    'book-set'
);

-- ONIX Publishing status https://onix-codelists.io/codelist/64
CREATE TYPE work_status AS ENUM (
    'unspecified',
    'cancelled',
    'forthcoming',
    'postponed-indefinitely',
    'active',
    'no-longer-our-product',
    'out-of-stock-indefinitely',
    'out-of-print',
    'inactive',
    'unknown',
    'remaindered',
    'withdrawn-from-sale',
    'recalled'
);

CREATE TABLE work (
    work_id             UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    work_type           work_type NOT NULL,
    work_status         work_status NOT NULL,
    full_title          TEXT NOT NULL CHECK (octet_length(full_title) >= 1),
    title               TEXT NOT NULL CHECK (octet_length(title) >= 1),
    subtitle            TEXT CHECK (octet_length(subtitle) >= 1),
    reference           TEXT CHECK (octet_length(reference) >= 1),
    edition             INTEGER NOT NULL CHECK (edition > 0),
    imprint_id          UUID NOT NULL REFERENCES imprint(imprint_id) ON DELETE CASCADE,
    doi                 TEXT CHECK (doi ~* 'https:\/\/doi.org\/10.\d{4,9}\/[-._\;\(\)\/:a-zA-Z0-9]+$'),
    publication_date    DATE,
    place               TEXT CHECK (octet_length(reference) >= 1),
    width               INTEGER CHECK (width > 0),
    height              INTEGER CHECK (height > 0),
    page_count          INTEGER CHECK (page_count > 0),
    page_breakdown      TEXT CHECK(octet_length(page_breakdown) >=1),
    image_count         INTEGER CHECK (image_count >= 0),
    table_count         INTEGER CHECK (table_count >= 0),
    audio_count         INTEGER CHECK (audio_count >= 0),
    video_count         INTEGER CHECK (video_count >= 0),
    license             TEXT CHECK (license ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)'),
    copyright_holder    TEXT NOT NULL CHECK (octet_length(copyright_holder) >= 1),
    landing_page        TEXT CHECK (landing_page ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)'),
    lccn                INTEGER CHECK(lccn > 0),
    oclc                INTEGER CHECK (oclc > 0),
    short_abstract      TEXT CHECK (octet_length(short_abstract) >= 1),
    long_abstract       TEXT CHECK (octet_length(long_abstract) >= 1),
    general_note        TEXT CHECK (octet_length(general_note) >= 1),
    toc                 TEXT CHECK (octet_length(toc) >= 1),
    cover_url           TEXT CHECK (cover_url ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)'),
    cover_caption       TEXT CHECK (octet_length(cover_caption) >= 1)
);
-- case-insensitive UNIQ index on doi
CREATE UNIQUE INDEX doi_uniq_idx ON work(lower(doi));

-------------------- Language

CREATE TYPE language_relation AS ENUM (
    'original',
    'translated-from',
    'translated-into'
);

CREATE TYPE language_code AS ENUM (
    'aar',
    'abk',
    'ace',
    'ach',
    'ada',
    'ady',
    'afa',
    'afh',
    'afr',
    'ain',
    'aka',
    'akk',
    'alb',
    'ale',
    'alg',
    'alt',
    'amh',
    'ang',
    'anp',
    'apa',
    'ara',
    'arc',
    'arg',
    'arm',
    'arn',
    'arp',
    'art',
    'arw',
    'asm',
    'ast',
    'ath',
    'aus',
    'ava',
    'ave',
    'awa',
    'aym',
    'aze',
    'bad',
    'bai',
    'bak',
    'bal',
    'bam',
    'ban',
    'baq',
    'bas',
    'bat',
    'bej',
    'bel',
    'bem',
    'ben',
    'ber',
    'bho',
    'bih',
    'bik',
    'bin',
    'bis',
    'bla',
    'bnt',
    'bos',
    'bra',
    'bre',
    'btk',
    'bua',
    'bug',
    'bul',
    'bur',
    'byn',
    'cad',
    'cai',
    'car',
    'cat',
    'cau',
    'ceb',
    'cel',
    'cha',
    'chb',
    'che',
    'chg',
    'chi',
    'chk',
    'chm',
    'chn',
    'cho',
    'chp',
    'chr',
    'chu',
    'chv',
    'chy',
    'cmc',
    'cnr',
    'cop',
    'cor',
    'cos',
    'cpe',
    'cpf',
    'cpp',
    'cre',
    'crh',
    'crp',
    'csb',
    'cus',
    'cze',
    'dak',
    'dan',
    'dar',
    'day',
    'del',
    'den',
    'dgr',
    'din',
    'div',
    'doi',
    'dra',
    'dsb',
    'dua',
    'dum',
    'dut',
    'dyu',
    'dzo',
    'efi',
    'egy',
    'eka',
    'elx',
    'eng',
    'enm',
    'epo',
    'est',
    'ewe',
    'ewo',
    'fan',
    'fao',
    'fat',
    'fij',
    'fil',
    'fin',
    'fiu',
    'fon',
    'fre',
    'frm',
    'fro',
    'frr',
    'frs',
    'fry',
    'ful',
    'fur',
    'gaa',
    'gay',
    'gba',
    'gem',
    'geo',
    'ger',
    'gez',
    'gil',
    'gla',
    'gle',
    'glg',
    'glv',
    'gmh',
    'goh',
    'gon',
    'gor',
    'got',
    'grb',
    'grc',
    'gre',
    'grn',
    'gsw',
    'guj',
    'gwi',
    'hai',
    'hat',
    'hau',
    'haw',
    'heb',
    'her',
    'hil',
    'him',
    'hin',
    'hit',
    'hmn',
    'hmo',
    'hrv',
    'hsb',
    'hun',
    'hup',
    'iba',
    'ibo',
    'ice',
    'ido',
    'iii',
    'ijo',
    'iku',
    'ile',
    'ilo',
    'ina',
    'inc',
    'ind',
    'ine',
    'inh',
    'ipk',
    'ira',
    'iro',
    'ita',
    'jav',
    'jbo',
    'jpn',
    'jpr',
    'jrb',
    'kaa',
    'kab',
    'kac',
    'kal',
    'kam',
    'kan',
    'kar',
    'kas',
    'kau',
    'kaw',
    'kaz',
    'kbd',
    'kha',
    'khi',
    'khm',
    'kho',
    'kik',
    'kin',
    'kir',
    'kmb',
    'kok',
    'kom',
    'kon',
    'kor',
    'kos',
    'kpe',
    'krc',
    'krl',
    'kro',
    'kru',
    'kua',
    'kum',
    'kur',
    'kut',
    'lad',
    'lah',
    'lam',
    'lao',
    'lat',
    'lav',
    'lez',
    'lim',
    'lin',
    'lit',
    'lol',
    'loz',
    'ltz',
    'lua',
    'lub',
    'lug',
    'lui',
    'lun',
    'luo',
    'lus',
    'mac',
    'mad',
    'mag',
    'mah',
    'mai',
    'mak',
    'mal',
    'man',
    'mao',
    'map',
    'mar',
    'mas',
    'may',
    'mdf',
    'mdr',
    'men',
    'mga',
    'mic',
    'min',
    'mis',
    'mkh',
    'mlg',
    'mlt',
    'mnc',
    'mni',
    'mno',
    'moh',
    'mon',
    'mos',
    'mul',
    'mun',
    'mus',
    'mwl',
    'mwr',
    'myn',
    'myv',
    'nah',
    'nai',
    'nap',
    'nau',
    'nav',
    'nbl',
    'nde',
    'ndo',
    'nds',
    'nep',
    'new',
    'nia',
    'nic',
    'niu',
    'nno',
    'nob',
    'nog',
    'non',
    'nor',
    'nqo',
    'nso',
    'nub',
    'nwc',
    'nya',
    'nym',
    'nyn',
    'nyo',
    'nzi',
    'oci',
    'oji',
    'ori',
    'orm',
    'osa',
    'oss',
    'ota',
    'oto',
    'paa',
    'pag',
    'pal',
    'pam',
    'pan',
    'pap',
    'pau',
    'peo',
    'per',
    'phi',
    'phn',
    'pli',
    'pol',
    'pon',
    'por',
    'pra',
    'pro',
    'pus',
    'qaa',
    'que',
    'raj',
    'rap',
    'rar',
    'roa',
    'roh',
    'rom',
    'rum',
    'run',
    'rup',
    'rus',
    'sad',
    'sag',
    'sah',
    'sai',
    'sal',
    'sam',
    'san',
    'sas',
    'sat',
    'scn',
    'sco',
    'sel',
    'sem',
    'sga',
    'sgn',
    'shn',
    'sid',
    'sin',
    'sio',
    'sit',
    'sla',
    'slo',
    'slv',
    'sma',
    'sme',
    'smi',
    'smj',
    'smn',
    'smo',
    'sms',
    'sna',
    'snd',
    'snk',
    'sog',
    'som',
    'son',
    'sot',
    'spa',
    'srd',
    'srn',
    'srp',
    'srr',
    'ssa',
    'ssw',
    'suk',
    'sun',
    'sus',
    'sux',
    'swa',
    'swe',
    'syc',
    'syr',
    'tah',
    'tai',
    'tam',
    'tat',
    'tel',
    'tem',
    'ter',
    'tet',
    'tgk',
    'tgl',
    'tha',
    'tib',
    'tig',
    'tir',
    'tiv',
    'tkl',
    'tlh',
    'tli',
    'tmh',
    'tog',
    'ton',
    'tpi',
    'tsi',
    'tsn',
    'tso',
    'tuk',
    'tum',
    'tup',
    'tur',
    'tut',
    'tvl',
    'twi',
    'tyv',
    'udm',
    'uga',
    'uig',
    'ukr',
    'umb',
    'und',
    'urd',
    'uzb',
    'vai',
    'ven',
    'vie',
    'vol',
    'vot',
    'wak',
    'wal',
    'war',
    'was',
    'wel',
    'wen',
    'wln',
    'wol',
    'xal',
    'xho',
    'yao',
    'yap',
    'yid',
    'yor',
    'ypk',
    'zap',
    'zbl',
    'zen',
    'zgh',
    'zha',
    'znd',
    'zul',
    'zun',
    'zxx',
    'zza'
);

CREATE TABLE language (
    language_id         UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    work_id             UUID NOT NULL REFERENCES work(work_id) ON DELETE CASCADE,
    language_code       language_code NOT NULL,
    language_relation   language_relation NOT NULL,
    main_language       BOOLEAN NOT NULL DEFAULT False
);

-- UNIQ index on combination of language and work
CREATE UNIQUE INDEX language_uniq_work_idx ON language(work_id, language_code);

-------------------- Series

CREATE TYPE series_type AS ENUM (
    'journal',
    'book-series'
);

CREATE TABLE series (
    series_id           UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    series_type         series_type NOT NULL,
    series_name         TEXT NOT NULL CHECK (octet_length(series_name) >= 1),
    issn_print          TEXT NOT NULL CHECK (issn_print ~* '\d{4}\-\d{3}(\d|X)'),
    issn_digital        TEXT NOT NULL CHECK (issn_digital ~* '\d{4}\-\d{3}(\d|X)'),
    series_url          TEXT CHECK (series_url ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)'),
    imprint_id          UUID NOT NULL REFERENCES imprint(imprint_id) ON DELETE CASCADE
);

--  UNIQ index on ISSNs
CREATE UNIQUE INDEX series_issn_print_idx ON series(issn_print);
CREATE UNIQUE INDEX series_issn_digital_idx ON series(issn_digital);

CREATE TABLE issue (
    series_id           UUID NOT NULL REFERENCES series(series_id) ON DELETE CASCADE,
    work_id             UUID NOT NULL REFERENCES work(work_id) ON DELETE CASCADE,
    issue_ordinal       INTEGER NOT NULL CHECK (issue_ordinal > 0),
    PRIMARY KEY (series_id, work_id)
);

-- UNIQ index on issue_ordinal and series_id
CREATE UNIQUE INDEX issue_uniq_ord_in_series_idx ON issue(series_id, issue_ordinal);

-------------------- Contributor

CREATE TABLE contributor (
    contributor_id      UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    first_name          TEXT CHECK (octet_length(first_name) >= 1),
    last_name           TEXT NOT NULL CHECK (octet_length(last_name) >= 1),
    full_name           TEXT NOT NULL CHECK (octet_length(full_name) >= 1),
    orcid               TEXT CHECK (orcid ~* '0000-000(1-[5-9]|2-[0-9]|3-[0-4])\d{3}-\d{3}[\dX]'),
    website             TEXT CHECK (octet_length(website) >= 1)
);
-- case-insensitive UNIQ index on orcid
CREATE UNIQUE INDEX orcid_uniq_idx ON contributor(lower(orcid));

CREATE TYPE contribution_type AS ENUM (
    'author',
    'editor',
    'translator',
    'photographer',
    'ilustrator',
    'music-editor',
    'foreword-by',
    'introduction-by',
    'afterword-by',
    'preface-by'
);

CREATE TABLE contribution (
    work_id             UUID NOT NULL REFERENCES work(work_id) ON DELETE CASCADE,
    contributor_id      UUID NOT NULL REFERENCES contributor(contributor_id) ON DELETE CASCADE,
    contribution_type   contribution_type NOT NULL,
    main_contribution   BOOLEAN NOT NULL DEFAULT False,
    biography           TEXT CHECK (octet_length(biography) >= 1),
    institution         TEXT CHECK (octet_length(institution) >= 1),
    PRIMARY KEY (work_id, contributor_id, contribution_type)
);

-------------------- Publication

CREATE TYPE publication_type AS ENUM (
    'Paperback',
    'Hardback',
    'PDF',
    'HTML',
    'XML',
    'Epub',
    'Mobi'
);

CREATE TABLE publication (
    publication_id      UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    publication_type    publication_type NOT NULL,
    work_id             UUID NOT NULL REFERENCES work(work_id) ON DELETE CASCADE,
    isbn                TEXT CHECK (octet_length(isbn) = 17),
    publication_url     TEXT CHECK (publication_url ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)')
);

CREATE INDEX publication_isbn_idx ON publication(isbn);


-------------------- Price

CREATE TYPE currency_code AS ENUM (
    'adp',
    'aed',
    'afa',
    'afn',
    'alk',
    'all',
    'amd',
    'ang',
    'aoa',
    'aok',
    'aon',
    'aor',
    'ara',
    'arp',
    'ars',
    'ary',
    'ats',
    'aud',
    'awg',
    'aym',
    'azm',
    'azn',
    'bad',
    'bam',
    'bbd',
    'bdt',
    'bec',
    'bef',
    'bel',
    'bgj',
    'bgk',
    'bgl',
    'bgn',
    'bhd',
    'bif',
    'bmd',
    'bnd',
    'bob',
    'bop',
    'bov',
    'brb',
    'brc',
    'bre',
    'brl',
    'brn',
    'brr',
    'bsd',
    'btn',
    'buk',
    'bwp',
    'byb',
    'byn',
    'byr',
    'bzd',
    'cad',
    'cdf',
    'chc',
    'che',
    'chf',
    'chw',
    'clf',
    'clp',
    'cny',
    'cop',
    'cou',
    'crc',
    'csd',
    'csj',
    'csk',
    'cuc',
    'cup',
    'cve',
    'cyp',
    'czk',
    'ddm',
    'dem',
    'djf',
    'dkk',
    'dop',
    'dzd',
    'ecs',
    'ecv',
    'eek',
    'egp',
    'ern',
    'esa',
    'esb',
    'esp',
    'etb',
    'eur',
    'fim',
    'fjd',
    'fkp',
    'frf',
    'gbp',
    'gek',
    'gel',
    'ghc',
    'ghp',
    'ghs',
    'gip',
    'gmd',
    'gne',
    'gnf',
    'gns',
    'gqe',
    'grd',
    'gtq',
    'gwe',
    'gwp',
    'gyd',
    'hkd',
    'hnl',
    'hrd',
    'hrk',
    'htg',
    'huf',
    'idr',
    'iep',
    'ilp',
    'ilr',
    'ils',
    'inr',
    'iqd',
    'irr',
    'isj',
    'isk',
    'itl',
    'jmd',
    'jod',
    'jpy',
    'kes',
    'kgs',
    'khr',
    'kmf',
    'kpw',
    'krw',
    'kwd',
    'kyd',
    'kzt',
    'laj',
    'lak',
    'lbp',
    'lkr',
    'lrd',
    'lsl',
    'lsm',
    'ltl',
    'ltt',
    'luc',
    'luf',
    'lul',
    'lvl',
    'lvr',
    'lyd',
    'mad',
    'mdl',
    'mga',
    'mgf',
    'mkd',
    'mlf',
    'mmk',
    'mnt',
    'mop',
    'mro',
    'mru',
    'mtl',
    'mtp',
    'mur',
    'mvq',
    'mvr',
    'mwk',
    'mxn',
    'mxp',
    'mxv',
    'myr',
    'mze',
    'mzm',
    'mzn',
    'nad',
    'ngn',
    'nic',
    'nio',
    'nlg',
    'nok',
    'npr',
    'nzd',
    'omr',
    'pab',
    'peh',
    'pei',
    'pen',
    'pes',
    'pgk',
    'php',
    'pkr',
    'pln',
    'plz',
    'pte',
    'pyg',
    'qar',
    'rhd',
    'rok',
    'rol',
    'ron',
    'rsd',
    'rub',
    'rur',
    'rwf',
    'sar',
    'sbd',
    'scr',
    'sdd',
    'sdg',
    'sdp',
    'sek',
    'sgd',
    'shp',
    'sit',
    'skk',
    'sll',
    'sos',
    'srd',
    'srg',
    'ssp',
    'std',
    'stn',
    'sur',
    'svc',
    'syp',
    'szl',
    'thb',
    'tjr',
    'tjs',
    'tmm',
    'tmt',
    'tnd',
    'top',
    'tpe',
    'trl',
    'try',
    'ttd',
    'twd',
    'tzs',
    'uah',
    'uak',
    'ugs',
    'ugw',
    'ugx',
    'usd',
    'usn',
    'uss',
    'uyi',
    'uyn',
    'uyp',
    'uyu',
    'uyw',
    'uzs',
    'veb',
    'vef',
    'ves',
    'vnc',
    'vnd',
    'vuv',
    'wst',
    'xaf',
    'xag',
    'xau',
    'xba',
    'xbb',
    'xbc',
    'xbd',
    'xcd',
    'xdr',
    'xeu',
    'xfo',
    'xfu',
    'xof',
    'xpd',
    'xpf',
    'xpt',
    'xre',
    'xsu',
    'xts',
    'xua',
    'xxx',
    'ydd',
    'yer',
    'yud',
    'yum',
    'yun',
    'zal',
    'zar',
    'zmk',
    'zmw',
    'zrn',
    'zrz',
    'zwc',
    'zwd',
    'zwl',
    'zwn',
    'zwr'
);

CREATE TABLE price (
    price_id            UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    publication_id      UUID NOT NULL REFERENCES publication(publication_id) ON DELETE CASCADE,
    currency_code       currency_code NOT NULL,
    unit_price          double precision NOT NULL
);

-------------------- Subject

CREATE TYPE subject_type AS ENUM (
    'bic',
    'bisac',
    'thema',
    'lcc',
    'custom',
    'keyword'
);

CREATE TABLE subject (
    subject_id          UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    work_id             UUID NOT NULL REFERENCES work(work_id) ON DELETE CASCADE,
    subject_type        subject_type NOT NULL,
    subject_code        TEXT NOT NULL CHECK (octet_length(subject_code) >= 1),
    subject_ordinal     INTEGER NOT NULL CHECK (subject_ordinal > 0)
);

-------------------- Funder

CREATE TABLE funder (
    funder_id           UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    funder_name         TEXT NOT NULL CHECK (octet_length(funder_name) >= 1),
    funder_doi          TEXT CHECK (funder_doi ~* 'https:\/\/doi.org\/10.\d{4,9}\/[-._\;\(\)\/:a-zA-Z0-9]+$')
);
-- case-insensitive UNIQ index on funder_doi
CREATE UNIQUE INDEX funder_doi_uniq_idx ON funder(lower(funder_doi));

CREATE TABLE funding (
    funding_id          UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    work_id             UUID NOT NULL REFERENCES work(work_id) ON DELETE CASCADE,
    funder_id           UUID NOT NULL REFERENCES funder(funder_id) ON DELETE CASCADE,
    program             TEXT CHECK (octet_length(program) >= 1),
    project_name        TEXT CHECK (octet_length(project_name) >= 1),
    project_shortname   TEXT CHECK (octet_length(project_shortname) >= 1),
    grant_number        TEXT CHECK (octet_length(grant_number) >= 1),
    jurisdiction        TEXT CHECK (octet_length(jurisdiction) >= 1)
);
