#include "record_manager.hpp"

#include <algorithm>
#include <ctime>
#include <fstream>
#include <iostream>

#include "logger.hpp"

std::shared_ptr<RecordManager> g_record_manager = nullptr;

namespace fs = std::filesystem;

//
// 构造函数：自动加载 SRS 配置
//
RecordManager::RecordManager(const std::string& srs_record_cfg_path) : srs_record_cfg_path_(srs_record_cfg_path)
{
    LOG_INFO("[RecordManager] Loading SRS config: " + srs_record_cfg_path_);

    bool ok = loadSrsConfig();
    if (!ok)
    {
        LOG_ERROR("[RecordManager] Failed to load SRS config.");
        return;
    }

    LOG_INFO("[RecordManager] SRS config loaded successfully.");
    LOG_INFO("record_dir = " + record_dir_);
    LOG_INFO("dvr_duration_sec = " + std::to_string(dvr_duration_sec_));
    LOG_INFO("http_port = " + std::to_string(http_port_));

    // 自动根据 dvr_duration 启动扫描线程
    startAutoScan(dvr_duration_sec_);
}

//
// 解析 SRS DVR 配置，提取 record_dir_ 与 dvr_duration_sec_
//
bool RecordManager::loadSrsConfig()
{
    std::ifstream ifs(srs_record_cfg_path_);
    if (!ifs.is_open())
    {
        LOG_ERROR("[RecordManager] Cannot open SRS config file: " + srs_record_cfg_path_);
        return false;
    }

    std::string line;
    std::string dvr_path;

    bool in_http_server = false;

    while (std::getline(ifs, line))
    {
        line.erase(0, line.find_first_not_of(" \t"));
        if (line.empty() || line[0] == '#') continue;

        // ---------- 进入 http_server 块 ----------
        if (line.find("http_server") != std::string::npos && line.find("{") != std::string::npos)
        {
            in_http_server = true;
            continue;
        }
        if (in_http_server && line == "}")
        {
            in_http_server = false;
            continue;
        }

        if (in_http_server)
        {
            if (line.rfind("listen", 0) == 0)
            {
                int port = 0;
                if (sscanf(line.c_str(), "listen %d;", &port) == 1)
                {
                    http_port_ = port;
                }
            }
        }

        // 解析 dvr_path
        if (line.find("dvr_path") != std::string::npos)
        {
            auto pos = line.find('/');
            auto semicolon = line.find(';');
            if (pos != std::string::npos && semicolon != std::string::npos)
                dvr_path = line.substr(pos, semicolon - pos);
        }

        // 解析 dvr_duration
        else if (line.find("dvr_duration") != std::string::npos)
        {
            int sec = 0;
            if (sscanf(line.c_str(), "dvr_duration %d", &sec) == 1) dvr_duration_sec_ = sec;
        }
    }

    if (dvr_path.empty())
    {
        LOG_ERROR("[RecordManager] dvr_path not found in config.");
        return false;
    }

    // /sata/record/[stream]/[2006]-[01]-[02]/...
    auto pos = dvr_path.find("[stream]");
    if (pos != std::string::npos)
        record_dir_ = dvr_path.substr(0, pos);
    else
    {
        LOG_ERROR("[RecordManager] Cannot extract record_dir from dvr_path: " + dvr_path);
        return false;
    }

    return true;
}

void RecordManager::startAutoScan(int interval_sec)
{
    scan_interval_sec_ = interval_sec;  // ← 保存扫描周期
    if (running_) return;

    running_ = true;

    scan_thread_ = std::thread(
        [this]()
        {
            LOG_INFO("[RecordManager] Auto-scan thread started, interval = " + std::to_string(scan_interval_sec_) +
                     " seconds.");

            while (running_)
            {
                auto t0 = std::chrono::steady_clock::now();

                this->scanAll();
                LOG_INFO("[RecordManager] scanAll() completed.");

                // 休眠剩余时间
                auto t1 = std::chrono::steady_clock::now();
                auto used_ms = std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0).count();
                int sleep_ms = scan_interval_sec_ * 1000 - used_ms;
                if (sleep_ms < 100) sleep_ms = 100;

                std::this_thread::sleep_for(std::chrono::milliseconds(sleep_ms));
            }

            LOG_INFO("[RecordManager] Auto-scan thread stopped.");
        });
}

void RecordManager::stopAutoScan()
{
    if (!running_) return;

    running_ = false;
    if (scan_thread_.joinable()) scan_thread_.join();

    LOG_INFO("[RecordManager] Auto-scan thread stopped.");
}

//
// 扫描所有文件
//
void RecordManager::scanAll()
{
    std::lock_guard<std::mutex> lock(index_mutex_);

    index_.clear();

    if (!fs::exists(record_dir_))
    {
        LOG_WARN("[RecordManager] record_dir not exist: " + record_dir_);
        return;
    }

    for (auto const& entry : fs::recursive_directory_iterator(record_dir_))
    {
        if (!entry.is_regular_file()) continue;

        auto p = entry.path();
        if (p.extension() != ".mp4") continue;

        auto info = parseFile(p);
        if (info.start_ms <= 0) continue;

        index_[info.stream].push_back(info);
    }

    for (auto& kv : index_)
    {
        sortStream(kv.first);
    }

    LOG_INFO("[RecordManager] scanAll completed. streams=" + std::to_string(index_.size()));
}

//
// 排序函数：按 start_ms 升序
//
void RecordManager::sortStream(const std::string& stream)
{
    auto& files = index_[stream];
    std::sort(files.begin(), files.end(),
              [](const RecordFileInfo& a, const RecordFileInfo& b) { return a.start_ms < b.start_ms; });
}

//
// 解析路径得到文件时间戳
//
RecordFileInfo RecordManager::parseFile(const fs::path& p)
{
    RecordFileInfo info;
    info.path = p.string();

    try
    {
        auto filename = p.filename().string();                              // 10-23-17.mp4
        auto date_dir = p.parent_path().parent_path().filename().string();  // yyyy-mm-dd
        auto stream_dir = p.parent_path().parent_path().parent_path().filename().string();

        info.stream = stream_dir;

        int y = 0, mon = 0, d = 0, h = 0, m = 0, s = 0;
        sscanf(date_dir.c_str(), "%d-%d-%d", &y, &mon, &d);
        sscanf(filename.c_str(), "%d-%d-%d", &h, &m, &s);

        std::tm tm{};
        tm.tm_year = y - 1900;
        tm.tm_mon = mon - 1;
        tm.tm_mday = d;
        tm.tm_hour = h;
        tm.tm_min = m;
        tm.tm_sec = s;

        int64_t start = std::mktime(&tm) * 1000LL;
        info.start_ms = start;

        // 读取 mp4 时长
        MP4FileHandle hFile = MP4Read(info.path.c_str());
        if (hFile != MP4_INVALID_FILE_HANDLE)
        {
            double durSec = MP4GetDuration(hFile) / (double)MP4GetTimeScale(hFile);
            MP4Close(hFile);
            info.end_ms = start + (int64_t)(durSec * 1000.0);
        }
        else
        {
            info.end_ms = start + 60000;  // fallback
        }
    }
    catch (...)
    {
        info.start_ms = -1;
        info.end_ms = -1;
    }

    return info;
}

//
// 查询录像段
//
std::vector<RecordSegment> RecordManager::querySegments(const std::string& stream, int64_t start_ms, int64_t end_ms)
{
    std::lock_guard<std::mutex> lock(index_mutex_);

    std::vector<RecordSegment> result;
    if (start_ms <= 0 || end_ms <= 0 || start_ms >= end_ms) return result;
    if (!index_.count(stream)) return result;

    const auto& files = index_[stream];
    std::vector<RecordFileInfo> hits;

    for (const auto& f : files)
    {
        bool overlap = !(f.end_ms <= start_ms || f.start_ms >= end_ms);
        if (overlap) hits.push_back(f);
    }

    if (hits.empty()) return result;

    std::sort(hits.begin(), hits.end(), [](auto& a, auto& b) { return a.start_ms < b.start_ms; });

    int idx = 1;
    RecordSegment seg{};
    seg.index = idx;
    seg.start_ms = hits[0].start_ms;
    seg.end_ms = hits[0].end_ms;
    seg.files.push_back(hits[0]);

    for (size_t i = 1; i < hits.size(); ++i)
    {
        auto& prev = hits[i - 1];
        auto& cur = hits[i];

        bool continuous = (cur.start_ms - prev.end_ms) <= 2000;

        if (continuous)
        {
            seg.files.push_back(cur);
            seg.end_ms = cur.end_ms;
        }
        else
        {
            seg.segment_id = stream + "_" + std::to_string(seg.start_ms) + "_" + std::to_string(seg.end_ms);
            result.push_back(seg);

            idx++;
            seg = RecordSegment{};
            seg.index = idx;
            seg.start_ms = cur.start_ms;
            seg.end_ms = cur.end_ms;
            seg.files.push_back(cur);
        }
    }

    seg.segment_id = stream + "_" + std::to_string(seg.start_ms) + "_" + std::to_string(seg.end_ms);
    result.push_back(seg);

    return result;
}

//
// 根据 segmentId 获取 segment
//
RecordSegment RecordManager::getSegment(const std::string& segmentId)
{
    std::lock_guard<std::mutex> lock(index_mutex_);

    // 1) 找最后一个 "_"
    size_t pos_last = segmentId.rfind('_');
    if (pos_last == std::string::npos) return {};

    // 2) 再往前找一个 "_"
    size_t pos_mid = segmentId.rfind('_', pos_last - 1);
    if (pos_mid == std::string::npos) return {};

    // 3) 三段拆分
    std::string stream = segmentId.substr(0, pos_mid);
    std::string startStr = segmentId.substr(pos_mid + 1, pos_last - pos_mid - 1);
    std::string endStr = segmentId.substr(pos_last + 1);

    int64_t start_ms = 0;
    int64_t end_ms = 0;

    try
    {
        start_ms = std::stoll(startStr);
        end_ms = std::stoll(endStr);
    }
    catch (...)
    {
        LOG_ERROR("[RecordManager] segmentId parse failed: " + segmentId);
        return {};
    }

    // 确认 stream 在 index_ 里
    if (!index_.count(stream))
    {
        LOG_WARN("[RecordManager] stream not exist in index: " + stream);
        return {};
    }

    // 4) 根据时间区间收集属于该 segment 的所有文件
    const auto& files = index_[stream];

    RecordSegment seg;
    seg.segment_id = segmentId;
    seg.index = 1;
    seg.start_ms = start_ms;
    seg.end_ms = end_ms;

    for (const auto& f : files)
    {
        // 与 segment 时间区间有重叠的文件都属于这个 segment
        bool overlap = !(f.end_ms <= start_ms || f.start_ms >= end_ms);
        if (overlap) seg.files.push_back(f);
    }

    if (seg.files.empty())
    {
        LOG_WARN("[RecordManager] No files found for segmentId: " + segmentId);
        return {};
    }

    return seg;
}

int64_t RecordManager::toMsTimestamp(const std::string& s)
{
    std::tm tm{};
    char* ret = strptime(s.c_str(), "%Y-%m-%d %H:%M:%S", &tm);
    if (!ret) return -1;

    time_t t = mktime(&tm);
    return (int64_t)t * 1000;
}

std::string RecordManager::toReadable(int64_t ms)
{
    time_t t = ms / 1000;
    std::tm* tm = localtime(&t);

    char buf[32];
    strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm);
    return buf;
}

std::string RecordManager::loc_to_stream(int loc)
{
    // loc 必须 0~7
    if (loc < 0 || loc > 7) return "";

    return "AHD" + std::to_string(loc + 1) + "_main";
}
