package me.coley.recaf;

import me.coley.recaf.control.Controller;
import me.coley.recaf.control.headless.HeadlessController;
import me.coley.recaf.decompile.cfr.CfrDecompiler;
import me.coley.recaf.decompile.fernflower.FernFlowerDecompiler;
import me.coley.recaf.decompile.procyon.ProcyonDecompiler;
import me.coley.recaf.workspace.*;
import org.junit.jupiter.api.*;

import java.io.IOException;

import static org.junit.jupiter.api.Assertions.*;

/**
 * Decompiler implementation tests.
 *
 * @author Matt
 */
public class DecompileTest extends Base {
	private Controller controller;

	@Nested
	public class Basic {
		@BeforeEach
		public void setup() {
			try {
				JavaResource resource = new JarResource(getClasspathFile("inherit.jar"));
				resource.getClasses();
				resource.getFiles();
				controller = DecompileTest.setup(resource);
			} catch(IOException ex) {
				fail(ex);
			}
		}

		@Test
		public void testFernFlower() {
			FernFlowerDecompiler decompiler = new FernFlowerDecompiler();
			for (String name : controller.getWorkspace().getPrimaryClassNames()) {
				String decomp = decompiler.decompile(controller, name);
				assertNotNull(decomp);
			}
		}

		@Test
		public void testCfr() {
			CfrDecompiler decompiler = new CfrDecompiler();
			for (String name : controller.getWorkspace().getPrimaryClassNames()) {
				String decomp = decompiler.decompile(controller, name);
				assertNotNull(decomp);
			}
		}

		@Test
		public void testProcyon() {
			ProcyonDecompiler decompiler = new ProcyonDecompiler();
			for (String name : controller.getWorkspace().getPrimaryClassNames()) {
				String decomp = decompiler.decompile(controller, name);
				assertNotNull(decomp);
			}
		}
	}

	@Nested
	public class FernFlower {
		@Test
		public void testNamedInner() {
			try {
				JavaResource resource = new JarResource(getClasspathFile("InnerTest.jar"));
				resource.getClasses();
				resource.getFiles();
				controller = DecompileTest.setup(resource);
				FernFlowerDecompiler decompiler = new FernFlowerDecompiler();
				String decomp = decompiler.decompile(controller, "Host$InnerMember");
				assertNotNull(decomp);
				assertFalse(decomp.trim().isEmpty());
			} catch(IOException ex) {
				fail(ex);
			}
		}

		@Test
		public void testAnonymousInner() {
			try {
				JavaResource resource = new JarResource(getClasspathFile("InnerTest.jar"));
				resource.getClasses();
				resource.getFiles();
				controller = DecompileTest.setup(resource);
				FernFlowerDecompiler decompiler = new FernFlowerDecompiler();
				String decomp = decompiler.decompile(controller, "Host$1");
				assertNotNull(decomp);
				assertFalse(decomp.trim().isEmpty());
			} catch(IOException ex) {
				fail(ex);
			}
		}
	}

	private static Controller setup(JavaResource resource) {
		Controller controller = new HeadlessController(null, null);
		controller.setWorkspace(new Workspace(resource));
		return controller;
	}

	// TODO: Test for options working by decompiling a synthetic member with differing options
}

@@ -389,16 +389,48 @@
 ception;
+%0Aimport java.lang.reflect.Field;
 %0A%0Aimport
@@ -837,35 +837,31 @@
 oller = 
-DecompileTest.setup
+setupController
 (resourc
@@ -909,32 +909,100 @@
 (ex);%0A%09%09%09%7D%0A%09%09%7D%0A%0A
+%09%09@AfterEach%0A%09%09public void shutdown() %7B%0A%09%09%09removeController();%0A%09%09%7D%0A%0A
 %09%09@Test%0A%09%09public
@@ -1825,16 +1825,84 @@
 lower %7B%0A
+%09%09@AfterEach%0A%09%09public void shutdown() %7B%0A%09%09%09removeController();%0A%09%09%7D%0A%0A
 %09%09@Test%0A
@@ -2092,35 +2092,31 @@
 oller = 
-DecompileTest.setup
+setupController
 (resourc
@@ -2588,27 +2588,23 @@
 r = 
-DecompileTest.setup
+setupController
 (res
@@ -2898,16 +2898,26 @@
 er setup
+Controller
 (JavaRes
@@ -3073,16 +3073,486 @@
 er;%0A%09%7D%0A%0A
+%09private static void removeController() %7B%0A%09%09try %7B%0A%09%09%09// In %22Recaf.java%22 we prevent setting the controller twice...%0A%09%09%09// I swear I'm taking crazy pills, because the surefire config should be isolating tests...%0A%09%09%09// That means each test should get a separate JVM. But clearly something is wrong.%0A%09%09%09Field f = Recaf.class.getDeclaredField(%22currentController%22);%0A%09%09%09f.setAccessible(true);%0A%09%09%09f.set(null, null);%0A%09%09%7D catch(Exception ex) %7B%0A%09%09%09fail(%22Failed to reset%22);%0A%09%09%7D%0A%09%7D%0A%0A
 %09// TODO

Add hack to make decompile tests pass... I swear the surefire config should isolate each test, but it doesn't seem to be the case