#include "stockagemanager.h"
#include "connection_guard.h"
#include <iostream>
#include <random>
#include <chrono>
#include <thread>

StockageManager::StockageManager(ConnectionPool &pool, MessageBroker &broker)
    : Worker(pool, broker, "StockageManager") {}

StockageManager::~StockageManager() {
    addStocksRunning = false;
    if (addStocksThread.joinable()) addStocksThread.join();
}

void StockageManager::run() {
    addStocksThread = std::thread([this]() { addLocalStocks(); });
    while (runningWorker) {
        setCurrentStep("Main loop: Running...");
        std::this_thread::sleep_for(std::chrono::seconds(1));
        signalActivity();
    }
}

void StockageManager::addLocalStocks() {
    auto lastExecutionTime = std::chrono::steady_clock::now();
    std::uniform_real_distribution<> dist(0.0, 1.0);
    while (addStocksRunning) {
        signalActivity();
        auto now = std::chrono::steady_clock::now();
        auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(now - lastExecutionTime).count();
        if (elapsed >= 60) {
            try {
                setCurrentStep("Add Local Stocks: Fetch Town IDs");
                auto townIds = getTownIds();
                for (const auto &townId : townIds) {
                    std::mt19937 gen(std::random_device{}());
                    double chance = round(dist(gen) * 2160);
                    if (chance <= 1) {
                        addStockForTown(townId);
                    }
                }
            } catch (const std::exception &e) {
                std::cerr << "[StockageManager] Fehler in addLocalStocks: " << e.what() << std::endl;
            }
            lastExecutionTime = now;
        }
        cleanupBuyableSotck();
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}


std::vector<int> StockageManager::getTownIds() {
    try {
        ConnectionGuard connGuard(pool);
        auto &db = connGuard.get();
        db.prepare("get_towns", QUERY_GET_TOWNS);
        const auto towns = db.execute("get_towns");
        std::vector<int> townIds;
        for (const auto &town: towns) {
            auto id = town.at("id");
            townIds.push_back(std::stoi(id));
        }
        return townIds;
    } catch (const std::exception &e) {
        std::cerr << "[ProduceWorker] Fehler beim Abrufen abgeschlossener Produktionen: "
                  << e.what() << std::endl;
    }
    return {};
}

void StockageManager::addStockForTown(int townId) {
    try {
        ConnectionGuard connGuard(pool);
        auto &db = connGuard.get();
        db.prepare("add_stock", QUERY_INSERT_STOCK);
        db.execute("add_stock", {std::to_string(townId)});
        nlohmann::json message = {
            {"event", "stock_change"},
            {"branch", std::to_string(townId) }
        };
        sendMessageToRegionUsers(townId, message);
    } catch (const std::exception &e) {
        std::cerr << "[StockageManager] Fehler in addStockForTown: " << e.what() << std::endl;
    }
}

void StockageManager::cleanupBuyableSotck() {
    try {
        ConnectionGuard connGuard(pool);
        auto &db = connGuard.get();
        db.prepare("cleanup_stock", QUERY_CLEANUP_STOCK);
        db.execute("cleanup_stock", {});
    } catch (const std::exception &e) {
        std::cerr << "[StockageManager] Fehler bei stock cleanup: " << e.what() << std::endl;
    }
}
