#include <softbus_core/alignment/TimeAligner.h>

#include <algorithm>
#include <cmath>
#include <limits>

namespace softbus::core {

TimeAligner::TimeAligner(TimeAlignerConfig config)
    : config_(config)
{
}

void TimeAligner::setConfig(const TimeAlignerConfig& config)
{
    std::lock_guard<std::mutex> lock(mutex_);
    config_ = config;
}

TimeAlignerConfig TimeAligner::config() const
{
    std::lock_guard<std::mutex> lock(mutex_);
    return config_;
}

DOMMessage TimeAligner::rawToDom(const RawPacket& raw) const
{
    DOMMessage dom;
    dom.traceId = raw.traceId;
    dom.id = raw.sourceId;
    dom.sourceId = raw.sourceId;
    dom.timestampNs = raw.timestampNs;
    dom.domain = DomDomain::Process;
    dom.quality = QualityCode::Good;
    dom.value = {
        {"protocol", raw.protocolTag},
        {"runtimeDeviceId", raw.runtimeDeviceId},
        {"payloadSize", raw.payload.size()},
        {"payloadHex", nlohmann::json::array()}
    };
    for (const auto byte : raw.payload) {
        dom.value["payloadHex"].push_back(byte);
    }
    return dom;
}

void TimeAligner::ingest(const RawPacket& raw)
{
    ingestDom(rawToDom(raw));
}

void TimeAligner::ingestDom(const DOMMessage& dom)
{
    std::lock_guard<std::mutex> lock(mutex_);
    auto& buffer = channels_[dom.sourceId].samples;
    buffer.push_back(dom);
    while (buffer.size() > 256) {
        buffer.pop_front();
    }
    lastAnchorNs_ = std::max(lastAnchorNs_, dom.timestampNs);
}

AlignedSample TimeAligner::alignAt(int64_t anchorNs)
{
    AlignedSample sample;
    sample.anchorTimestampNs = anchorNs;

    for (auto& [sourceId, channel] : channels_) {
        auto& samples = channel.samples;
        if (samples.empty()) {
            continue;
        }

        DOMMessage best;
        int64_t bestDelta = std::numeric_limits<int64_t>::max();
        bool found = false;

        for (const auto& candidate : samples) {
            const int64_t delta = std::llabs(candidate.timestampNs - anchorNs);
            if (delta <= config_.windowNs && delta < bestDelta) {
                bestDelta = delta;
                best = candidate;
                found = true;
            }
        }

        if (found) {
            sample.channels[sourceId] = best;
        }
    }

    return sample;
}

std::vector<AlignedSample> TimeAligner::drainAligned()
{
    std::lock_guard<std::mutex> lock(mutex_);
    if (lastAnchorNs_ == 0 || channels_.empty()) {
        return {};
    }

    std::vector<AlignedSample> result;
    result.push_back(alignAt(lastAnchorNs_));
    return result;
}

} // namespace softbus::core
