-- Перечисление для пола
CREATE TYPE gender_enum AS ENUM (
    'male', -- мужчина
    'female' -- женщина
);

-- Перечисление для типа обследования
CREATE TYPE examination_categories_enum AS ENUM (
    'physical', -- физикальное обследование
    'laboratory', -- лабораторное обследование
    'instrumental' -- инструментальное обследование
);

-- Перечисление для исхода госпитализации (выписка)
CREATE TYPE hospital_discharge_reason_enum AS ENUM (
    'death', -- смерть
    'improvement', -- улучшение состояния
    'refusal' -- отказ от госпитализации или дальнейшего лечения
);

-- Перечисление для контекста использования единицы измерения
CREATE TYPE unit_context_enum AS ENUM (
    'examination', -- используется только для обследований (лабораторные, инструментальные, физикальные)
    'medication' -- используется только для лекарственных средств (дозировка, количество)
);

-- Функция: нет двойных пробелов подряд
CREATE OR REPLACE FUNCTION no_double_space (str text)
    RETURNS boolean
    AS $$
BEGIN
    RETURN str !~ E'\s{2,}';
END;
$$
LANGUAGE plpgsql
IMMUTABLE;

-- Функция: нет пробелов в начале и конце строки
CREATE OR REPLACE FUNCTION no_space_start_end (str text)
    RETURNS boolean
    AS $$
BEGIN
    RETURN str !~ E'^\s'
        AND str !~ E'\s$';
END;
$$
LANGUAGE plpgsql
IMMUTABLE;

-- Функция: нет пробелов вообще
CREATE OR REPLACE FUNCTION no_space (str text)
    RETURNS boolean
    AS $$
BEGIN
    RETURN str !~ E'\s';
END;
$$
LANGUAGE plpgsql
IMMUTABLE;

-- Функция: длина строки в заданных границах
CREATE OR REPLACE FUNCTION str_length_between (str text, min_len int, max_len int)
    RETURNS boolean
    AS $$
BEGIN
    RETURN LENGTH(str) BETWEEN min_len AND max_len;
END;
$$
LANGUAGE plpgsql
IMMUTABLE;

-- Функция: стандартная проверка для слова
CREATE OR REPLACE FUNCTION default_word_check (str text)
    RETURNS boolean
    AS $$
BEGIN
    RETURN str IS NULL
        OR no_space (str)
        AND str_length_between (str, 1, 64);
END;
$$
LANGUAGE plpgsql
IMMUTABLE;

-- Функция: стандартная проверка для строки
CREATE OR REPLACE FUNCTION default_str_check (str text)
    RETURNS boolean
    AS $$
BEGIN
    RETURN str IS NULL
        OR no_double_space (str)
        AND no_space_start_end (str)
        AND str_length_between (str, 1, 128);
END;
$$
LANGUAGE plpgsql
IMMUTABLE;


-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
-- Люди
-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
--
-- Справочник людей
CREATE TABLE person (
    person_id serial PRIMARY KEY,
    -- фамилия
    last_name text NOT NULL CHECK (default_word_check (last_name)),
    -- имя
    first_name text NOT NULL CHECK (default_word_check (first_name)),
    -- отчество
    middle_name text CHECK (default_word_check (middle_name)),
    -- дата рождения
    birth_date date NOT NULL CHECK (birth_date <= CURRENT_DATE),
    -- пол
    gender text NOT NULL,
    -- место жительства
    address text NOT NULL CHECK (default_str_check (address))
);

-- Справочник пациентов
CREATE TABLE patient (
    patient_id int PRIMARY KEY REFERENCES person (person_id),
    policy_number text NOT NULL CHECK (policy_number ~ '^[0-9]{16}$')
);

-- Справочник врачей
CREATE TABLE doctor (
    doctor_id int PRIMARY KEY REFERENCES person (person_id)
);

CREATE TABLE registrar (
    registrar_id int PRIMARY KEY REFERENCES person (person_id)
);

-- Справочник единиц измерения для числовых результатов
CREATE TABLE unit (
    unit_id serial PRIMARY KEY,
    name text NOT NULL CHECK (name ~ '^[а-яА-ЯёЁ%^/]+$' AND str_length_between (name, 1, 16)),
    UNIQUE (name)
);

-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
-- Назначения
-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
--
-- Базовая таблица назначения (TPT)
CREATE TABLE prescription (
    prescription_id serial PRIMARY KEY,
    -- пациент
    patient_id int NOT NULL REFERENCES patient (patient_id) ON DELETE CASCADE,
    -- врач
    doctor_id int NOT NULL REFERENCES doctor (doctor_id) ON DELETE RESTRICT
);

-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
-- Обследования
-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
--
-- Справочник типов обследований (Общий анализ крови", "ЭКГ", "УЗИ печени")
CREATE TABLE examination_type (
    examination_type_id serial PRIMARY KEY,
    -- название типа обследования (одно слово, без пробелов)
    name text NOT NULL CHECK (default_word_check (name)),
    -- категория обследования
    category text NOT NULL,
    UNIQUE (name)
);

-- Общая таблица результатов обследований (TPT)
CREATE TABLE result (
    result_id serial PRIMARY KEY,
    examination_id int NOT NULL REFERENCES examination_type (examination_type_id) ON DELETE CASCADE
);

-- Журнал фактических обследований пациентов
CREATE TABLE examination_type_prescription (
    examination_prescription_id serial PRIMARY KEY,
    prescription_id int NOT NULL REFERENCES prescription (prescription_id) ON DELETE CASCADE,
	result_id int REFERENCES result (result_id) ON DELETE CASCADE,
    -- тип обследования
    examination_type_id int NOT NULL REFERENCES examination_type (examination_type_id) ON DELETE CASCADE,
    UNIQUE (prescription_id)
);

-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
-- Фактические результаты обследований
-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
--

-- Числовой результат обследования пациента (только один на обследование)
CREATE TABLE numeric_result (
    -- обследование пациента
    result_id int PRIMARY KEY REFERENCES result (result_id) ON DELETE CASCADE,
    -- значение результата
    value numeric NOT NULL,
    -- единица измерения
    unit_id int NOT NULL REFERENCES unit (unit_id) ON DELETE RESTRICT
);

-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
-- Нормальные результаты обследований
-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
--
-- Качественный результат обследования пациента (только один на обследование)
CREATE TABLE qualitative_result (
    -- обследование пациента
    result_id int PRIMARY KEY REFERENCES result (result_id) ON DELETE CASCADE,
    -- признак отклонения
    value boolean NOT NULL
);

-- Общая таблица для справочника референсных (нормальных) значений (TPT)
CREATE TABLE reference_value (
    reference_value_id serial PRIMARY KEY,
    examination_type_id int NOT NULL REFERENCES examination_type (examination_type_id) ON DELETE CASCADE,
    gender text, -- пол (если норма специфична)
    age_min int, -- нижняя граница возраста (если есть зависимость)
    age_max int, -- верхняя граница возраста (если есть зависимость)
    CHECK (
        (age_min IS NULL OR age_max IS NULL) -- если один из параметров не задан, не сравниваем
        OR (age_min < age_max)               -- если оба заданы, min < max
    ),
    UNIQUE (examination_type_id, gender, age_min, age_max)
);

-- Справочник референсных (нормальных) значений для числовых обследований
CREATE TABLE reference_numeric_value (
    reference_value_id int PRIMARY KEY REFERENCES reference_value (reference_value_id) ON DELETE CASCADE,
    min_value numeric,
    max_value numeric,
    unit_id int NOT NULL REFERENCES unit (unit_id) ON DELETE RESTRICT
);

-- Справочник референсных (нормальных) значений для качественных обследований
CREATE TABLE reference_qualitative_value (
    reference_value_id int PRIMARY KEY REFERENCES reference_value (reference_value_id) ON DELETE CASCADE,
    description_true text NOT NULL CHECK (default_word_check (description_true)),
    description_false text NOT NULL CHECK (default_word_check (description_false)),
    UNIQUE (description_true, description_false)
);

-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
-- Синдромы
-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
--
-- Справочник синдромов
CREATE TABLE syndrome_type (
    syndrome_type_id serial PRIMARY KEY,
    name text NOT NULL CHECK (default_word_check (name)),
    UNIQUE (name)
);

-- Соответствие синдромов и типов обследований (определяет, какое обследование позволяет определить синдром)
CREATE TABLE syndrome_examination_type (
    syndrome_id int PRIMARY KEY REFERENCES syndrome_type (syndrome_type_id) ON DELETE CASCADE,
    examination_type_id int NOT NULL REFERENCES examination_type (examination_type_id) ON DELETE CASCADE,
    UNIQUE (examination_type_id)
);

-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
-- Болезни и диагнозы
-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
--
-- Справочник заболеваний
CREATE TABLE disease (
    disease_id serial PRIMARY KEY,
    -- русское наименование
    name text NOT NULL CHECK (default_str_check (name)),
    -- код МКБ в формате A12.3
    icd_code text NOT NULL CHECK (icd_code ~ '^[A-Z][0-9]{2}\.[0-9]$'),
    UNIQUE (name),
    UNIQUE (icd_code)
);

-- Соответствие заболеваний и синдромов
CREATE TABLE disease_syndrome (
    disease_syndrome_id SERIAL PRIMARY KEY,
    disease_id int NOT NULL REFERENCES disease (disease_id) ON DELETE CASCADE,
    syndrome_id int NOT NULL REFERENCES syndrome_type (syndrome_type_id) ON DELETE CASCADE,
    UNIQUE (disease_id, syndrome_id)
);

-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
-- Госпитализация
-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
--
-- Госпитализация (начало)
CREATE TABLE hospital_admission (
    hospital_admission_id serial PRIMARY KEY,
    -- пациент
    patient_id int NOT NULL REFERENCES patient (patient_id) ON DELETE CASCADE,
    -- предварительный диагноз
    preliminary_disease_id int NOT NULL REFERENCES disease (disease_id),
    -- дата и время поступления
    admission_datetime timestamp NOT NULL CHECK (admission_datetime <= CURRENT_TIMESTAMP)
);

-- Завершение госпитализации
CREATE TABLE hospital_discharge (
    hospital_discharge_id serial PRIMARY KEY,
    hospital_admission_id int NOT NULL REFERENCES hospital_admission (hospital_admission_id) ON DELETE CASCADE,
    -- дата и время выписки/смерти
    discharge_datetime timestamp NOT NULL CHECK (discharge_datetime <= CURRENT_TIMESTAMP),
    final_disease_id int NOT NULL REFERENCES disease (disease_id),
    -- причина завершения
    reason text NOT NULL
);

-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
-- Лекарства
-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
--
-- Справочник способов приёма лекарств
CREATE TABLE drug_intake_method (
    drug_intake_method_id serial PRIMARY KEY,
    -- наименование способа (например, "перорально", "внутримышечно", "внутривенно", "ингаляционно", "ректально")
    name text NOT NULL CHECK (default_word_check (name)),
    UNIQUE (name)
);

-- Справочник лекарств
CREATE TABLE drug_type (
    drug_type_id serial PRIMARY KEY,
    international_name_ru text NOT NULL CHECK (default_word_check (international_name_ru)),
    international_name_en text CHECK (default_word_check (international_name_en)),
    international_name_la text CHECK (default_word_check (international_name_la)),
    brand_name_ru text CHECK (default_word_check (brand_name_ru)),
    UNIQUE (international_name_ru),
    UNIQUE (international_name_en),
    UNIQUE (international_name_la),
    UNIQUE (brand_name_ru)
);

-- Журнал фактических назначений лекарств пациенту
CREATE TABLE drug_type_prescription  (
    drug_prescription_id serial PRIMARY KEY,
    prescription_id int NOT NULL REFERENCES prescription (prescription_id) ON DELETE CASCADE,
    drug_type_id int NOT NULL REFERENCES drug_type (drug_type_id) ON DELETE RESTRICT,
    -- количество вещества за приём
    dose numeric NOT NULL CHECK (dose > 0),
    -- единица измерения дозы
    dose_unit_id int NOT NULL REFERENCES unit (unit_id) ON DELETE RESTRICT,
    -- способ приёма
    intake_method_id int NOT NULL REFERENCES drug_intake_method (drug_intake_method_id) ON DELETE RESTRICT,
    -- длительность приёма (в днях)
    duration_days int NOT NULL CHECK (duration_days > 0),
    UNIQUE (prescription_id)
);

-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
-- Процедуры (для пациента)
-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
--
-- Справочник типов процедур
CREATE TABLE procedure_type (
    procedure_type_id serial PRIMARY KEY,
    -- наименование процедуры (например, "физиотерапия")
    name text NOT NULL CHECK (default_word_check (name)),
    UNIQUE (name)
);

-- Журнал фактических назначений процедур пациенту
CREATE TABLE procedure_type_prescription (
    procedure_prescription_id serial PRIMARY KEY,
    prescription_id int NOT NULL REFERENCES prescription (prescription_id) ON DELETE CASCADE,
    procedure_type_id int NOT NULL REFERENCES procedure_type (procedure_type_id) ON DELETE RESTRICT,
    scheduled_datetime timestamp NOT NULL,
    UNIQUE (prescription_id)
);


-- Общая функция возвращения всех госпитализаций и периодов пациента
CREATE OR REPLACE FUNCTION get_hospitalization_periods (p_patient_id int)
    RETURNS TABLE (
        admission_datetime timestamp,
        discharge_datetime timestamp
    )
    AS $$
BEGIN
    RETURN QUERY
    SELECT
        ha.admission_datetime,
        hd.discharge_datetime
    FROM
        hospital_admission ha
    LEFT JOIN hospital_discharge hd ON ha.hospital_admission_id = hd.hospital_admission_id
WHERE
    ha.patient_id = p_patient_id;
END;
$$
LANGUAGE plpgsql;

-- Триггер: запрещает новую госпитализацию при наличии незавершённой
CREATE OR REPLACE FUNCTION check_active_hospitalization ()
    RETURNS TRIGGER
    AS $$
DECLARE
    open_hospitalization boolean;
BEGIN
    SELECT
        EXISTS (
            SELECT
                1
            FROM
                get_hospitalization_periods (NEW.patient_id)
            WHERE
                discharge_datetime IS NULL) INTO open_hospitalization;
    IF open_hospitalization THEN
        RAISE EXCEPTION
            USING ERRCODE = 'P0001', MESSAGE = '10001: ACTIVE_HOSPITALIZATION_EXISTS';
        END IF;
        RETURN NEW;
END;
$$
LANGUAGE plpgsql;

-- Триггер: запрещает перекрытие госпитализаций
CREATE OR REPLACE FUNCTION check_hospitalization_overlap ()
    RETURNS TRIGGER
    AS $$
DECLARE
    overlap_found boolean;
BEGIN
    SELECT
        EXISTS (
            SELECT
                1
            FROM
                get_hospitalization_periods (NEW.patient_id)
            WHERE
                discharge_datetime IS NOT NULL
                AND NEW.admission_datetime < discharge_datetime
                AND NEW.admission_datetime > admission_datetime) INTO overlap_found;
    IF overlap_found THEN
        RAISE EXCEPTION
            USING ERRCODE = 'P0001', MESSAGE = '10002: HOSPITALIZATION_OVERLAP';
        END IF;
        RETURN NEW;
END;
$$
LANGUAGE plpgsql;

-- Подключение триггеров на hospital_admissions
CREATE TRIGGER trg_check_active_hospitalization
    BEFORE INSERT ON hospital_admission
    FOR EACH ROW
    EXECUTE FUNCTION check_active_hospitalization ();

CREATE TRIGGER trg_check_hospitalization_overlap
    BEFORE INSERT ON hospital_admission
    FOR EACH ROW
    EXECUTE FUNCTION check_hospitalization_overlap ();


-- Проверка: выписка должна быть позже поступления
CREATE OR REPLACE FUNCTION check_discharge_after_admission ()
    RETURNS TRIGGER
    AS $$
DECLARE
    admission_time timestamp;
BEGIN
    SELECT
        admission_datetime INTO admission_time
    FROM
        hospital_admission
    WHERE
        hospital_admission_id = NEW.hospital_admission_id;
    IF NEW.discharge_datetime <= admission_time THEN
        RAISE EXCEPTION
            USING ERRCODE = 'P0001', MESSAGE = '10003: DISCHARGE_BEFORE_ADMISSION';
        END IF;
        RETURN NEW;
END;
$$
LANGUAGE plpgsql;

CREATE TRIGGER trg_check_discharge_after_admission
    BEFORE INSERT OR UPDATE ON hospital_discharge
    FOR EACH ROW
    EXECUTE FUNCTION check_discharge_after_admission ();

-- Триггер: нельзя создать выписку, если уже есть выписка по этой госпитализации
CREATE OR REPLACE FUNCTION check_unique_discharge ()
    RETURNS TRIGGER
    AS $$
DECLARE
    discharge_count integer;
BEGIN
    SELECT
        COUNT(*) INTO discharge_count
    FROM
        hospital_discharge
    WHERE
        hospital_admission_id = NEW.hospital_admission_id
        AND hospital_discharge_id <> COALESCE(NEW.hospital_discharge_id, -1);
    IF discharge_count > 0 THEN
        RAISE EXCEPTION
            USING ERRCODE = 'P0001', MESSAGE = '10004: DISCHARGE_ALREADY_EXISTS';
        END IF;
        RETURN NEW;
END;
$$
LANGUAGE plpgsql;

CREATE TRIGGER trg_check_unique_discharge
    BEFORE INSERT OR UPDATE ON hospital_discharge
    FOR EACH ROW
    EXECUTE FUNCTION check_unique_discharge ();



-- Триггер: запрет на запись числового результата, если есть качественный по тому же обследованию
CREATE OR REPLACE FUNCTION check_numeric_result_uniqueness ()
    RETURNS TRIGGER
    AS $$
DECLARE
    qualitative_exists boolean;
BEGIN
    SELECT
        EXISTS (
            SELECT
                1
            FROM
                qualitative_result
            WHERE
                result_id = NEW.result_id) INTO qualitative_exists;
    IF qualitative_exists THEN
        RAISE EXCEPTION
            USING ERRCODE = 'P0001', MESSAGE = '10005: QUALITATIVE_RESULT_ALREADY_EXISTS_FOR_THIS_EXAMINATION';
        END IF;
        RETURN NEW;
END;
$$
LANGUAGE plpgsql;

CREATE TRIGGER trg_check_numeric_result_uniqueness
    BEFORE INSERT OR UPDATE ON numeric_result
    FOR EACH ROW
    EXECUTE FUNCTION check_numeric_result_uniqueness ();



-- Триггер: запрет на запись качественного результата, если есть числовой по тому же обследованию
CREATE OR REPLACE FUNCTION check_qualitative_result_uniqueness ()
    RETURNS TRIGGER
    AS $$
DECLARE
    numeric_exists boolean;
BEGIN
    SELECT
        EXISTS (
            SELECT
                1
            FROM
                numeric_result
            WHERE
                result_id = NEW.result_id) INTO numeric_exists;
    IF numeric_exists THEN
        RAISE EXCEPTION
            USING ERRCODE = 'P0001', MESSAGE = '10006: NUMERIC_RESULT_ALREADY_EXISTS_FOR_THIS_EXAMINATION';
        END IF;
        RETURN NEW;
END;
$$
LANGUAGE plpgsql;

CREATE TRIGGER trg_check_qualitative_result_uniqueness
    BEFORE INSERT OR UPDATE ON qualitative_result
    FOR EACH ROW
    EXECUTE FUNCTION check_qualitative_result_uniqueness ();



CREATE OR REPLACE FUNCTION get_results() 
RETURNS TABLE ("Пациент" text, "Обследование" text, "Результат" varchar) 
AS $$
BEGIN
    RETURN QUERY(SELECT pa.policy_number, et.name, COALESCE(qr.value::varchar, CONCAT(nr.value || ' ' || u.name))
				FROM patient pa
				LEFT JOIN prescription pr 
					ON pa.patient_id = pr.patient_id
				LEFT JOIN examination_type_prescription etp 
					ON pr.prescription_id = etp.prescription_id
				LEFT JOIN examination_type et
					ON et.examination_type_id = etp.examination_type_id
				LEFT JOIN result r
					ON etp.result_id = r.result_id
				LEFT JOIN qualitative_result qr
					ON r.result_id = qr.result_id
				LEFT JOIN numeric_result nr
					ON r.result_id = nr.result_id
				LEFT JOIN unit u
					ON nr.unit_id = u.unit_id
				WHERE et.name IS NOT NULL);
END;
$$ LANGUAGE plpgsql;




CREATE EXTENSION IF NOT EXISTS pgcrypto;



CREATE TABLE person_account(
	person_id int NOT NULL UNIQUE REFERENCES person,
	login varchar(60) NOT NULL,
	password varchar NOT NULL,
	CONSTRAINT empty_login CHECK (trim(login) <> '')
);

CREATE OR REPLACE FUNCTION check_password(_password varchar(60))
RETURNS void AS
$BODY$
BEGIN
	IF (trim(_password) = '')
	THEN
		RAISE EXCEPTION 'Пароль не может быть пустым!';
	END IF;

	IF (trim(_password) <> _password)
	THEN
		RAISE EXCEPTION 'Пароль должен быть без пробелов!';
	END IF;

	IF (length(_password) < 8)
	THEN
		RAISE EXCEPTION 'Пароль должен иметь больше 8 знаков!';
	END IF;

	IF (lower(_password) = _password OR _password !~ '[0-9]')
	THEN
		RAISE EXCEPTION 'Пароль должен иметь прописные и заглавные буквы, а также цифры!';
	END IF;

	IF ((SELECT COUNT(*) AS letter_count
		FROM ( SELECT regexp_split_to_table(_password, '') AS letter) AS letters
		GROUP BY letter
		ORDER BY letter
		LIMIT 1) >= length(_password)/2)
	THEN
		RAISE EXCEPTION 'Пароль не должен иметь больше половины одинаковых символов!';
	END IF;
END
$BODY$
LANGUAGE plpgsql VOLATILE;

CREATE OR REPLACE FUNCTION create_person_account()
RETURNS TRIGGER AS $$
DECLARE
	role int;
BEGIN
    PERFORM check_password(NEW.password);
    NEW.password := crypt(NEW.password, gen_salt('bf'));
	
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- Создаем триггер
CREATE TRIGGER trigger_create_account
BEFORE INSERT ON person_account
FOR EACH ROW
EXECUTE FUNCTION create_person_account();

CREATE OR REPLACE FUNCTION check_enter_in_person_account(_login varchar, _password varchar)
RETURNS int AS $$
DECLARE
	_hash_password varchar := null;
    _person_id int;
BEGIN
    -- Получаем person_id и проверяем авторизацию
    SELECT pa.person_id, pa.password
    INTO _person_id, _hash_password
    FROM person_account pa
    WHERE pa.login = _login
    AND pa.password = crypt(_password, pa.password);

    -- Если запись не найдена
    IF _person_id IS NULL THEN
        RAISE EXCEPTION 'Неверный логин или пароль!';
    END IF;
	
	RETURN _person_id;
END;
$$ LANGUAGE plpgsql;


-- person
INSERT INTO public.person (person_id, middle_name, first_name, last_name, birth_date, gender, address) VALUES
(1, 'Иванов', 'Николай', 'Владимирович', '1954-10-26', 'male', 'ул. Чайковского, дом 32, квартира 46'),
(2, 'Сидоров', 'Владимир', 'Анатольевич', '1956-12-30', 'male', 'пр. Мира, дом 37, квартира 47'),
(3, 'Кузнецов', 'Пётр', 'Сергеевич', '1978-04-12', 'male', 'ул. Кирова, дом 29, квартира 55'),
(4, 'Петров', 'Иван', 'Владимирович', '2005-09-15', 'male', 'ул. Чайковского, дом 16, квартира 108'),
(5, 'Иванов', 'Николай', 'Андреевич', '1973-11-16', 'male', 'ул. Молодёжная, дом 28, квартира 41'),
(6, 'Иванов', 'Егор', 'Сергеевич', '1987-05-21', 'male', 'ул. Гагарина, дом 3, квартира 92'),
(8, 'апраоплр', 'апарспмориолтьмтич', 'выавпасрмо', '2001-11-28', 'Мужчина', 'вавпраоплдожропав'),
(7, 'впа', 'апр', 'авыпро', '2005-11-28', 'Женщина', 'впарплоро');

insert into doctor (doctor_id)
values (1),
		(2),
		(3);

insert into registrar (registrar_id)
values (4),
		(5),
		(6);

-- patient
INSERT INTO public.patient (patient_id, policy_number) VALUES
(7, '3456789787654322'),
(8, '1232567687654231');


INSERT INTO person_account (person_id, login, password)
VALUES (1, 'Иванов Н.В.', 'Иванов123'),
	(2, 'Сидоров В.А.', 'Сидоров123'),
	(3, 'Кузнецов П.С.', 'Кузнецов123'),
	(4, 'Петров И.В.', 'Петров123'),
	(5, 'Иванов Н.А.', 'Иванов123'),
	(6, 'Иванов Е.С.', 'Иванов123');

-- unit
INSERT INTO public.unit (unit_id, name) VALUES
(2, 'мг/л'),
(3, 'г/л'),
(4, 'ммоль/л'),
(5, 'мкмоль/л'),
(6, 'ед/л'),
(7, '%'),
(8, 'тыс/мкл'),
(9, 'мл'),
(10, 'мм');

-- disease
INSERT INTO public.disease (disease_id, name, icd_code) VALUES
(34, 'Губчатая энцефалопатия', 'A12.3'),
(35, 'Красная волчанка', 'A12.5'),
(29, 'Проказа', 'A12.4'),
(36, 'Грипп', 'A12.2');

-- syndrome_type
INSERT INTO public.syndrome_type (syndrome_type_id, name) VALUES
(1, 'Лихорадка'),
(2, 'Боль в груди');

-- disease_syndrome
INSERT INTO public.disease_syndrome (disease_syndrome_id, disease_id, syndrome_id) VALUES
(1, 29, 1);

-- drug_intake_method
INSERT INTO public.drug_intake_method (drug_intake_method_id, name) VALUES
(2, 'Внутримышечно');

-- drug_type
INSERT INTO public.drug_type (drug_type_id, international_name_ru, international_name_en, international_name_la, brand_name_ru) VALUES
(3, 'Корвалол', NULL, NULL, NULL),
(2, 'Парацетамол', 'Paracetamol', NULL, NULL);

-- drug_type_prescription
-- Таблица пустая

-- examination_type
INSERT INTO public.examination_type (examination_type_id, name, category) VALUES
(2, 'ЭКГ', 'Физикальное'),
(3, 'ЭЭГ', 'Инструментальное');

-- reference_value
INSERT INTO public.reference_value (reference_value_id, examination_type_id, gender, age_min, age_max) VALUES
(4, 2, 'Мужчина', NULL, 18),
(5, 3, 'Женщина', NULL, 18);

-- hospital_admission
INSERT INTO public.hospital_admission (hospital_admission_id, patient_id, preliminary_disease_id, admission_datetime) VALUES
(21, 8, 29, '2025-11-30 20:31:06.045'),
(30, 7, 35, '2025-11-30 20:45:06.045254');

-- hospital_discharge
INSERT INTO public.hospital_discharge (hospital_discharge_id, hospital_admission_id, discharge_datetime, final_disease_id, reason) VALUES
(1, 21, '2025-12-01 15:59:02.624121', 36, 'Ложная тревога');

-- result
INSERT INTO public.result (result_id, examination_id) VALUES
(5, 3),
(7, 3),
(8, 2),
(9, 3),
(10, 2);

-- numeric_result
INSERT INTO public.numeric_result (result_id, value, unit_id) VALUES
(7, 1.00, 7),
(8, 1.00, 7),
(9, 12.00, 3),
(10, 1.00, 3);

-- prescription
INSERT INTO public.prescription (prescription_id, patient_id, doctor_id) VALUES
(2, 8, 1),
(23, 7, 1),
(24, 7, 2);

-- procedure_type
INSERT INTO public.procedure_type (procedure_type_id, name) VALUES
(3, 'Физиотерапия');

-- procedure_type_prescription
INSERT INTO public.procedure_type_prescription (procedure_prescription_id, prescription_id, procedure_type_id, scheduled_datetime) VALUES
(3, 2, 3, '2025-11-29 11:11:25.048055');

-- qualitative_result
INSERT INTO public.qualitative_result (result_id, value) VALUES
(5, true);

-- reference_numeric_value
INSERT INTO public.reference_numeric_value (reference_value_id, min_value, max_value, unit_id) VALUES
(4, NULL, 1, 7);

-- reference_qualitative_value
INSERT INTO public.reference_qualitative_value (reference_value_id, description_true, description_false) VALUES
(4, 'Отсутствует', 'Отсутствует');

-- examination_type_prescription
INSERT INTO public.examination_type_prescription (examination_prescription_id, prescription_id, result_id, examination_type_id) VALUES
(7, 2, 5, 3),
(11, 23, 9, 3),
(12, 24, 10, 2);

-- syndrome_examination_type
INSERT INTO public.syndrome_examination_type (syndrome_id, examination_type_id) VALUES
(2, 3);