#pragma once

#include <istream>
#include <string>

#include "alib/exception"
#include "common/ResultInterpret.h"
#include "global/GlobalData.h"
#include "environment/Environment.h"
#include "readline/IstreamLineInterface.h"
#include "readline/StringLineInterface.h"

struct AqlTestResult {
	int retcode;
	unsigned seed;
	std::string output;
};

/** @brief Runs AQL test with code stored in stream */
template < typename Stream >
AqlTestResult AqlTest ( Stream & is, unsigned seed ) {
	try {
		cli::Environment environment;
		cli::CommandResult result;

		// Capture CLI output
		std::ostringstream oss;
		common::Streams::out = ext::reference_wrapper < std::ostream > ( oss );
		common::Streams::err = ext::reference_wrapper < std::ostream > ( oss );

		// seed cli, run test file
		auto testSeed = std::make_shared < cli::StringLineInterface > ( "set seed " + ext::to_string ( seed ) );
		auto testFile = std::make_shared < cli::IstreamLineInterface < Stream& > > ( is );
		result = environment.execute ( testSeed );
		result = environment.execute ( testFile );

		int returnValue;
		if ( result == cli::CommandResult::QUIT || result == cli::CommandResult::RETURN ) {
			returnValue = cli::ResultInterpret::cli ( environment.getResult ( ) );
		} else if ( result == cli::CommandResult::EOT || result == cli::CommandResult::OK ) {
			returnValue = 0;
		} else {
			returnValue = 4;
		}

		return { returnValue, seed, oss.str ( ) };
	} catch ( const std::exception & ) {
		std::ostringstream oss;
		alib::ExceptionHandler::handle ( oss );
		return { -1, seed, oss.str ( ) };
	}
}
