-- +goose Up
-- +goose StatementBegin
CREATE FUNCTION updated_at_update() RETURNS TRIGGER
    LANGUAGE plpgsql AS
$$
BEGIN
    NEW.updated_at = NOW();
RETURN NEW;
END;
$$;

CREATE TABLE IF NOT EXISTS problems
(
    id            serial         NOT NULL,
    title         varchar(64)    NOT NULL,
    legend        varchar(10240) NOT NULL DEFAULT '',
    input_format  varchar(10240) NOT NULL DEFAULT '',
    output_format varchar(10240) NOT NULL DEFAULT '',
    notes         varchar(10240) NOT NULL DEFAULT '',
    tutorial      varchar(10240) NOT NULL DEFAULT '',
    latex_summary varchar(10240) NOT NULL DEFAULT '',
    time_limit    integer        NOT NULL DEFAULT 1000,
    memory_limit  integer        NOT NULL DEFAULT 64,
    created_at    timestamptz    NOT NULL DEFAULT now(),
    updated_at    timestamptz    NOT NULL DEFAULT now(),
    PRIMARY KEY (id),
    CHECK (length(title) != 0),
    CHECK (memory_limit BETWEEN 4 and 1024),
    CHECK (time_limit BETWEEN 250 and 15000)
);

CREATE TRIGGER on_problems_update
    BEFORE UPDATE
    ON problems
    FOR EACH ROW
EXECUTE PROCEDURE updated_at_update();

CREATE TABLE IF NOT EXISTS contests
(
    id         serial      NOT NULL,
    title      varchar(64) NOT NULL,
    created_at timestamptz NOT NULL DEFAULT now(),
    updated_at timestamptz NOT NULL DEFAULT now(),
    PRIMARY KEY (id),
    CHECK (length(title) != 0)
);

CREATE TRIGGER on_contests_update
    BEFORE UPDATE
    ON contests
    FOR EACH ROW
EXECUTE PROCEDURE updated_at_update();

CREATE TABLE IF NOT EXISTS tasks
(
    id         serial      NOT NULL,
    problem_id integer     NOT NULL REFERENCES problems (id),
    contest_id integer     NOT NULL REFERENCES contests (id),
    position   integer     NOT NULL,
    created_at timestamptz NOT NULL DEFAULT now(),
    updated_at timestamptz NOT NULL DEFAULT now(),
    PRIMARY KEY (id),
    UNIQUE (problem_id, contest_id),
    UNIQUE (contest_id, position),
    CHECK (position >= 0)
);

CREATE TRIGGER on_tasks_update
    BEFORE UPDATE
    ON tasks
    FOR EACH ROW
EXECUTE PROCEDURE updated_at_update();

CREATE TABLE IF NOT EXISTS participants
(
    id         serial      NOT NULL,
    user_id    integer     NOT NULL,
    contest_id integer     NOT NULL REFERENCES contests (id),
    name       varchar(64) NOT NULL,
    created_at timestamptz NOT NULL DEFAULT now(),
    updated_at timestamptz NOT NULL DEFAULT now(),
    PRIMARY KEY (id),
    UNIQUE (user_id, contest_id),
    CHECK (length(name) != 0)
);

CREATE TRIGGER on_participants_update
    BEFORE UPDATE
    ON participants
    FOR EACH ROW
EXECUTE PROCEDURE updated_at_update();

CREATE TABLE IF NOT EXISTS solutions
(
    id             serial           NOT NULL,
    task_id        integer          NOT NULL REFERENCES tasks (id),
    participant_id integer          NOT NULL REFERENCES participants (id),
    solution       varchar(1048576) NOT NULL,
    state          integer          NOT NULL DEFAULT 1,
    score          integer          NOT NULL,
    penalty        integer          NOT NULL,
    total_score    integer          NOT NULL,
    language       integer          NOT NULL,
    updated_at     timestamptz      NOT NULL DEFAULT now(),
    created_at     timestamptz      NOT NULL DEFAULT now(),
    PRIMARY KEY (id)
);

CREATE TRIGGER on_solutions_update
    BEFORE UPDATE
    ON solutions
    FOR EACH ROW
EXECUTE PROCEDURE updated_at_update();

-- +goose StatementEnd

-- +goose Down
-- +goose StatementBegin
DROP TRIGGER IF EXISTS on_problems_update ON problems;
DROP TABLE IF EXISTS problems;
DROP TRIGGER IF EXISTS on_contests_update ON contests;
DROP TABLE IF EXISTS contests;
DROP TRIGGER IF EXISTS on_tasks_update ON tasks;
DROP TABLE IF EXISTS tasks;
DROP TRIGGER IF EXISTS on_participants_update ON participants;
DROP TABLE IF EXISTS participants;
DROP TRIGGER IF EXISTS on_solutions_update ON solutions;
DROP TABLE IF EXISTS solutions;
DROP FUNCTION updated_at_update();
-- +goose StatementEnd
