#ifndef USERCHARACTERWORKER_H
#define USERCHARACTERWORKER_H

#include "worker.h"
#include <random>

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

protected:
    void run() override;

private:
    struct Character {
        int id;
        int age;
        int health;
    };

    void processCharacterEvents();
    void updateCharacterHealth(Character& character);
    void updateCharactersMood();
    int calculateHealthChange(int age);
    void handleCharacterDeath(int characterId);
    void recalculateKnowledge();
    void processPregnancies();
    void handleCredits();
    void setHeir(int characterId);
    int getFalukantUserId(int characterId);
    int getHeirFromChildren(int deceasedCharacterId);
    int getRandomHeir(int deceasedCharacterId);
    void setNewCharacter(int falukantUserId, int heirCharacterId);
    void setNewMoney(int falukantUserId, double newAmount);
    double getHouseValue(int falukantUserId);
    double getSettlementValue(int falukantUserId);
    double getInventoryValue(int falukantUserId);
    double getCreditDebt(int falukantUserId);
    double getCurrentMoney(int falukantUserId);
    double calculateNewMoney(int falukantUserId, bool hasHeir);
    int    getChildCount(int deceasedUserId);

    std::random_device rd;
    std::mt19937 gen;
    std::uniform_real_distribution<> dist;
    bool didRunToday { false };

    static constexpr const char *QUERY_GET_USERS_TO_UPDATE = R"(
        SELECT "id", CURRENT_DATE - birthdate::date AS age, "health"
        FROM "falukant_data"."character"
        WHERE "user_id" IS NOT NULL;
    )";

    static constexpr const char *QUERY_UPDATE_CHARACTERS_HEALTH = R"(
        UPDATE "falukant_data"."character"
        SET health = $1
        WHERE id = $2
    )";

    static constexpr const char *QUERY_UPDATE_GET_ITEMS_TO_UPDATE = R"(
        SELECT id, product_id, producer_id, quantity
        FROM falukant_log.production p
        WHERE p.production_timestamp::date < current_date
    )";

    static constexpr const char *QUERY_UPDATE_GET_CHARACTER_IDS = R"(
        select fu.id user_id, c.id character_id, c2.id director_id
        from falukant_data.falukant_user fu
        join falukant_data."character" c
          on c.user_id = fu.id
        left join falukant_data.director d
          on d.employer_user_id = fu.id
        left join falukant_data."character" c2
          on c2.id = d.director_character_id
        where fu.id = $1
    )";

    static constexpr const char *QUERY_UPDATE_KNOWLEDGE = R"(
        update falukant_data.knowledge
        set knowledge = least(knowledge + $3, 100)
        where character_id = $1
        and product_id = $2
    )";

    static constexpr const char *QUERY_DELETE_LOG_ENTRY = R"(
        delete from falukant_log.production
        where id = $1
    )";

    static constexpr char const* QUERY_GET_PREGNANCY_CANDIDATES  = R"(
        SELECT
          r.character1_id AS father_cid,
          r.character2_id AS mother_cid,
          c1.title_of_nobility,
          c1.last_name,
          c1.region_id,
          fu1.id AS father_uid,
          fu2.id AS mother_uid,
          -- Durchschnittsalter in Tagen
          ((NOW()::date - c1.birthdate::date)
           + (NOW()::date - c2.birthdate::date)) / 2 AS avg_age_days,
          -- Angepasste Schwangerschaftswahrscheinlichkeit in Prozent
          100.0 /
            (1
             + EXP(
                 0.0647 * (
                   ((NOW()::date - c1.birthdate::date)
                    + (NOW()::date - c2.birthdate::date)) / 2
                 )
                 - 0.0591
               )
            ) AS prob_pct
        FROM falukant_data.relationship r
        JOIN falukant_type.relationship r2
          ON r2.id = r.relationship_type_id
          AND r2.tr = 'married'
        JOIN falukant_data."character" c1
          ON c1.id = r.character1_id
        JOIN falukant_data."character" c2
          ON c2.id = r.character2_id
        LEFT JOIN falukant_data.falukant_user fu1
          ON fu1.id = c1.user_id
        LEFT JOIN falukant_data.falukant_user fu2
          ON fu2.id = c2.user_id
        WHERE random()*100 < (
          100.0 /
            (1
             + EXP(
                 0.11166347 * (
                   ((NOW()::date - c1.birthdate::date)
                    + (NOW()::date - c2.birthdate::date)) / 2
                 )
                 - 2.638267
               )
            )
        ) / 2;  -- Geburtenrate halbiert
    )";

    static constexpr char const* QUERY_INSERT_CHILD = R"(
        INSERT INTO falukant_data."character" (
          user_id,
          region_id,
          first_name,
          last_name,
          birthdate,
          gender,
          title_of_nobility,
          mood_id,
          created_at,
          updated_at
        ) VALUES (
          NULL,
          $1::int,   -- region_id
          /* zufälliger Vorname passend zum Gender */
          (
            SELECT id
            FROM falukant_predefine.firstname
            WHERE gender = $2
            ORDER BY RANDOM()
            LIMIT 1
          ),
          $3::int,   -- last_name (Eltern-Nachname)
          NOW(),
          $2::varchar, -- gender
          $4::int,   -- title_of_nobility
          /* zufällige Stimmung */
          (
            SELECT id
            FROM falukant_type.mood
            ORDER BY RANDOM()
            LIMIT 1
          ),
          NOW(),
          NOW()
        )
        RETURNING id AS child_cid
    )";

    static constexpr char const* QUERY_INSERT_CHILD_RELATION     = R"(
        -- QUERY_INSERT_CHILD_RELATION
        INSERT INTO falukant_data.child_relation (
          father_character_id,
          mother_character_id,
          child_character_id,
          name_set,
          created_at,
          updated_at
        )
        VALUES (
          $1::int,    -- father_cid
          $2::int,    -- mother_cid
          $3::int,    -- child_cid
          false,
          NOW(), NOW()
        )
        RETURNING
          father_character_id,
          -- Vater-User
          (SELECT user_id FROM falukant_data."character" WHERE id = father_character_id) AS father_user_id,
          mother_character_id,
          -- Mutter-User
          (SELECT user_id FROM falukant_data."character" WHERE id = mother_character_id) AS mother_user_id,
          child_character_id,
          -- Kind-User
          (SELECT user_id FROM falukant_data."character" WHERE id = child_character_id)   AS child_user_id;
    )";

    static constexpr char const* QUERY_AUTOBATISM = R"(
        update falukant_data.child_relation
        set name_set = true
        where id in (
            select cr.id
            from falukant_data.child_relation cr
            join falukant_data."character" c
              on c.id = cr.child_character_id
            where cr.name_set = false
                  and c.birthdate < current_date - interval '5 days'
        )
    )";

    static constexpr char const* QUERY_UPDATE_MOOD = R"(
        UPDATE falukant_data."character" AS c
        SET mood_id = falukant_data.get_random_mood_id()
        WHERE c.health > 0;
    )";

    static constexpr char const* QUERY_GET_OPEN_CREDITS = R"(
        select c.id credit_id, c.amount, c.remaining_amount, c.interest_rate, fu.id user_id, fu."money", c2.id character_id, dp.created_at debitor_prism_start,
            dp.created_at::date < current_date prism_started_previously
        from falukant_data.credit c
        join falukant_data.falukant_user fu
          on fu.id = c.id
        join falukant_data."character" c2
          on c2.user_id = c.falukant_user_id
        left join falukant_data.debtors_prism dp
          on dp.character_id = c2.id
        where c.remaining_amount > 0
        and c.updated_at::date < current_date
    )";

    static constexpr char const* QUERY_UPDATE_CREDIT = R"(
        update falukant_data.credit c
        set remaining_amount = $1
        where falukant_user_id = $2
    )";

    static constexpr char const* QUERY_CLEANUP_CREDITS = R"(
        delete from falukant_data.credit
        where remaining_amount >= 0.01
    )";

    static constexpr char const* QUERY_ADD_CHARACTER_TO_DEBTORS_PRISM = R"(
        insert into falukant_data.debtors_prism (character_id) values ($1)
    )";

    static constexpr const char* QUERY_GET_HEIR = R"(
        SELECT child_character_id
          FROM falukant_data.child_relation
         WHERE father_character_id = $1
            OR mother_character_id = $1
      ORDER BY (is_heir IS TRUE) DESC,
               updated_at         DESC
         LIMIT 1
    )";

    static constexpr const char* QUERY_RANDOM_HEIR = R"(
    WITH chosen AS (
        SELECT
          cr.id               AS relation_id,
          cr.child_character_id
        FROM
          falukant_data.child_relation AS cr
        JOIN
          falukant_data."character"   AS ch
          ON ch.id = cr.child_character_id
        WHERE
          (cr.father_character_id = $1 OR cr.mother_character_id = $1)
          -- gleicher Wohnort wie der Verstorbene
          AND ch.region_id = (
              SELECT region_id
                FROM falukant_data."character"
               WHERE id = $1
          )
          -- nicht älter als 10 Tage
          AND ch.birthdate >= NOW() - INTERVAL '10 days'
          -- Titel "noncivil"
          AND ch.title_of_nobility = (
              SELECT id
                FROM falukant_type.title
               WHERE label_tr = 'noncivil'
          )
        ORDER BY RANDOM()
        LIMIT 1
    )
    UPDATE
      falukant_data.child_relation AS cr2
    SET
      is_heir    = true,
      updated_at = NOW()
    FROM
      chosen
    WHERE
      cr2.id = chosen.relation_id
    RETURNING
      chosen.child_character_id
    )";

    static constexpr const char* QUERY_SET_CHARACTER_USER = R"(
        UPDATE falukant_data."character"
           SET user_id = $1,
               updated_at = NOW()
         WHERE id = $2
    )";

    static constexpr const char* QUERY_UPDATE_USER_MONEY = R"(
        UPDATE falukant_data.falukant_user
           SET money = $1,
               updated_at = NOW()
         WHERE user_id = $2
    )";

    static constexpr const char* QUERY_GET_FALUKANT_USER_ID = R"(
        SELECT user_id
          FROM falukant_data."character"
         WHERE id = $1
         LIMIT 1
    )";

// Sub‐Queries
    static constexpr const char* QUERY_GET_CURRENT_MONEY = R"(
        SELECT COALESCE(money,0) AS sum
          FROM falukant_data.falukant_user
         WHERE user_id = $1
    )";

    static constexpr const char* QUERY_HOUSE_VALUE = R"(
        SELECT COALESCE(SUM(h.cost),0) AS sum
          FROM falukant_data.user_house AS uh
          JOIN falukant_type.house    AS h  ON uh.house_type_id = h.id
         WHERE uh.user_id = $1
    )";

    static constexpr const char* QUERY_SETTLEMENT_VALUE = R"(
        SELECT COALESCE(SUM(b.base_cost),0) AS sum
          FROM falukant_data.branch       AS br
          JOIN falukant_type.branch       AS b  ON br.branch_type_id = b.id
         WHERE br.falukant_user_id = $1
    )";

    static constexpr const char* QUERY_INVENTORY_VALUE = R"(
        SELECT COALESCE(SUM(i.quantity * p.sell_cost),0) AS sum
          FROM falukant_data.inventory    AS i
          JOIN falukant_type.product      AS p  ON i.product_id = p.id
          JOIN falukant_data.branch       AS br ON i.stock_id   = br.id
         WHERE br.falukant_user_id = $1
    )";

    static constexpr const char* QUERY_CREDIT_DEBT = R"(
        SELECT COALESCE(SUM(remaining_amount),0) AS sum
          FROM falukant_data.credit
         WHERE falukant_user_id = $1
    )";

    static constexpr const char* QUERY_COUNT_CHILDREN = R"(
        SELECT COUNT(*) AS cnt
          FROM falukant_data.child_relation
         WHERE father_character_id = $1
            OR mother_character_id = $1
    )";

    // Queries zum Löschen von Character-Verknüpfungen beim Tod
    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"(
        DELETE FROM falukant_data.relationship
        WHERE character1_id = $1
           OR character2_id = $1;
    )";

    static constexpr const char *QUERY_DELETE_CHILD_RELATION = R"(
        DELETE FROM falukant_data.child_relation
        WHERE child_character_id = $1
           OR father_character_id = $1
           OR mother_character_id = $1;
    )";

    static constexpr const char *QUERY_DELETE_KNOWLEDGE = R"(
        DELETE FROM falukant_data.knowledge
        WHERE character_id = $1;
    )";

    static constexpr const char *QUERY_DELETE_DEBTORS_PRISM = R"(
        DELETE FROM falukant_data.debtors_prism
        WHERE character_id = $1;
    )";

    static constexpr const char *QUERY_DELETE_POLITICAL_OFFICE = R"(
        DELETE FROM falukant_data.political_office
        WHERE character_id = $1;
    )";

    static constexpr const char *QUERY_DELETE_ELECTION_CANDIDATE = R"(
        DELETE FROM falukant_data.election_candidate
        WHERE character_id = $1;
    )";

};

#endif // USERCHARACTERWORKER_H
