#include <iostream>
#include <string>
#include <cstdlib>
#include <chrono>
#include <thread>
#include <boost/filesystem.hpp>

#include "json/json.h"
#include "defines.hpp"

const char* DEFAULT_WATCH_DOG_CONFIG_PATH = ETC_PATH"WatchDog/watch_dog.json";

// 递归计算目录大小
std::uintmax_t calculateDirectorySize(const boost::filesystem::path& path) {
    if (!boost::filesystem::exists(path)) {
        LOG(ERROR) << path << "not exist!!!!!";
        return 0;
    }
    std::uintmax_t size = 0;
    for (const auto& entry : boost::filesystem::recursive_directory_iterator(path)) {
        if (boost::filesystem::is_regular_file(entry)) {
            size += boost::filesystem::file_size(entry);
        }
    }
    return size;
}

// 删除最后修改时间最早的文件
void deleteOldestFile(const boost::filesystem::path& directoryPath) {
    boost::filesystem::path oldestFilePath;
    std::time_t oldestTime = std::numeric_limits<std::time_t>::max();

    for (const auto& entry : boost::filesystem::directory_iterator(directoryPath)) {
        if (boost::filesystem::is_regular_file(entry)) {
            const std::time_t lastModifiedTime = boost::filesystem::last_write_time(entry);
            if (lastModifiedTime < oldestTime) {
                oldestTime = lastModifiedTime;
                oldestFilePath = entry.path();
            }
        }
    }

    if (!oldestFilePath.empty()) {
        try {
            boost::filesystem::remove(oldestFilePath);
            LOG(INFO) << "Deleted file: " << oldestFilePath << std::endl;
        } catch (const std::exception& e) {
            LOG(ERROR) << "Failed to delete file: " << oldestFilePath << ", Error: " << e.what() << std::endl;
        }
    } else {
        LOG(WARNING) << "No files found in the directory." << oldestFilePath << std::endl;
    }
}

int main(int argc, char** argv) {
    std::string config_path;
    if (argc > 1) {
        config_path = argv[1];
    }
    else {
        config_path = DEFAULT_WATCH_DOG_CONFIG_PATH;
    }

    ZX::InitGlog("WatchDog", ETC_PATH"WatchDog/WatchDogLog/");
    LOG(INFO) << "load etc file from: " << DEFAULT_WATCH_DOG_CONFIG_PATH;
    Json::Value config_json;
    if (false == ReadJsonFile(config_path, config_json) || !config_json.isMember("process") || !config_json["process"].isArray()) {
        auto time = std::chrono::steady_clock::now();
        std::chrono::duration<double> diff = std::chrono::steady_clock::now() - time;
        while (diff.count() < 10) {
            LOG(ERROR) << "watch Program is empty!!! after " << 10  - diff.count() << "s, system will restart." << std::endl;
            std::this_thread::sleep_for(std::chrono::seconds(1));
            diff = std::chrono::steady_clock::now() - time;
        }
        system("systemctl reboot");
        exit(-1);
    }

    std::vector<std::string> programs;
    for (int i = 0; i < config_json["process"].size(); i++) {
        programs.push_back(config_json["process"][i]["program"].asString());
    }

    std::vector<std::string> logpaths;
    std::vector<std::uintmax_t> maxsizes;
    for (int i = 0; i < config_json["logpaths"].size(); i++) {
        logpaths.push_back(config_json["logpaths"][i]["path"].asString());
        maxsizes.push_back(config_json["logpaths"][i]["size"].asInt64());
    }
    
    int timeout_seconds = 10; // 超时时间（秒）

    while (true) {
        // 检查程序是否存活
        for (int i = 0; i < programs.size(); i++) {
            std::string cmd = "ps aux | grep '" + programs[i] + "' | grep -v grep";
            if (system(cmd.c_str()) != 0) {
                // 程序已死亡，重启
                LOG(WARNING) << "Program " << programs[i] << " has died, restarting..." << std::endl;
                std::stringstream pro(programs[i]);
                std::string name;
                pro >> name;
                system(("pkill -f " + name).c_str());
                std::this_thread::sleep_for(std::chrono::seconds(1));
                system(("./" + programs[i] + " &").c_str());
            }
        }

        // 清理目录下文件
        // 计算目录大小
        for (int i = 0; i < logpaths.size(); i++) {
            std::uintmax_t size = calculateDirectorySize(logpaths.at(i)) / (1024 * 1024);
            LOG(INFO) << logpaths[i] << " size: " << size << "MB" << " max size:" << maxsizes[i] << "MB";
            while (size > maxsizes[i]) {
                deleteOldestFile(logpaths[i]);
                size = calculateDirectorySize(logpaths[i]) / (1024 * 1024);
            }
        }

        // 等待一段时间后再次检测
        std::this_thread::sleep_for(std::chrono::seconds(timeout_seconds));
    }

    return 0;
}
