#ifndef DIRECTOR_WORKER_H
#define DIRECTOR_WORKER_H

#include "worker.h"

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

protected:
    void run() override;

private:
    void performTask();
    void startProductions(std::unordered_map<std::string, std::string> director);
    void startTransports(std::unordered_map<std::string, std::string>);
    void startSellings(std::unordered_map<std::string, std::string>);
    void paySalary();
    void calculateSatisfaction();

    static constexpr const char *QUERY_GET_DIRECTORS = R"(
        select d.may_produce, d.may_sell, d.may_start_transport, b.id branch_id, fu.id falukantUserId, d.id
        from falukant_data.director d
        join falukant_data.falukant_user fu
          on fu.id = d.employer_user_id
        join falukant_data."character" c
          on c.id  = d.director_character_id
        join falukant_data.branch b
          on b.region_id = c.region_id
             and b.falukant_user_id = fu.id
        where current_time between '08:00:00' and '17:00:00'
    )";

    static constexpr const char *QUERY_GET_BEST_PRODUCTION = R"(
        select fdu."id" falukant_user_id, fdu."money", fdu."certificate", ftp."id" product_id, ftp.label_tr,(select sum("quantity")
        from "falukant_data"."stock" fds
        where fds."branch_id" = fdb."id") stock_size, coalesce((select sum(coalesce(fdi."quantity", 0))
        from "falukant_data"."stock" fds
        join "falukant_data"."inventory" fdi
          on fdi."stock_id" = fds."id"
        where fds."branch_id" = fdb."id"), 0) used_in_stock,
        (ftp."sell_cost" * (fdtpw."worth_percent" + (fdk_character."knowledge" * 2 + fdk_director."knowledge") / 3) / 100 - 6 * ftp.category) / (300.0 * ftp. production_time) worth,
        fdb."id" branch_id,
        (select count("id") from "falukant_data"."production" where "branch_id" = fdb."id") running_productions,
        coalesce((select sum(coalesce(fdp.quantity, 0)) quantity from
        falukant_data.production fdp where fdp.branch_id = fdb.id), 0) running_productions
        from "falukant_data"."director" fdd
        join "falukant_data".character fdc
          on fdc.id = fdd.director_character_id
        join "falukant_data"."falukant_user" fdu
          on fdd."employer_user_id" = fdu."id"
        join "falukant_data"."character" user_character
          on user_character."user_id" = fdu."id"
        join "falukant_data"."branch" fdb
          on fdb."falukant_user_id" = fdu."id"
             and fdb."region_id" = fdc."region_id"
        join "falukant_data"."town_product_worth" fdtpw
          on fdtpw."region_id" = fdb."region_id"
        join "falukant_data"."knowledge" fdk_character
          on
        fdk_character."product_id" = fdtpw."product_id"
        and fdk_character."character_id" = user_character."id"
        and fdk_character."product_id" = fdtpw."product_id"
        join "falukant_data"."knowledge" fdk_director
          on
        fdk_director."product_id" = fdtpw."product_id"
        and fdk_director."character_id" = fdd."director_character_id"
        and fdk_director."product_id" = fdtpw."product_id"
        join "falukant_type"."product" ftp
          on
        ftp."id" = fdtpw."product_id"
        and ftp.category <= fdu.certificate
        where  fdd."id" = $1
        order by worth desc
        limit 1;
    )";

    static constexpr const char *QUERY_INSERT_PRODUCTION = R"(
        insert into "falukant_data"."production" ("branch_id", "product_id", "quantity")
        values ($1, $2, $3)
    )";

    static constexpr const char *QUERY_GET_INVENTORY = R"(
        select i.id, i.product_id, i.quantity, i.quality, p.sell_cost, fu.id user_id, b.region_id, b.id branch_id
        from falukant_data.inventory i
        join falukant_data.stock s
          on s.id = i.stock_id
        join falukant_data.branch b
          on b.id = s.branch_id
        join falukant_data.falukant_user fu
          on fu.id = b.falukant_user_id
        join falukant_data.director d
          on d.employer_user_id = fu.id
        join falukant_type.product p
          on p.id = i.product_id
        where d.id = $1
    )";

    static constexpr const char *QUERY_REMOVE_INVENTORY = R"(
        delete from falukant_data.inventory
        where id = $1
    )";

    static constexpr const char *QUERY_ADD_SELL_LOG = R"(
        INSERT INTO falukant_log.sell ("region_id", "product_id", "quantity", "seller_id")
        values ($1, $2, $3, $4)
        ON CONFLICT ("region_id", "product_id", "seller_id")
        DO UPDATE
        SET "quantity" = falukant_log.sell."quantity" + EXCLUDED.quantity
    )";

    static constexpr const char *QUERY_GET_SALARY_TO_PAY = R"(
        select d.id, d.employer_user_id, d.income
        from falukant_data.director d
        where date(d.last_salary_payout) < date(now())
    )";

    static constexpr const char *QUERY_SET_SALARY_PAYED = R"(
        update falukant_data.director
        set last_salary_payout = NOW()
        where id = $1
    )";

    static constexpr const char *QUERY_UPDATE_SATISFACTION = R"(
        WITH new_sats AS (
          SELECT
            d.id,
            ROUND(
              d.income::numeric
              /
              (
                c.title_of_nobility
                * POWER(1.231, AVG(k.knowledge) / 1.5)
              )
              * 100
            ) AS new_satisfaction
          FROM falukant_data.director d
          JOIN falukant_data.knowledge k
            ON d.director_character_id = k.character_id
          JOIN falukant_data.character c
            ON c.id = d.director_character_id
          GROUP BY d.id, c.title_of_nobility, d.income
        )
        UPDATE falukant_data.director dir
        SET satisfaction = ns.new_satisfaction
        FROM new_sats ns
        WHERE dir.id = ns.id
          -- Nur updaten, wenn sich der Wert tatsächlich ändert:
          AND dir.satisfaction IS DISTINCT FROM ns.new_satisfaction
        RETURNING dir.employer_user_id;
    )";
};

#endif // DIRECTOR_WORKER_H
