#pragma once

#include "worker.h"
#include <vector>
#include <string>

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

protected:
    void run() override;

private:
    void processProductions();
    std::vector<std::unordered_map<std::string, std::string>> getFinishedProductions(Database &db);
    bool addToInventory(Database &db, int branchId, int productId, int quantity, int quality, int userId);
    bool storeInStock(Database &db, int stockId, int productId, int quantity, int quality);
    void deleteProduction(Database &db, const std::string &productionId);
    void sendProductionReadyEvent(int userId, int productId, int quantity, int quality, int branchId);
    void addProductionToLog(int regionId, int userId, int productId, int quantity);

    static constexpr const char *QUERY_GET_FINISHED_PRODUCTIONS = R"(
        SELECT DISTINCT
            p.id AS production_id,
            p.branch_id,
            p.product_id,
            p.quantity,
            p.start_timestamp,
            pr.production_time,
            k.character_id,
            case when k2.id is not null then (k.knowledge * 2 + k2.knowledge) / 3 else k.knowledge end AS quality,
            br.region_id,
            br.falukant_user_id user_id
        FROM falukant_data.production p
        JOIN falukant_type.product pr ON p.product_id = pr.id
        JOIN falukant_data.branch br ON p.branch_id = br.id
        JOIN falukant_data.character c ON c.user_id = br.falukant_user_id
        JOIN falukant_data.knowledge k ON p.product_id = k.product_id AND k.character_id = c.id
        JOIN falukant_data.stock s ON s.branch_id = br.id
        LEFT JOIN falukant_data.director d on d.employer_user_id = c.user_id
        LEFT JOIN falukant_data.knowledge k2 on k2.character_id = d.director_character_id and k2.product_id = p.product_id
        WHERE p.start_timestamp + interval '1 minute' * pr.production_time <= NOW()
        ORDER BY p.start_timestamp;
    )";

    static constexpr const char *QUERY_GET_AVAILABLE_STOCKS = R"(
        SELECT stock.id, stock.quantity AS total_capacity, (
            SELECT COALESCE(SUM(inventory.quantity), 0)
            FROM falukant_data.inventory
            WHERE inventory.stock_id = stock.id
        ) AS filled, stock.branch_id
        FROM falukant_data.stock stock 
        JOIN falukant_data.branch branch
        ON stock.branch_id = branch.id 
        WHERE branch.id = $1
        ORDER BY total_capacity DESC;
    )";

    static constexpr const char *QUERY_DELETE_PRODUCTION = R"(
        DELETE FROM falukant_data.production WHERE id = $1;
    )";

    static constexpr const char *QUERY_INSERT_INVENTORY = R"(
        INSERT INTO falukant_data.inventory (stock_id, product_id, quantity, quality, produced_at)
        VALUES ($1, $2, $3, $4, NOW());
    )";

    static constexpr const char *QUERY_INSERT_UPDATE_PRODUCTION_LOG = R"(
        INSERT INTO falukant_log.production (
            region_id,
            product_id,
            quantity,
            producer_id,
            production_date
        )
        VALUES ($1, $2, $3, $4, CURRENT_DATE)
        ON CONFLICT (producer_id, product_id, region_id, production_date)
        DO UPDATE
        SET quantity = falukant_log.production.quantity + EXCLUDED.quantity;
    )";

    static constexpr const char *QUERY_ADD_OVERPRODUCTION_NOTIFICATION = R"(
        INSERT INTO falukant_log.notification
        (user_id, tr, shown, created_at, updated_at)
        VALUES($1, $2, false, now(), now());
    )";
};
