package jadx.tests.api;

import java.io.File;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.jetbrains.annotations.Nullable;

import jadx.api.JadxInternalAccess;
import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.RootNode;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.notNullValue;

public abstract class SmaliTest extends IntegrationTest {

	private static final String SMALI_TESTS_PROJECT = "jadx-core";
	private static final String SMALI_TESTS_DIR = "src/test/smali";
	private static final String SMALI_TESTS_EXT = ".smali";

	protected ClassNode getClassNodeFromSmali(String file, String clsName) {
		File smaliFile = getSmaliFile(file);
		return getClassNodeFromFiles(Collections.singletonList(smaliFile), clsName);
	}

	/**
	 * Preferred method for one file smali test
	 */
	protected ClassNode getClassNodeFromSmali() {
		return getClassNodeFromSmaliWithPkg(getTestPkg(), getTestName());
	}

	protected ClassNode getClassNodeFromSmaliWithClsName(String fullClsName) {
		return getClassNodeFromSmali(getTestPkg() + File.separatorChar + getTestName(), fullClsName);
	}

	protected ClassNode getClassNodeFromSmaliWithPath(String path, String clsName) {
		return getClassNodeFromSmali(path + File.separatorChar + clsName, clsName);
	}

	protected ClassNode getClassNodeFromSmaliWithPkg(String pkg, String clsName) {
		return getClassNodeFromSmali(pkg + File.separatorChar + clsName, pkg + '.' + clsName);
	}

	protected ClassNode getClassNodeFromSmaliFiles(String pkg, String testName, String clsName) {
		return getClassNodeFromFiles(collectSmaliFiles(pkg, testName), pkg + '.' + clsName);
	}

	protected ClassNode getClassNodeFromSmaliFiles(String clsName) {
		return searchCls(loadFromSmaliFiles(), getTestPkg() + '.' + clsName);
	}

	protected List<ClassNode> loadFromSmaliFiles() {
		jadxDecompiler = loadFiles(collectSmaliFiles(getTestPkg(), getTestName()));
		RootNode root = JadxInternalAccess.getRoot(jadxDecompiler);
		List<ClassNode> classes = root.getClasses(false);
		decompileAndCheck(jadxDecompiler, classes);
		return classes;
	}

	private List<File> collectSmaliFiles(String pkg, @Nullable String testDir) {
		String smaliFilesDir;
		if (testDir == null) {
			smaliFilesDir = pkg + File.separatorChar;
		} else {
			smaliFilesDir = pkg + File.separatorChar + testDir + File.separatorChar;
		}
		File smaliDir = new File(SMALI_TESTS_DIR, smaliFilesDir);
		String[] smaliFileNames = smaliDir.list((dir, name) -> name.endsWith(".smali"));
		assertThat("Smali files not found in " + smaliDir, smaliFileNames, notNullValue());
		return Stream.of(smaliFileNames)
				.map(file -> new File(smaliDir, file))
				.collect(Collectors.toList());
	}

	private static File getSmaliFile(String baseName) {
		File smaliFile = new File(SMALI_TESTS_DIR, baseName + SMALI_TESTS_EXT);
		if (smaliFile.exists()) {
			return smaliFile;
		}
		File pathFromRoot = new File(SMALI_TESTS_PROJECT, smaliFile.getPath());
		if (pathFromRoot.exists()) {
			return pathFromRoot;
		}
		throw new AssertionError("Smali file not found: " + smaliFile.getPath());
	}
}

@@ -2473,34 +2473,20 @@
 r = 
-new File(SMALI_TESTS_DIR, 
+getSmaliDir(
 smal
@@ -3174,11 +3174,379 @@
 h());%0A%09%7D
+%0A%0A%09private static File getSmaliDir(String baseName) %7B%0A%09%09File smaliDir = new File(SMALI_TESTS_DIR, baseName);%0A%09%09if (smaliDir.exists()) %7B%0A%09%09%09return smaliDir;%0A%09%09%7D%0A%09%09File pathFromRoot = new File(SMALI_TESTS_PROJECT, smaliDir.getPath());%0A%09%09if (pathFromRoot.exists()) %7B%0A%09%09%09return pathFromRoot;%0A%09%09%7D%0A%09%09throw new AssertionError(%22Smali dir not found: %22 + smaliDir.getPath());%0A%09%7D
 %0A%7D%0A

fix directory search for smali tests