// если версия явно не заданы вычисляем ее из тэга ревизии v.{num}***
// результатом будет версия '{num}.{distance}' где distance - расстояние от
// текущей ревизии до ревизии с тэгом
def tagDistance = 0;
def isRelease = false;

if (!version) {
    
    def rev = ["hg", "log", "-r", ".", "--template", "{latesttag('re:^v') % '{tag}-{distance}'}"].execute().text.trim();

    def tagVersion;

    def match = (rev =~ /^v(\d+\.\d+\.\d+).*-(\d+)$/);
    
    if (match.size()) {
        tagVersion = match[0][1];
        tagDistance = match[0][2].toInteger();

        version = tagVersion;

        if (tagDistance > 0)
            version++;
    } else {
        throw new Exception("A version must be specied");
    }
} else {
    println "explicit version: $version";
}

if (hasProperty('versionSuffix') && versionSuffix) {
    version += "-$versionSuffix"
}

if(!npmName)
    npmName = name;

if (hasProperty('release')) {
    isRelease = (release != 'false')
} else {
    isRelease = (tagDistance == 0);
}

if(!["amd", "commonjs", "system", "umd", "es6", "esnext"].contains(jsmodule))
    throw new Exception("Invalid jsmodule specified: $jsmodule");
if(!["es3", "es5", "es6", "es2016", "es2017", "esnext"].contains(target))
    throw new Exception("Invalid target specified: $target")

def targetLibs = [
    "es3" : "es5,es2015.promise,es2015.symbol,dom,scripthost",
    "es5" : "es5,es2015.promise,es2015.symbol,dom,scripthost"
];

ext.packageName="@$npmScope/$npmName";

def srcDir = "$projectDir/src"
def typingsDir = "$srcDir/typings"
def distDir = "$buildDir/dist"
def testDir = "$buildDir/test"
def lib = targetLibs[target] ?: "${target},dom";

println "lib: $lib";

def sourceSets = ["main", "amd", "cjs"];
def testSets = ["test", "testAmd", "testCjs"];

task beforeBuild {
}

def createSoursetTasks = { String name, String outDir ->
    def setName = name.capitalize();

    def compileDir = "$buildDir/compile/$name"
    def declDir = "$typingsDir/$name"
    def setDir = "$projectDir/src/$name"
    def jsDir = outDir;

    def beforeBuildTask = task "beforeBuild$setName"(dependsOn: beforeBuild) {
    }

    def copyJsTask = task "copyJs$setName"(dependsOn: beforeBuildTask, type: Copy) {
        from "$setDir/js"
        into jsDir
    }

    def lintJsTask = task "lintJs$setName"(dependsOn: beforeBuildTask, type: Exec) {
        inputs.dir("$setDir/js/").skipWhenEmpty();
        commandLine "eslint", '--format', 'stylish', "$setDir/js/"
    }

    def compileTsTask = task "compileTs$setName"(dependsOn: beforeBuildTask, type: Exec) {
        inputs.dir("$setDir/ts").skipWhenEmpty()
        inputs.file("$srcDir/tsconfig.json")
        inputs.file("$setDir/tsconfig.json")
        outputs.dir(compileDir)
        outputs.dir(declDir)

        commandLine 'node_modules/.bin/tsc',
            '-p', "$setDir/tsconfig.json",
            '-t', target,
            '-m', jsmodule,
            '-d',
            '--outDir', compileDir,
            '--declarationDir', declDir

        if (lib)
            args '--lib', lib
    }

    def copyTsOutputTask = task "copyTsOutput$setName"(dependsOn: compileTsTask, type: Copy) {
        from compileDir
        into jsDir
    }

    def copyTypingsTask = task "copyTypings$setName"(dependsOn: compileTsTask, type: Copy) {
        from declDir
        into jsDir
    }

    def copyResourcesTask = task "copyResources$setName"(dependsOn: beforeBuildTask, type: Copy) {
        from "$setDir/resources"
        into outDir
    }

    task "build$setName" {
        dependsOn copyTypingsTask,
            copyTsOutputTask,
            copyJsTask,
            copyResourcesTask,
            lintJsTask
    }
}

task printVersion {
    doLast {
        println "version: $version";
        println "isRelease: $isRelease, tagDistance: $tagDistance";
        println "packageName: $packageName";
        println "bundle: ${pack.outputs.files.join(',')}";
        println "target: $target";
        println "module: $jsmodule";
    }
}

task clean {
    doLast {
        delete buildDir
        delete typingsDir
    }
}

task _initBuild {
    mustRunAfter clean

    def buildInfoFile = "$buildDir/platform";
    inputs.property('target',target);
    inputs.property('jsmodule',jsmodule);
    outputs.file(buildInfoFile);

    doLast {
        delete buildDir
        mkdir buildDir

        def f = new File(buildInfoFile);
        f << "$target-$jsmodule";
    }
}

task cleanNpm {
    doLast {
        delete 'node_modules'
    }
}

task _npmInstall() {
    inputs.file("package.json")
    outputs.dir("node_modules")
    doLast {
        exec {
            commandLine 'npm', 'install'
        }
    }
}

beforeBuild {
    dependsOn _initBuild
    dependsOn _npmInstall
}

sourceSets.each { createSoursetTasks(it, distDir) }

testSets.each { createSoursetTasks(it, testDir) }

compileTsAmd {
    dependsOn compileTsMain
}

compileTsCjs {
    dependsOn compileTsMain
}

task build(dependsOn: buildMain) {
    if (jsmodule == "amd")
        dependsOn buildAmd
    if (jsmodule == "commonjs")
        dependsOn buildCjs
}

compileTsTest {
    dependsOn build
}

compileTsTestAmd {
    dependsOn compileTsTest
}

compileTsTestCjs {
    dependsOn compileTsTest
}

task _installLocalCjsDependency(dependsOn: [buildTestCjs, "_packageMeta"], type: Exec) {
    inputs.file("$distDir/package.json")
    outputs.upToDateWhen {
        new File("$testDir/$packageName").exists()
    }

    workingDir testDir

    commandLine 'npm', 'install', '--no-save', '--force', distDir
}

task test(dependsOn: [buildTest], type: Exec) {
    if (jsmodule == "amd")
        dependsOn buildTestAmd
    if (jsmodule == "commonjs") {
        dependsOn buildTestCjs
        dependsOn _installLocalCjsDependency
    }

    commandLine 'node', "$testDir/run-tests.js"
}

task _packageMeta(type: Copy) {
    mustRunAfter build

    inputs.property("version", version)
    from('.') {
        include '.npmignore', 'readme.md', 'license', 'history.md'
    }
    from("package.${jsmodule}.json") {
        expand project.properties
        rename { "package.json" }
    }
    into distDir
}

task pack(dependsOn: [build, _packageMeta], type: Exec) {
    def packageFile = "$npmScope-$npmName-${version}.tgz"
    workingDir distDir
    outputs.file("$buildDir/$packageFile")

    commandLine 'npm', 'pack'
    doLast {
        ant.move file: "$distDir/$packageFile",
                 todir: buildDir
    }
}

task publish(dependsOn: [build, _packageMeta], type: Exec) {
    doFirst {
        if (!isRelease)
            throw new Exception("Can't publish an unreleased version");
    }
    workingDir distDir

    commandLine 'npm', 'publish', '--access', 'public'
}

task markRelease(type: Exec) {
    onlyIf { tagDistance > 1 }
    commandLine "hg", "tag", "v$version";
}