CREATE SCHEMA IF NOT EXISTS institutions;

CREATE EXTENSION IF NOT EXISTS "pgcrypto";
CREATE EXTENSION IF NOT EXISTS "pg_trgm";

CREATE OR REPLACE FUNCTION institutions.update_lastupdated_timestamp()
RETURNS TRIGGER AS $$
BEGIN
   NEW.last_updated_at = now();
   RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TABLE institutions.country (
    country_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    iso_code VARCHAR NOT NULL,
    name_english VARCHAR NOT NULL,
    name_official VARCHAR,
    name_short VARCHAR,
    publicated BOOLEAN NOT NULL,
    hidden BOOLEAN,
    country_group VARCHAR NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE institutions.location (
    location_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    id_original VARCHAR NOT NULL,
    country_id UUID NOT NULL REFERENCES institutions.country(country_id),
    origin_name VARCHAR NOT NULL,
    name_short VARCHAR,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE institutions.institution_type (
    institution_type_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name_short VARCHAR,
    status VARCHAR CHECK (status IN ('H +', 'H -', 'H +/-')),
    comment TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE institutions.institution (
    institution_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    id_original VARCHAR NOT NULL,
    country_id UUID NOT NULL REFERENCES institutions.country(country_id),
    location_id UUID REFERENCES institutions.location(location_id),
    institution_type_id UUID NOT NULL REFERENCES institutions.institution_type(institution_type_id),
    name_short VARCHAR,
    abbreviation VARCHAR,
    homepage VARCHAR,
    name_german VARCHAR,
    address_street VARCHAR,
    address_zip VARCHAR,
    address_city VARCHAR,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE institutions.degree_type (
    degree_type_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    id_original VARCHAR NOT NULL,
    country_id UUID NOT NULL REFERENCES institutions.country(country_id),
    name_short VARCHAR,
    name_german VARCHAR,
    name_female VARCHAR,
    name_female_german VARCHAR,
    comment TEXT,
    hide_requirement BOOLEAN,
    requirement TEXT,
    additional_requirement TEXT,
    hide_studies BOOLEAN,
    studies_min_length FLOAT,
    studies_max_length FLOAT,
    explanation_studies_length TEXT,
    studies_description TEXT,
    abbreviation VARCHAR,
    abbreviation_female VARCHAR,
    degree_class VARCHAR CHECK (degree_class IN ('A1', 'A2', 'A3', 'A4', 'A5', 'PGS', 'NZ', 'D1', 'D2', 'HC')),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE institutions.degree_type_equivalence (
    degree_type_equivalence_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    id_original VARCHAR NOT NULL,
    degree_type_id UUID NOT NULL REFERENCES institutions.degree_type(degree_type_id),
    hidden BOOLEAN,
    equivalence_class VARCHAR NOT NULL,
    comment TEXT,
    admin_comment TEXT,
    internal_comment TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE institutions.degree_field_of_study (
    degree_field_of_study_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    id_original VARCHAR NOT NULL,
    country_id UUID NOT NULL REFERENCES institutions.country(country_id),
    name_short VARCHAR,
    name_german VARCHAR,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE institutions.degree (
    degree_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    id_original VARCHAR NOT NULL,
    country_id UUID NOT NULL REFERENCES institutions.country(country_id),
    degree_type_id UUID REFERENCES institutions.degree_type(degree_type_id),
    field_of_study_id UUID REFERENCES institutions.degree_field_of_study(degree_field_of_study_id),
    degree_short VARCHAR,
    name_short VARCHAR,
    name_german VARCHAR,
    name_female VARCHAR,
    name_female_german VARCHAR,
    comment TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE institutions.alias_name (
    alias_name_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    type VARCHAR NOT NULL CHECK (type IN ('alias', 'alternative', 'outdated')),
    id_original VARCHAR NOT NULL,
    name_short VARCHAR,
    name_german VARCHAR,
    comment TEXT,
    hidden BOOLEAN,
    deleted BOOLEAN,
    language_id VARCHAR,
    name_translated VARCHAR,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE institutions.entity_name_link (
    entity_type VARCHAR NOT NULL CHECK (entity_type IN ('degree', 'institution', 'location', 'degree_type')),
    entity_id UUID NOT NULL,
    name_id UUID NOT NULL REFERENCES institutions.alias_name(alias_name_id),
    name_type VARCHAR NOT NULL CHECK (name_type IN ('alias', 'alternative', 'outdated')),
    PRIMARY KEY (entity_type, entity_id, name_id),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE institutions.institution_degree (
    institution_id UUID REFERENCES institutions.institution(institution_id),
    degree_id UUID REFERENCES institutions.degree(degree_id),
    PRIMARY KEY (institution_id, degree_id),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE institutions.degree_equivalence (
    degree_id UUID REFERENCES institutions.degree(degree_id),
    equivalence_id UUID REFERENCES institutions.degree_type_equivalence(degree_type_equivalence_id),
    PRIMARY KEY (degree_id, equivalence_id),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE institutions.degree_type_equivalence_link (
    degree_type_id UUID REFERENCES institutions.degree_type(degree_type_id),
    equivalence_id UUID REFERENCES institutions.degree_type_equivalence(degree_type_equivalence_id),
    PRIMARY KEY (degree_type_id, equivalence_id),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

DO $$
DECLARE
    tbl TEXT;
BEGIN
    FOR tbl IN
        SELECT table_name FROM information_schema.columns
        WHERE column_name = 'last_updated_at'
          AND table_schema = 'app'
    LOOP
        EXECUTE format('
            DROP TRIGGER IF EXISTS trg_update_last_updated_at ON institutions.%I;
            CREATE TRIGGER trg_update_last_updated_at
            BEFORE UPDATE ON institutions.%I
            FOR EACH ROW
            EXECUTE FUNCTION institutions.update_lastupdated_timestamp();',
            tbl, tbl
        );
    END LOOP;
END $$;

-- Drop and recreate institution_search
CREATE OR REPLACE VIEW institutions.institution_search AS
SELECT 
    i.institution_id,
    i.name_short AS main_name_short,
    i.name_german AS main_name_german,
    a.name_short AS alias_name_short,
    a.name_german AS alias_name_german,
    a.type AS alias_type,
    it.status AS institution_status,
    GREATEST(
        similarity(i.name_short, ''),
        similarity(i.name_german, ''),
        similarity(a.name_short, ''),
        similarity(a.name_german, '')
    ) AS match_score
FROM institutions.institution i
LEFT JOIN institutions.entity_name_link enl ON enl.entity_type = 'institution' AND enl.entity_id = i.institution_id
LEFT JOIN institutions.alias_name a ON enl.name_id = a.alias_name_id
LEFT JOIN institutions.institution_type it ON i.institution_type_id = it.institution_type_id;

-- Drop and recreate degree_search
CREATE OR REPLACE VIEW institutions.degree_search AS
SELECT 
    d.degree_id,
    d.name_short AS main_name_short,
    d.name_german AS main_name_german,
    a.name_short AS alias_name_short,
    a.name_german AS alias_name_german,
    a.type AS alias_type,
    GREATEST(
        similarity(d.name_short, ''),
        similarity(d.name_german, ''),
        similarity(a.name_short, ''),
        similarity(a.name_german, '')
    ) AS match_score
FROM institutions.degree d
LEFT JOIN institutions.entity_name_link enl 
  ON enl.entity_type = 'degree' AND enl.entity_id = d.degree_id
LEFT JOIN institutions.alias_name a 
  ON enl.name_id = a.alias_name_id;

CREATE INDEX idx_inst_name_short_trgm ON institutions.institution USING gin (name_short gin_trgm_ops);
CREATE INDEX idx_inst_name_german_trgm ON institutions.institution USING gin (name_german gin_trgm_ops);
CREATE INDEX idx_alias_name_short_trgm ON institutions.alias_name USING gin (name_short gin_trgm_ops);
CREATE INDEX idx_alias_name_german_trgm ON institutions.alias_name USING gin (name_german gin_trgm_ops);
