#include <filesystem>
#include <fstream>
#include <iostream>
#include <regex>
#include <string>
#include <vector>
#include <iomanip>
#include <cmath>
#include <cstring>
#include <optional>

#include "computing.h"

bool computeAdcResults(uint32_t &freq, double &amplitude, double &dc);

struct TestInfo {
    uint32_t referenceFreqKhz;
    double referenceAmplitudeMv;
    std::filesystem::path fileName;
};

std::optional<TestInfo> parseFileName(const std::filesystem::path &path) {
    static const std::regex re(R"((\d+)\s*khz.*?(\d+)\s*mv)",
                               std::regex::icase);

    std::smatch match;
    std::string name = path.stem().string();

    if (!std::regex_search(name, match, re))
        return std::nullopt;

    TestInfo info;
    info.referenceFreqKhz = std::stoul(match[1].str());
    info.referenceAmplitudeMv = std::stod(match[2].str());
    info.fileName = path;

    return info;
}

bool loadSamples(const std::filesystem::path &path, std::vector<uint8_t> &samples) {
    std::ifstream file(path);

    if (!file)
        return false;

    samples.clear();

    unsigned value;

    while (file >> value) {
        if (value > 255)
            return false;
        samples.push_back(static_cast<uint8_t>(value));
    }

    return !samples.empty();
}

int main()
{
    namespace fs = std::filesystem;

    std::cout
        << "File\t"
        << "Freq_ref_kHz\t"
        << "Amp_ref_mV\t"
        << "Freq_alg_kHz\t"
        << "Amp_alg_mV\t"
        << "Freq_abs_err_kHz\t"
        << "Freq_rel_err_% \t"
        << "Amp_abs_err_mV\t"
        << "Amp_rel_err_%"
        << '\n';

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

        if (entry.path().extension() != ".txt")
            continue;

        auto info = parseFileName(entry.path());

        if (!info)
            continue;

        std::vector<uint8_t> samples;

        if (!loadSamples(entry.path(), samples))
        {
            std::cerr << "Cannot read " << entry.path() << '\n';
            continue;
        }

        if (samples.size() != EXT_ADC_BUFFER_SIZE) {
            std::cerr << "ERROR: " << entry.path() << " invalid samples count: expect " << EXT_ADC_BUFFER_SIZE << ", got " << samples.size() << '\n';
            continue;
        }
        memcpy(ExtAdcBuffer, samples.data(), samples.size());

        uint32_t freqHz = 0;
        double amplitude = 0.0;
        double dc = 0.0;

        if (!computeAdcResults(freqHz, amplitude, dc)) {
            std::cerr << "Processing failed: " << entry.path() << '\n';
            continue;
        }
        const double freq = static_cast<double>(freqHz) / 1000.0;
        amplitude = amplitude * 1000.0;

        double freqAbsError = std::abs(static_cast<double>(freq) - info->referenceFreqKhz);
        double freqRelError = freqAbsError / info->referenceFreqKhz * 100.0;
        double ampAbsError = std::abs(amplitude - info->referenceAmplitudeMv);
        double ampRelError = ampAbsError / info->referenceAmplitudeMv * 100.0;

        std::cout
            << entry.path().filename().string() << '\t'
            << info->referenceFreqKhz << '\t'
            << info->referenceAmplitudeMv << '\t'
            << freq << '\t'
            << std::fixed << std::setprecision(2) << amplitude << '\t'
            << freqAbsError << '\t'
            << freqRelError << '\t'
            << ampAbsError << '\t'
            << ampRelError
            << '\n';
    }

    return 0;
}