//
// LDASTools frameCPP - FrCheck Validation for Serial Reader No-TOC Test
//
// Validates that frames generated by test_serial_reader_no_toc pass FrCheck
//

#include <iostream>
#include <fstream>
#include <sstream>
#include <stdexcept>
#include <cstdlib>

#define BOOST_TEST_MAIN
#include <boost/test/included/unit_test.hpp>

// FrameCPP includes
#include "framecpp/FrameCPP.hh"
#include "framecpp/Common/FrameSpec.hh"
#include "framecpp/Common/MemoryBuffer.hh"
#include "framecpp/Common/FrameStream.hh"
#include "framecpp/Common/FrameCPPServices.hh"

// LDAS Tools includes
#include "ldastoolsal/LoggerManager.hh"

// Frame sample helper
#define USING_MAKE_FRAME_VERSION 1
#include "FrSample.hh"

using namespace FrameCPP;
using namespace FrameCPP::Common;

/// \brief Global logger manager
static std::unique_ptr<LDASTools::AL::LoggerManager> g_logger_mgr;

/// \brief Initialize FrameCPP
bool do_init()
{
    FrameCPP::Initialize();
    return true;
}

static const bool HAS_BEEN_INITIALIZED = do_init();

/// \brief Global initializer
struct GlobalInitializer
{
    GlobalInitializer()
    {
        g_logger_mgr = std::make_unique<LDASTools::AL::LoggerManager>();
    }
};

static GlobalInitializer g_initializer;

/// \brief Test frame generation and FrCheck validation for a single version
bool testVersionWithFrCheck(int version)
{
    std::ostringstream msg;
    msg << "Testing frame version " << version << " with FrCheck";
    BOOST_TEST_MESSAGE(msg.str());

    try
    {
        // Create test frame
        stat_data_container_type stat_data;
        make_frame_ret_type original_frame = makeFrameVersion(version, stat_data);

        if (!original_frame)
        {
            BOOST_TEST_MESSAGE("  FAIL: makeFrameVersion returned null");
            return false;
        }

        // Write frame to MemoryBuffer WITHOUT TOC
        std::string frame_data;
        {
            MemoryBuffer* write_buffer = new MemoryBuffer(std::ios::out);
            OFrameStream ofs(write_buffer, version);
            ofs.DisableTOC();
            ofs.WriteFrame(original_frame);
            ofs.Close();
            frame_data = write_buffer->str();
            std::cout << "  Generated " << frame_data.size() << " bytes" << std::endl;
        }

        // Write to temporary file
        std::string temp_filename = "test_serial_reader_v" + std::to_string(version) + "_notoc.gwf";
        {
            std::ofstream temp_file(temp_filename, std::ios::binary);
            if (!temp_file)
            {
                BOOST_TEST_MESSAGE("  FAIL: Could not create temporary file");
                return false;
            }
            temp_file.write(frame_data.data(), frame_data.size());
            temp_file.close();
            std::cout << "  Wrote to " << temp_filename << std::endl;
        }

        // Run FrCheck with -s flag (sequential read only, skip TOC test)
        // Since we intentionally created files without TOC, we must skip TOC validation
#ifndef FRCHECK_PATH
#error "FRCHECK_PATH must be defined by CMake"
#endif
        std::string frcheck_cmd = std::string(FRCHECK_PATH) + " -s -i " + temp_filename;
        std::cout << "  Running: " << frcheck_cmd << std::endl;

        int result = system(frcheck_cmd.c_str());

        // Clean up temporary file
        std::remove(temp_filename.c_str());

        if (result != 0)
        {
            BOOST_TEST_MESSAGE("  FAIL: FrCheck returned exit code " << (result >> 8));
            return false;
        }

        BOOST_TEST_MESSAGE("  PASS: FrCheck validation succeeded");
        return true;
    }
    catch (const std::exception& e)
    {
        BOOST_TEST_MESSAGE("  FAIL: Exception: " << e.what());
        return false;
    }
}

BOOST_AUTO_TEST_CASE(test_v6_frcheck)
{
    BOOST_CHECK(testVersionWithFrCheck(6));
}

BOOST_AUTO_TEST_CASE(test_v7_frcheck)
{
    BOOST_CHECK(testVersionWithFrCheck(7));
}

BOOST_AUTO_TEST_CASE(test_v8_frcheck)
{
    BOOST_CHECK(testVersionWithFrCheck(8));
}
