<?php

use MediaWiki\MainConfigNames;
use MediaWiki\Shell\CommandFactory;
use MediaWiki\SyntaxHighlight\Pygmentize;
use MediaWiki\SyntaxHighlight\SyntaxHighlight;
use MediaWiki\SyntaxHighlight\Tests\TestPSRClientException;
use Shellbox\Command\BoxedCommand;
use Shellbox\Command\BoxedResult;
use Shellbox\ShellboxError;

/**
 * @covers MediaWiki\SyntaxHighlight\SyntaxHighlight
 * @covers MediaWiki\SyntaxHighlight\Pygmentize
 */
class PygmentizeTest extends MediaWikiIntegrationTestCase {
	protected function setUp(): void {
		parent::setUp();
		$this->overrideConfigValues( [
			// Run with the default useBundled=true
			'PygmentizePath' => false,
			// Silence wfWarn for the expected Shellbox error
			MainConfigNames::DevelopmentWarnings => false,
		] );
	}

	private function newInstance(): SyntaxHighlight {
		$services = $this->getServiceContainer();
		return new SyntaxHighlight(
			$services->getMainConfig(),
			$services->getMainWANObjectCache()
		);
	}

	private function stubShellbox( ?BoxedResult $result, ?Exception $e ) {
		$factory = $this->createStub( CommandFactory::class );
		$command = new class ( $result, $e ) extends BoxedCommand {
			private $result;
			private $e;

			public function __construct( $result, $e ) {
				$this->result = $result;
				$this->e = $e;
			}

			public function execute(): BoxedResult {
				if ( $this->e ) {
					throw $this->e;
				}
				return $this->result;
			}
		};
		$factory->method( 'createBoxed' )->willReturn( $command );
		$this->setService( 'ShellCommandFactory', $factory );
	}

	public static function provideHighlight() {
		yield 'basic' => [
			( new BoxedResult )
					->stdout( '<div class="mw-highlight><code>x</code></div>' )
					->exitCode( 0 ),
			null,
			'<div class="mw-highlight mw-highlight-lang-json mw-content-ltr" dir="ltr"><code>x</code></div>'
		];
		yield 'pre-fallback for non-zero exit' => [
			( new BoxedResult )
					->stdout( 'Boo' )
					->exitCode( 42 ),
			null,
			'<div class="mw-highlight mw-highlight-lang-json mw-content-ltr" dir="ltr"><pre>"example"</pre></div>'
		];
		yield 'pre-fallback for Shellbox error (T292663)' => [
			null,
			new ShellboxError( 'Wazaaaa', 0 ),
			'<div class="mw-highlight mw-highlight-lang-json mw-content-ltr" dir="ltr"><pre>"example"</pre></div>'
		];
		yield 'pre-fallback for network error (T292663)' => [
			null,
			new TestPSRClientException( 'Empty reponse from server', 0 ),
			'<div class="mw-highlight mw-highlight-lang-json mw-content-ltr" dir="ltr"><pre>"example"</pre></div>'
		];
	}

	/**
	 * @dataProvider provideHighlight
	 */
	public function testHighlightBasic( ?BoxedResult $result, ?Exception $e, string $expect ) {
		$this->stubShellbox( $result, $e );

		$this->hideDeprecated( SyntaxHighlight::class . '::highlight' );
		$status = SyntaxHighlight::highlight( '"example"', 'json' );
		$this->assertSame( $expect, $status->getValue() );

		$status = $this->newInstance()->syntaxHighlight( '"example"', 'json' );
		$this->assertSame( $expect, $status->getValue() );
	}

	public function testFetchGeneratedCss() {
		// Check that pygments.generated.css was generated by running the maintenance script
		$file = __DIR__ . '/../../modules/pygments.generated.css';
		$fileContent = file_get_contents( $file );

		$generatedCss = "/* Stylesheet generated by updateCSS.php */\n" . Pygmentize::fetchGeneratedCSS();
		$this->assertEquals( $generatedCss, $fileContent );
	}
}
