#pragma once

#include "worker.h"
#include <random>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <string>
#include <thread>
#include <atomic>

class CharacterCreationWorker : public Worker {
public:
    CharacterCreationWorker(ConnectionPool &pool, MessageBroker &broker);
    ~CharacterCreationWorker() override;

protected:
    void run() override;

private:
    std::mt19937 gen;
    std::uniform_int_distribution<int> dist;
    std::unordered_map<std::string, std::unordered_set<int>> first_name_cache;
    std::unordered_set<int> last_name_cache;
    std::atomic<bool> deathCheckRunning{true};
    std::thread deathThread;

    bool isTodayCharacterCreated();
    void createCharactersForToday();
    void createCharactersForRegion(int region_id);
    void createCharacter(int region_id, const std::string &gender, int title_of_nobility);
    std::vector<int> getTownRegionIds();
    void loadNames();
    int getRandomFromSet(const std::unordered_set<int> &name_set);
    void monitorCharacterDeaths();
    void handleCharacterDeath(int characterId);
    void notifyUser(int userId, const std::string &eventType);
    void markCharacterAsDeceased(int characterId);
    bool calculateDeathProbability(int age);

    static constexpr const char *QUERY_IS_PREVIOUS_DAY_CHARACTER_CREATED = R"(
        SELECT created_at
        FROM falukant_data."character"
        WHERE user_id IS NULL
        AND created_at::date = CURRENT_DATE
        ORDER BY created_at DESC
        LIMIT 1;
    )";

    static constexpr const char *QUERY_GET_TOWN_REGION_IDS = R"(
        SELECT fdr.id
        FROM falukant_data.region fdr
        JOIN falukant_type.region ftr ON fdr.region_type_id = ftr.id
        WHERE ftr.label_tr = 'city';
    )";

    static constexpr const char *QUERY_LOAD_FIRST_NAMES = R"(
        SELECT id, gender
        FROM falukant_predefine.firstname;
    )";

    static constexpr const char *QUERY_LOAD_LAST_NAMES = R"(
        SELECT id
        FROM falukant_predefine.lastname;
    )";

    static constexpr const char *QUERY_INSERT_CHARACTER = R"(
        INSERT INTO falukant_data."character"(
            user_id, region_id, first_name, last_name,
            birthdate, gender, created_at, updated_at, title_of_nobility
        )
        VALUES (NULL, $1, $2, $3, NOW(), $4, NOW(), NOW(), $5);
    )";

    static constexpr const char *QUERY_GET_ELIGIBLE_NPC_FOR_DEATH = R"(
        WITH aged AS (
          SELECT
            c.id,
            (current_date - c.birthdate::date) AS age,
            c.user_id
          FROM
            falukant_data."character" c
          WHERE
            c.user_id IS NULL
            AND (current_date - c.birthdate::date) > 60
        ),
        always_sel AS (
          -- Immer mitnehmen: alle über 85 Tage
          SELECT *
          FROM aged
          WHERE age > 85
        ),
        random_sel AS (
          -- Zufallsstichprobe: alle zwischen 61 und 85 Tagen, hier beispielhaft auf 10 limitiert
          SELECT *
          FROM aged
          WHERE age <= 85
          ORDER BY random()
          LIMIT 10  -- <-- hier die gewünschte Anzahl anpassen
        )
        -- Zusammenführen der beiden Mengen
        SELECT *
        FROM always_sel
        UNION ALL
        SELECT *
        FROM random_sel;
    )";

    static constexpr const char *QUERY_DELETE_DIRECTOR = R"(
        DELETE FROM falukant_data.director
        WHERE director_character_id = $1
        RETURNING employer_user_id;
    )";

    static constexpr const char *QUERY_DELETE_RELATIONSHIP = R"(
        WITH deleted AS (
          DELETE FROM falukant_data.relationship
          WHERE character1_id = $1
             OR character2_id = $1
          RETURNING
            CASE
              WHEN character1_id = $1 THEN character2_id
              ELSE character1_id
            END AS related_character_id,
            relationship_type_id
        )
        SELECT
          c.user_id AS related_user_id
        FROM deleted d
        JOIN falukant_data."character" c
          ON c.id = d.related_character_id;
    )";

    static constexpr const char *QUERY_DELETE_CHILD_RELATION = R"(
        WITH deleted AS (
          DELETE FROM falukant_data.child_relation
          WHERE child_character_id = $1
          RETURNING
            father_character_id,
            mother_character_id
        )
        SELECT
          cf.user_id AS father_user_id,
          cm.user_id AS mother_user_id
        FROM deleted d
        JOIN falukant_data."character" cf
          ON cf.id = d.father_character_id
        JOIN falukant_data."character" cm
          ON cm.id = d.mother_character_id;
    )";

    static constexpr const char *QUERY_INSERT_NOTIFICATION = R"(
        INSERT INTO falukant_log.notification (user_id, tr, shown, created_at, updated_at)
        VALUES ($1, 'director_death', false, NOW(), NOW());
    )";


    static constexpr const char *QUERY_MARK_CHARACTER_DECEASED = R"(
        DELETE FROM falukant_data."character"
        WHERE id = $1;
    )";
};
