// app_config.hpp
#pragma once

#include <limits.h>
#include <unistd.h>

#include <fstream>
#include <iostream>
#include <map>
#include <nlohmann/json.hpp>
#include <stdexcept>
#include <string>

#include "logger.hpp"

using json = nlohmann::json;
using ordered_json = nlohmann::ordered_json;

// ------------------- 摄像头结构体 -------------------
enum class StreamType
{
    MAIN,
    SUB
};

struct Camera
{
    std::string device;
    std::string name;
    int width, height, fps;
    int bitrate;
    bool enabled;
    StreamType stream_type;  // 新增字段
};

// ------------------- MQTT Topic -------------------
struct VehicleMQTTTopics
{
    std::string heartbeat_up;
    std::string video_down;
    std::string record_query;
    std::string record_play;

    void fill_with_veh_id(const std::string& vehId)
    {
        heartbeat_up = "/kun/vehicle/video/status/" + vehId;
        video_down = "/kun/vehicle/video/request/" + vehId;
        record_query = "/kun/vehicle/video/record/query/" + vehId;
        record_play = "/kun/vehicle/video/record/play/" + vehId;
    }
};

// ------------------- MQTT 配置 -------------------
struct MQTTConfig
{
    std::string vehicle_id;
    std::string server_ip;
    int server_port;
    bool need_username_pwd;
    std::string client_id;
    std::string username;
    std::string password;
    int keep_alive;

    int qos = 1;                // 默认 QoS 级别
    bool clean_session = true;  // 默认 clean session

    VehicleMQTTTopics topics;
};

// ------------------- 总配置 -------------------
struct AppConfig
{
    std::vector<Camera> cameras;
    MQTTConfig mqtt;

    static AppConfig load_from_file(const std::string& filepath)
    {
        AppConfig cfg;

        std::ifstream ifs(filepath);
        if (!ifs.is_open())
        {
            LOG_ERROR("[Config] Failed to open config file: " + filepath);
            throw std::runtime_error("Failed to open config file: " + filepath);
        }

        json j;
        ifs >> j;

        // 读取摄像头
        if (j.contains("cameras"))
        {
            for (auto& c : j["cameras"])
            {
                Camera cam;
                cam.device = c.value("device", "");
                cam.name = c.value("name", "");
                cam.width = c.value("width", 1280);
                cam.height = c.value("height", 720);
                cam.fps = c.value("fps", 30);
                cam.bitrate = c.value("bitrate", 2000000);
                cam.enabled = c.value("enabled", false);
                cfg.cameras.push_back(cam);
                LOG_INFO("[Config] Loaded camera: " + cam.name + " (" + cam.device +
                         "), enabled=" + std::to_string(cam.enabled) + ", bitrate=" + std::to_string(cam.bitrate));
            }
        }

        // 读取 MQTT
        if (!j.contains("mqtt_server"))
        {
            LOG_ERROR("[Config] Missing 'mqtt_server' section");
            throw std::runtime_error("Config file missing 'mqtt_server'");
        }

        auto& m = j["mqtt_server"];
        cfg.mqtt.vehicle_id = std::to_string(m.value("veh_id", 0));
        cfg.mqtt.server_ip = m.value("address", "");
        cfg.mqtt.server_port = m.value("port", 1883);
        cfg.mqtt.need_username_pwd = m.value("need_username_pwd", true);
        cfg.mqtt.client_id = m.value("client_id", "");
        cfg.mqtt.username = m.value("username", "");
        cfg.mqtt.password = m.value("password", "");
        cfg.mqtt.keep_alive = m.value("mqtt_heart_threshold", 2000);
        cfg.mqtt.topics.fill_with_veh_id(cfg.mqtt.vehicle_id);

        LOG_INFO("[Config] Loaded MQTT server: " + cfg.mqtt.server_ip + ":" + std::to_string(cfg.mqtt.server_port));
        LOG_INFO("[Config] MQTT client ID: " + cfg.mqtt.client_id);
        LOG_INFO("[Config] MQTT Credentials - username: " + cfg.mqtt.username + ", password: " + cfg.mqtt.password);
        LOG_INFO("[Config] MQTT Topics: " + cfg.mqtt.topics.heartbeat_up + ", " + cfg.mqtt.topics.video_down);
        LOG_INFO("[Config] MQTT keepAlive: " + std::to_string(cfg.mqtt.keep_alive));

        return cfg;
    }
};

// ------------------- 辅助函数 -------------------
inline std::string get_executable_dir()
{
    char result[PATH_MAX] = {0};
    ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
    if (count == -1)
    {
        LOG_ERROR("[Config] Failed to read /proc/self/exe");
        throw std::runtime_error("Failed to read /proc/self/exe");
    }

    std::string full_path(result, count);
    auto pos = full_path.find_last_of('/');
    if (pos == std::string::npos)
    {
        LOG_ERROR("[Config] Failed to find executable directory");
        throw std::runtime_error("Failed to find executable directory");
    }

    return full_path.substr(0, pos);
}

inline std::string get_executable_dir_file_path(const std::string& filename)
{
    std::string dir = get_executable_dir();
    if (dir.back() != '/') dir += '/';
    return dir + filename;
}

// 全局配置变量
extern AppConfig g_app_config;
