CREATE SCHEMA IF NOT EXISTS brm;

CREATE TABLE brm.members (
    member_id    INTEGER PRIMARY KEY,
    nick         TEXT NOT NULL,
    name         TEXT NOT NULL,
    surname      TEXT NOT NULL
);

CREATE OR REPLACE FUNCTION brm.ensure_member(
    i_member_id INTEGER,
    i_nick TEXT,
    i_name TEXT,
    i_surname TEXT
)
RETURNS INTEGER
LANGUAGE SQL
BEGIN ATOMIC
    INSERT INTO brm.members (member_id, nick, name, surname)
    VALUES (i_member_id, i_nick, i_name, i_surname)
    ON CONFLICT (member_id)
    DO UPDATE
        SET
        nick    = EXCLUDED.nick,
        name    = EXCLUDED.name,
        surname = EXCLUDED.surname
    RETURNING member_id;
END;

CREATE TABLE brm.meetings (
    meeting_id  INTEGER PRIMARY KEY,
    title       TEXT NOT NULL,
    held_on     TSTZRANGE NOT NULL
);

CREATE OR REPLACE FUNCTION brm.start_meeting(
    i_meeting_id INTEGER,
    i_title TEXT
)
RETURNS INTEGER
LANGUAGE SQL
BEGIN ATOMIC
INSERT INTO brm.meetings (meeting_id, title, held_on)
VALUES (
    i_meeting_id,
    i_title,
    CASE
        WHEN now() < date_trunc('day', now()) + interval '23 hours'
        THEN tstzrange(
            now(),
            date_trunc('day', now()) + interval '23 hours',
            '[)'
        )
    END
)
RETURNING meeting_id;
END;

CREATE TABLE brm.votes (
    vote_id     SERIAL PRIMARY KEY,
    meeting_id  INTEGER NOT NULL REFERENCES brm.meetings(meeting_id),
    title       TEXT NOT NULL,
    open_time   TSTZRANGE NOT NULL,
    is_active   BOOLEAN NOT NULL DEFAULT FALSE
);

CREATE TABLE brm.meeting_member_status (
    member_id    INTEGER NOT NULL REFERENCES brm.members(member_id),
    meeting_id   INTEGER NOT NULL REFERENCES brm.meetings(meeting_id),
    in_debt      BOOLEAN NOT NULL,
    short_tenure BOOLEAN NOT NULL,
    has_vote     BOOLEAN NOT NULL,
    eligible     BOOLEAN NOT NULL,
    present      BOOLEAN NOT NULL DEFAULT FALSE,
    PRIMARY KEY (member_id, meeting_id)
);

CREATE OR REPLACE FUNCTION brm.record_meeting_member_status(
    i_meeting_id INTEGER,
    i_member_id INTEGER,
    i_in_debt BOOLEAN,
    i_short_tenure BOOLEAN,
    i_has_vote BOOLEAN
)
RETURNS INTEGER
LANGUAGE SQL
BEGIN ATOMIC
    INSERT INTO brm.meeting_member_status (member_id, meeting_id, in_debt, short_tenure, has_vote, eligible)
    SELECT i_member_id, i_meeting_id, i_in_debt, i_short_tenure, i_has_vote, i_has_vote
    RETURNING member_id;
END;

CREATE OR REPLACE FUNCTION brm.record_current_meeting_member_status(
    i_member_id INTEGER,
    i_in_debt BOOLEAN,
    i_short_tenure BOOLEAN,
    i_has_vote BOOLEAN
)
RETURNS INTEGER
LANGUAGE SQL
BEGIN ATOMIC
    SELECT brm.record_meeting_member_status((SELECT MAX(meeting_id) FROM brm.meetings),
        i_member_id, i_in_debt, i_short_tenure, i_has_vote);
END;



CREATE TABLE brm.vote_member_status (
    member_id    INTEGER NOT NULL REFERENCES brm.members(member_id),
    meeting_id   INTEGER NOT NULL REFERENCES brm.meetings(meeting_id),
    vote_id      INTEGER NOT NULL REFERENCES brm.votes(vote_id),
    in_debt      BOOLEAN NOT NULL,
    short_tenure BOOLEAN NOT NULL,
    has_vote     BOOLEAN NOT NULL,
    eligible     BOOLEAN NOT NULL,
    present      BOOLEAN NOT NULL,
    PRIMARY KEY (member_id, meeting_id, vote_id)
);

CREATE OR REPLACE FUNCTION brm.create_vote_and_init_status(
    i_meeting_id INTEGER,
    i_title TEXT
)
RETURNS INTEGER
LANGUAGE SQL
BEGIN ATOMIC
    WITH new_vote AS (
        INSERT INTO brm.votes (meeting_id, title, open_time, is_active)
        VALUES (i_meeting_id, i_title, tstzrange(now(), now()+interval '30 minutes'), TRUE)
        RETURNING vote_id, meeting_id
    ),
    copied AS (
        INSERT INTO brm.vote_member_status (
            member_id,
            meeting_id,
            vote_id,
            in_debt,
            short_tenure,
            has_vote,
            eligible
        )
        SELECT
            m.member_id,
            m.meeting_id,
            v.vote_id,
            m.in_debt,
            m.short_tenure,
            m.has_vote,
            m.eligible
        FROM brm.meeting_member_status m
        JOIN new_vote v ON v.meeting_id = m.meeting_id
    )
    SELECT vote_id FROM new_vote;
END;

CREATE OR REPLACE FUNCTION brm.new_vote_for_current_meeting(
    i_title TEXT
)
RETURNS INTEGER
LANGUAGE SQL
BEGIN ATOMIC
    SELECT brm.create_vote_and_init_status((SELECT MAX(meeting_id) FROM brm.meetings), i_title);
END;

CREATE OR REPLACE FUNCTION brm.sync_vote_present_to_meeting(i_member_id INTEGER, i_meeting_id INTEGER, i_present BOOLEAN)
RETURNS VOID
LANGUAGE SQL
BEGIN ATOMIC
    UPDATE brm.meeting_member_status
    SET present = i_present
    WHERE member_id = i_member_id AND meeting_id = i_meeting_id;
END;

CREATE OR REPLACE FUNCTION brm.sync_meeting_present_to_votes(i_member_id INTEGER, i_meeting_id INTEGER, i_present BOOLEAN)
RETURNS VOID
LANGUAGE SQL
BEGIN ATOMIC
    UPDATE brm.vote_member_status
    SET present = i_present
    WHERE member_id = i_member_id
      AND meeting_id = i_meeting_id
      AND EXISTS (SELECT 1 FROM brm.votes WHERE meeting_id = i_meeting_id AND is_active = TRUE);
END;

----------------------------------------------------------------
-- vim: set et sw=4 ts=4 :
