-- =========================================================
-- PostgreSQL paplašinājums pgcrypto
-- Tiek izmantots:
-- 1) drošai paroļu hešošanai (crypt, gen_salt)
-- 2) nejaušu tokenu ģenerēšanai (gen_random_bytes)
-- =========================================================
CREATE EXTENSION IF NOT EXISTS pgcrypto;

-- =========================================================
-- LIETOTĀJU TABULA
-- Glabā pamatinformāciju par sistēmas lietotājiem
-- =========================================================
CREATE TABLE IF NOT EXISTS users (
    id SERIAL PRIMARY KEY,                 -- Unikāls lietotāja identifikators
    username VARCHAR UNIQUE NOT NULL,       -- Lietotājvārds (unikāls)
    password_hash TEXT NOT NULL,            -- Paroles hash (nekad netiek glabāta parole)
    email VARCHAR UNIQUE NOT NULL,           -- Lietotāja e-pasts (unikāls)
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -- Izveides datums
);

-- =========================================================
-- SESIJU TABULA
-- Glabā aktīvās lietotāju sesijas
-- =========================================================
CREATE TABLE IF NOT EXISTS sessions (
    id SERIAL PRIMARY KEY,                  -- Sesijas ID
    user_id INT REFERENCES users(id) ON DELETE CASCADE, 
                                            -- Saite uz users tabulu
    session_token TEXT UNIQUE NOT NULL,     -- Unikāls sesijas tokens
    expires_at TIMESTAMP NOT NULL           -- Sesijas derīguma termiņš
);

-- =========================================================
-- PIESLĒGŠANĀS ŽURNĀLS
-- Reģistrē lietotāju login / logout vēsturi
-- =========================================================
CREATE TABLE IF NOT EXISTS login_logs (
    id SERIAL PRIMARY KEY,                  -- Žurnāla ieraksta ID
    user_id INT REFERENCES users(id),       -- Saite uz lietotāju
    login_time TIMESTAMP NOT NULL,           -- Pieslēgšanās laiks
    logout_time TIMESTAMP                   -- Izrakstīšanās laiks
);

-- =========================================================
-- FUNKCIJA: create_user
-- Izveido jaunu lietotāju ar validāciju un paroles hešošanu
-- =========================================================
CREATE OR REPLACE FUNCTION create_user(
    p_username TEXT,
    p_password TEXT,
    p_email TEXT
)
RETURNS TEXT AS $$
DECLARE
    v_message TEXT;                         -- Teksts, kas tiks atgriezts frontendam
BEGIN
    -- -------------------------------------
    -- Lietotājvārda validācija
    -- -------------------------------------
    IF p_username IS NULL OR length(trim(p_username)) < 3 THEN
        RETURN 'Lietotājvārds ir par īsu.';
    END IF;

    -- -------------------------------------
    -- Paroles validācija
    -- -------------------------------------
    IF p_password IS NULL OR length(p_password) < 6 THEN
        RETURN 'Parolei jābūt vismaz 6 simbolus garai.';
    END IF;

    -- -------------------------------------
    -- E-pasta formāta pārbaude (regex)
    -- -------------------------------------
    IF p_email IS NULL 
       OR p_email !~* '^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$' THEN
        RETURN 'Nederīgs e-pasta formāts.';
    END IF;

    -- -------------------------------------
    -- Lietotāja ievietošana datubāzē
    -- Parole tiek saglabāta tikai kā hash
    -- -------------------------------------
    INSERT INTO users (username, password_hash, email)
    VALUES (
        trim(p_username),
        crypt(p_password, gen_salt('bf')),
        trim(p_email)
    );

    v_message := 'Lietotājs izveidots.';
    RETURN v_message;

EXCEPTION
    -- Ja tiek pārkāpts UNIQUE ierobežojums
    WHEN unique_violation THEN
        RETURN 'Lietotājvārds vai e-pasts jau eksistē';

    -- Citas neparedzētas kļūdas
    WHEN others THEN
        RETURN 'Neizdevās izveidot lietotāju';
END;
$$ LANGUAGE plpgsql;

-- =========================================================
-- FUNKCIJA: delete_user
-- Dzēš lietotāju pēc ID
-- =========================================================
CREATE OR REPLACE FUNCTION delete_user(p_user_id INT)
RETURNS VOID AS $$
BEGIN
    -- Dzēš lietotāju, sesijas dzēsīsies automātiski (ON DELETE CASCADE)
    DELETE FROM users WHERE id = p_user_id;
END;
$$ LANGUAGE plpgsql;

-- =========================================================
-- FUNKCIJA: update_user
-- Atjauno lietotāja vārdu un/vai e-pastu
-- =========================================================
CREATE OR REPLACE FUNCTION update_user(
    p_user_id INT,
    p_username TEXT,
    p_email TEXT
)
RETURNS VOID AS $$
BEGIN
    -- COALESCE + NULLIF ļauj neatjaunināt lauku,
    -- ja ievade ir tukša vai NULL
    UPDATE users
    SET username = COALESCE(NULLIF(trim(p_username), ''), username),
        email = COALESCE(NULLIF(trim(p_email), ''), email)
    WHERE id = p_user_id;
END;
$$ LANGUAGE plpgsql;

-- =========================================================
-- FUNKCIJA: check_user_credentials
-- Pārbauda lietotājvārdu un paroli
-- =========================================================
CREATE OR REPLACE FUNCTION check_user_credentials(
    p_username TEXT,
    p_password TEXT
)
RETURNS INT AS $$
DECLARE
    v_user_id INT;                          -- Atrastā lietotāja ID
BEGIN
    -- Meklē lietotāju, kura parole sakrīt ar hash
    SELECT id
    INTO v_user_id
    FROM users
    WHERE username = p_username
      AND password_hash = crypt(p_password, password_hash);

    -- Ja neatbilst, atgriezīs NULL
    RETURN v_user_id;
END;
$$ LANGUAGE plpgsql;

-- =========================================================
-- FUNKCIJA: login_user
-- Izveido jaunu sesiju un reģistrē pieslēgšanos
-- =========================================================
CREATE OR REPLACE FUNCTION login_user(p_user_id INT)
RETURNS TEXT AS $$
DECLARE
    v_token TEXT;                           -- Sesijas tokens
    v_expires TIMESTAMP;                    -- Sesijas derīguma termiņš
BEGIN
    IF p_user_id IS NULL THEN
        RETURN NULL;
    END IF;

    -- Ģenerē drošu nejaušu tokenu
    v_token := encode(gen_random_bytes(32), 'hex');

    -- Nosaka sesijas derīguma laiku (30 minūtes)
    v_expires := now() + interval '30 minutes';

    -- Saglabā sesiju
    INSERT INTO sessions (user_id, session_token, expires_at)
    VALUES (p_user_id, v_token, v_expires);

    -- Reģistrē login notikumu
    INSERT INTO login_logs (user_id, login_time)
    VALUES (p_user_id, now());

    RETURN v_token;
END;
$$ LANGUAGE plpgsql;

-- =========================================================
-- FUNKCIJA: logout_user
-- Izraksta lietotāju pēc sesijas tokena
-- =========================================================
CREATE OR REPLACE FUNCTION logout_user(p_session_token TEXT)
RETURNS VOID AS $$
DECLARE
    v_user_id INT;
BEGIN
    -- Nosaka lietotāju pēc tokena
    SELECT user_id
    INTO v_user_id
    FROM sessions
    WHERE session_token = p_session_token;

    -- Dzēš sesiju
    DELETE FROM sessions WHERE session_token = p_session_token;

    -- Atjaunina pēdējo login_log ierakstu
    UPDATE login_logs
    SET logout_time = now()
    WHERE id = (
        SELECT id
        FROM login_logs
        WHERE user_id = v_user_id AND logout_time IS NULL
        ORDER BY login_time DESC
        LIMIT 1
    );
END;
$$ LANGUAGE plpgsql;

-- =========================================================
-- FUNKCIJA: is_logged_in
-- Pārbauda, vai sesija ir aktīva, un pagarina to
-- =========================================================
CREATE OR REPLACE FUNCTION is_logged_in(p_session_token TEXT)
RETURNS BOOLEAN AS $$
DECLARE
    v_expires TIMESTAMP;
BEGIN
    -- Nolasa sesijas derīguma termiņu
    SELECT expires_at
    INTO v_expires
    FROM sessions
    WHERE session_token = p_session_token;

    -- Ja sesija neeksistē
    IF v_expires IS NULL THEN
        RETURN FALSE;
    END IF;

    -- Ja sesijas laiks ir beidzies
    IF v_expires < now() THEN
        DELETE FROM sessions WHERE session_token = p_session_token;
        RETURN FALSE;
    END IF;

    -- Ja sesija derīga, pagarina to vēl par 30 minūtēm
    UPDATE sessions
    SET expires_at = now() + interval '30 minutes'
    WHERE session_token = p_session_token;

    RETURN TRUE;
END;
$$ LANGUAGE plpgsql;