<?php
namespace MediaWiki\Extension\Math\WikiTexVC;

use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\Util\MMLComparator;
use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\Util\MMLTestUtil;
use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\Util\MMLTestUtilHTML;
use MediaWikiUnitTestCase;
use Psr\Log\InvalidArgumentException;

/**
 * This is a very basic test for running more cases for MathML generation.
 * WIP: This tests is for running the specified testfiles in development.
 * Categories can be selected within 'provideTestCases' functions.
 * @covers \MediaWiki\Extension\Math\WikiTexVC\TexVC
 */
final class MMLGenerationParserTest extends MediaWikiUnitTestCase {
	/** @var float */
	private static $SIMILARITYTRESH = 0.7;
	/** @var bool */
	private static $SKIPXMLVALIDATION = true;

	/** @var string */
	private static $SELECTEDCATEGORY1 = "texvctreebugs";
	/** @var string */
	private static $FILENAME1 = __DIR__ . "/tex-2-mml.json";
	/** @var string */
	private static $FILENAME2 = __DIR__ . "/ParserTest-Ref.json";
	/** @var int */
	private static $SELECTEDFILE = 0; // 0 , 1 ... for selecting file
	/** @var bool */
	private static $APPLYFILTER = false;
	/** @var int */
	private static $FILTERSTART = 0;
	/** @var int */
	private static $FILTERLENGTH = 50;

	/** @var bool */
	private static $GENERATEHTML = false;
	/** @var string */
	private static $GENERATEDHTMLFILE = __DIR__ . "/MMLGenerationParserTest-Output.html";

	protected function setUp(): void {
		parent::setUp();
	}

	protected function tearDown(): void {
		parent::tearDown();
	}

	public static function setUpBeforeClass(): void {
		MMLTestUtilHTML::generateHTMLstart( self::$GENERATEDHTMLFILE, [ "name", "Tex-Input",
			"MathML(LaTeXML)", "MathML(Mathoid)", "MathML(WikiTexVC)", "F-Similarity" ], self::$GENERATEHTML );
	}

	public static function tearDownAfterClass(): void {
		MMLTestUtilHTML::generateHTMLEnd( self::$GENERATEDHTMLFILE, self::$GENERATEHTML );
	}

	/**
	 * @dataProvider provideTestCases
	 */
	public function testTexVC( $title, $tc ) {
		$texVC = new TexVC();

		if ( $tc->skipped ?? false ) {
			MMLTestUtilHTML::generateHTMLtableRow( self::$GENERATEDHTMLFILE, [ $tc->ctr, $tc->input,
				"skipped", "skipped" ], false, self::$GENERATEHTML );
			$this->addToAssertionCount( 1 );
			return;
		}
		# Fetch result from WikiTexVC(PHP)
		$resultT = $texVC->check( $tc->input, [
			'debug' => false,
			'usemathrm' => $tc->usemathrm ?? false,
			'oldtexvc' => $tc->oldtexvc ?? false
		] );

		$mathMLtexVC = MMLTestUtil::getMMLwrapped( $resultT["input"] );
		if ( self::$SELECTEDFILE == 0 ) {
			// File 0 has no refs, is just for checking basics.
			MMLTestUtilHTML::generateHTMLtableRow( self::$GENERATEDHTMLFILE, [ $tc->ctr,
				$tc->input, $tc->mmlLaTeXML ?? "tbd", "tbd",
				$mathMLtexVC, -0.0 ], false, self::$GENERATEHTML );
			$this->addToAssertionCount( 1 );
			return;
		}
		$mmlComparator = new MMLComparator();
		$compRes = $mmlComparator->compareMathML( $tc->mmlMathoid, $mathMLtexVC );
		MMLTestUtilHTML::generateHTMLtableRow( self::$GENERATEDHTMLFILE, [ $tc->ctr,
			$tc->input, $tc->mmlLaTeXML ?? "tbd", $tc->mmlMathoid ?? "tbd",
			$mathMLtexVC, $compRes['similarityF'] ], false, self::$GENERATEHTML );

		if ( !self::$SKIPXMLVALIDATION ) {
			if ( !$tc->mmlMathoid ) {
				$this->fail( "No Mathoid reference found for: " . $tc->input );
			}
			if ( $compRes['similarityF'] >= self::$SIMILARITYTRESH ) {
				$this->addToAssertionCount( 1 );
			} else {
				$this->assertXmlStringEqualsXmlString( $tc->mmlMathoid, $mathMLtexVC );
			}
		} else {
			$this->addToAssertionCount( 1 );
		}
	}

	public static function provideTestCases() {
		switch ( self::$SELECTEDFILE ) {
			case 0:
				return self::provideTestCases1();
			case 1:
				return self::provideTestCases2();
			default:
				self::throwException( new InvalidArgumentException( "No correct file specified" ) );
				return [];
		}
	}

	/**
	 * Provide testcases and filter and format them for
	 * the first testfile 'tex-2-mml.json'.
	 * @return array
	 */
	public static function provideTestCases1() {
		$res = MMLTestUtil::getJSON( self::$FILENAME1 );
		$f = $res->{self::$SELECTEDCATEGORY1};

		// Adding running indices for location of tests.
		$indexCtr = 0;
		foreach ( $f as $tc ) {
			$tc[1]->ctr = $indexCtr;
			$indexCtr += 1;
		}
		// Filtering results by index if necessary
		if ( self::$APPLYFILTER ) {
			$f = array_slice( $f, self::$FILTERSTART, self::$FILTERLENGTH );
		}
		return $f;
	}

	/**
	 * Provide testcases and filter and format them for
	 * the second testfile 'ParserTest.json'.
	 * @return array
	 */
	public static function provideTestCases2() {
		$res = MMLTestUtil::getJSON( self::$FILENAME2 );
		$f = [];
		// Adding running indices for location of tests.
		$indexCtr = 0;
		foreach ( $res as $tc ) {
			$tc->ctr = $indexCtr;
			$tc->input = $tc->tex; // Just to have uniform access here
			$indexCtr += 1;
			array_push( $f, [ "title N/A", $tc ] );
		}
		// Filtering results by index if necessary
		if ( self::$APPLYFILTER ) {
			$f = array_slice( $f, self::$FILTERSTART, self::$FILTERLENGTH );
		}
		return $f;
	}
}