/* -*- mode: c++ -*-
 * Copyright 2025 Dracal Technologies Inc. All rights reserved.
 */

#include <dracal/common/chrono.hpp>
#include <dracal/common/fmt.hpp>
#include <dracal/logging/utils.hpp>

namespace dracal::logging {

namespace utils {

std::vector<std::string> create_comment_section(const chrono::time_point<chrono::system_clock> now,
                                                const chrono::milliseconds interval, const std::string &comment) {

    const std::chrono::duration<double> seconds = interval;

    return {fmt::format("# Created: {}", common::format_timestamp_local_system_default(now)),
            fmt::format("# Interval: {:.6f} s", seconds.count()), fmt::format("# Comment: {}", comment), ""};
}

std::vector<std::string> create_header_section(const std::string &separator,
                                               const std::vector<std::string> &timestamp_column_names,
                                               const std::vector<std::string> &product_names,
                                               const std::vector<std::string> &channel_names,
                                               const std::vector<std::string> &channel_descriptions,
                                               const std::vector<std::string> &unit_symbols) {
    return {fmt::format("{}{}{}", fmt::join(timestamp_column_names, separator),
                        timestamp_column_names.size() == 0 ? "" : separator, fmt::join(product_names, separator)),
            fmt::format("{}{}", separator, fmt::join(channel_names, separator)),
            fmt::format("{}{}", separator, fmt::join(channel_descriptions, separator)),
            fmt::format("{}{}", separator, fmt::join(unit_symbols, separator))};
}

std::vector<std::string> timestamp_column_names(const timestamp_policy policy) {
    switch (policy) {
    case timestamp_policy::none:               return {};
    case timestamp_policy::system_default:     return {"DateTime"};
    case timestamp_policy::iso_8601_long:      return {"DateTime"};
    case timestamp_policy::iso_8601_long_dual: return {"Date", "Time"};
    case timestamp_policy::iso_8601_short:     return {"Time"};
    case timestamp_policy::iso_8601_long_ms:   return {"DateTime"};
    case timestamp_policy::iso_8601_long_ms_dual: return {"Date", "Time"};
    case timestamp_policy::iso_8601_short_ms:  return {"Time"};
    case timestamp_policy::epoch_ms:           return {"Timestamp"};
    }
    return {};
}

std::vector<std::string> format_timestamp(const timestamp_policy policy,
                                          const chrono::time_point<chrono::system_clock> ts) {
    switch (policy) {
    case timestamp_policy::none:
        return {};
    case timestamp_policy::system_default:
        return {common::format_timestamp_local_system_default(ts)};
    case timestamp_policy::iso_8601_long:
        return {common::format_timestamp_local_YYYYMMDDTHHMMSS(ts)};
    case timestamp_policy::iso_8601_long_dual: {
        const auto res = common::format_timestamp_local_YYYYMMDD_HHMMSS(ts);
        return {res[0], res[1]};
    }
    case timestamp_policy::iso_8601_short:
        return {common::format_timestamp_local_HHMMSS(ts)};
    case timestamp_policy::iso_8601_long_ms:
        return {common::format_timestamp_local_YYYYMMDDTHHMMSSmmm(ts)};
    case timestamp_policy::iso_8601_long_ms_dual: {
        const auto res = common::format_timestamp_local_YYYYMMDD_HHMMSSmmm(ts);
        return {res[0], res[1]};
    }
    case timestamp_policy::iso_8601_short_ms:
        return {common::format_timestamp_local_HHMMSSmmm(ts)};
    case timestamp_policy::epoch_ms:
        return {common::format_timestamp_milliseconds_from_epoch(ts)};
    }
    return {};
}

} // namespace utils

memory_sink_mt::memory_sink_mt(const size_t max_lines) : _max_lines(max_lines) {}

void memory_sink_mt::sink_it_(const spdlog::details::log_msg &msg) {
    if (_max_lines == 0) {
        return;
    }

    spdlog::memory_buf_t formatted;
    base_sink<std::mutex>::formatter_->format(msg, formatted);

    if (_lines.size() == _max_lines) {
        _lines.pop_front();
    }

    _lines.push_back(fmt::to_string(formatted));
}

void memory_sink_mt::flush_() {}

std::deque<std::string> memory_sink_mt::lines() {
    std::lock_guard<std::mutex> lock(mutex_);
    return _lines;
}

} // namespace dracal::logging