import org.apache.tools.ant.taskdefs.condition.Os

import java.util.regex.Matcher
import java.util.regex.Pattern

def config = project.hasProperty("sentryCli") ? project.sentryCli : [];

gradle.projectsEvaluated {
    def releases = [:];
    android.applicationVariants.each { variant ->
        def releaseName = "${variant.getApplicationId()}-${variant.getVersionName()}";
        variant.outputs.each { output ->
            def versionCode = output.getVersionCode();
            def variantName = variant.getName();
            def outputName = output.getName();
            if (releases[variantName] == null) {
                releases[variantName] = [:];
            }
            releases[variantName][outputName] = [outputName, releaseName, versionCode];
        }
    }
    // separately we then hook into the bundle task of react native to inject
    // sourcemap generation parameters.  In case for whatever reason no release
    // was found for the asset folder we just bail.
    def bundleTasks = tasks.findAll { task ->
        task.name.startsWith("bundle") && task.name.endsWith("JsAndAssets")
    }
    bundleTasks.each { bundleTask ->
        def props = bundleTask.getProperties();
        def cmd = props.get("commandLine") as List<String>;
        def cmdArgs = props.get("args") as List<String>;
        def bundleOutput = null;
        def sourcemapOutput = null;
        def reactRoot = props.get("workingDir");
        def shouldCleanUp = false;

        cmdArgs.eachWithIndex{ String arg, int i ->
            if (arg == "--bundle-output") {
                bundleOutput = cmdArgs[i + 1];
            } else if (arg == "--sourcemap-output") {
                sourcemapOutput = cmdArgs[i + 1];
            }
        }

        if (sourcemapOutput == null) {
            sourcemapOutput = bundleOutput + ".map";
            cmd.push("--sourcemap-output");
            cmd.push(sourcemapOutput);
            cmdArgs.push("--sourcemap-output");
            cmdArgs.push(sourcemapOutput);

            shouldCleanUp = true
        }

        bundleTask.setProperty("commandLine", cmd);
        bundleTask.setProperty("args", cmdArgs);

        if (config.flavorAware) {
            println "**********************************"
            println "* Flavor aware sentry properties *"
            println "**********************************"
        }

        // Lets leave this here if we need to debug
        // println bundleTask.properties
        //     .sort{it.key}
        //     .collect{it}
        //     .findAll{!['class', 'active'].contains(it.key)}
        //     .join('\n')

        def currentRelease = "";
        def pattern = Pattern.compile("bundle([A-Z][A-Za-z0-9]+)JsAndAssets")
        Matcher matcher = pattern.matcher(bundleTask.name)
        if (matcher.find()) {
            def match = matcher.group(1);
            currentRelease = match.substring(0, 1).toLowerCase() + match.substring(1);
        }

        def currentVariants = null;
        releases.each { key, release ->
            if (key.equalsIgnoreCase(currentRelease)) {
                currentVariants = release;
            }
        }
        
        if (currentVariants == null) return;

        def variant = null;
        def releaseName = null;
        def versionCodes = new ArrayList<Integer>(currentVariants.size());

        currentVariants.each { key, currentVariant ->
            variant = currentVariant[0];
            releaseName = currentVariant[1];
            versionCodes.push(currentVariant[2]);
        }

        def cliTask = tasks.create(
            name: bundleTask.getName() + variant + "SentryUpload",
            type: Exec) {
            description = "upload debug symbols to sentry"

            def propertiesFile = "$reactRoot/android/sentry.properties";
            if (config.flavorAware) {
                propertiesFile = "$reactRoot/android/sentry-$variant"+".properties"
                println "For $variant using: $propertiesFile"
            } else {
                environment("SENTRY_PROPERTIES", propertiesFile)
            }
            Properties sentryProps = new Properties();
            try {
                sentryProps.load(new FileInputStream(propertiesFile));
            } catch (FileNotFoundException e) {
                println "File not found: $propertiesFile"
            }
            def cliExecutable = sentryProps.get("cli.executable", "$reactRoot/node_modules/@sentry/cli/bin/sentry-cli");

            workingDir reactRoot

            def args = [
                cliExecutable
            ];
            if (config.logLevel) {
                args.push("--log-level");
                args.push(config.logLevel);
            }

            if (config.flavorAware) {
                args.push("--url");
                args.push(sentryProps.get("defaults.url"));
                args.push("--auth-token");
                args.push(sentryProps.get("auth.token"));
            }

            args.push("react-native");
            args.push("gradle");
            args.push("--bundle");
            args.push(bundleOutput);
            args.push("--sourcemap");
            args.push(sourcemapOutput);
            args.push("--release");
            args.push(releaseName);

            if (config.flavorAware) {
                args.push("--org");
                args.push(sentryProps.get("defaults.org"));
                args.push("--project");
                args.push(sentryProps.get("defaults.project"));
            }

            versionCodes.each { versionCode ->
                args.add("--dist");
                args.add(versionCode);
            }

            if (config.logLevel) {
                println args
            }
            if (Os.isFamily(Os.FAMILY_WINDOWS)) {
                commandLine("cmd", "/c", *args)
            } else {
                commandLine(*args)
            }
            enabled true
        }

        def cliCleanUpTask = tasks.create(
            name: bundleTask.getName() + variant + "SentryUploadCleanUp",
            type: Delete) {
            description = "clean up extra sourcemap"

            delete sourcemapOutput
        };

        bundleTask.doLast {
            cliTask.execute();
            if (shouldCleanUp) {
                cliCleanUpTask.execute();
            }
        }

        cliTask.dependsOn(bundleTask)
    }
}
