import com.diffplug.gradle.spotless.SpotlessExtension
import org.jetbrains.kotlin.ir.types.IdSignatureValues.result
// import nl.javadude.gradle.plugins.license.DownloadLicensesExtension
// import nl.javadude.gradle.plugins.license.LicenseExtension
import org.springframework.boot.gradle.tasks.run.BootRun
import java.nio.file.Files

group = "nl.tudelft.ewi.queue"
version = "2.2.2"

val javaVersion = JavaVersion.VERSION_17

val libradorVersion = "1.2.2-SNAPSHOT"
val labradoorVersion = "1.4.1-SNAPSHOT"
val chihuahUIVersion = "1.0.2"
val queryDslVersion = "4.4.0"

// A definition of all dependencies and repositories where to find them that need to
// be available during compilation of this build script.
buildscript {
	dependencies {
		// Spring Loaded for hot reloading Java classes within IntelliJ
		// specifically for the Spring Boot development capabilities.
		classpath("org.springframework", "springloaded", "1.2.8.RELEASE")
	}
}

// The repositories used to lookup dependencies.
repositories {
	mavenLocal()
	mavenCentral()

	maven {
		url = uri("https://build.shibboleth.net/nexus/content/repositories/releases")
	}
	maven {
		name = "GitLab Librador repository"
		url = uri("https://gitlab.ewi.tudelft.nl/api/v4/projects/3634/packages/maven")
	}
	maven {
		name = "GitLab Labradoor repository"
		url = uri("https://gitlab.ewi.tudelft.nl/api/v4/projects/3611/packages/maven")
	}
    maven {
        name = "GitLab ChihuahUI repository"
        url = uri("https://gitlab.ewi.tudelft.nl/api/v4/projects/8633/packages/maven")
    }
}

// The plugins used by Gradle to generate files, start Spring boot, perform static analysis etc.
plugins {
	// Plugin for the Kotlin-DSL to be on classpath, disabled
	// because it does not need to be applied during build.
	`kotlin-dsl` apply false

	// Standard plugins for Gradle to work properly
	java
	`maven-publish`
	eclipse
	idea
	jacoco

	// Spring plugins for managing dependencies and creating
	// a nice Spring Boot application.
	id("org.springframework.boot").version("2.5.14")
	id("io.spring.dependency-management").version("1.0.11.RELEASE")

	// Plugin to provide task to check the current versions of
	// dependencies and of Gradle to see if updates are available.
	id("com.github.ben-manes.versions").version("0.39.0")

	// Spotless plugin for checking style of Java code.
	id("com.diffplug.spotless").version("6.10.0")

	// Plugin for checking license headers within our code and files.
	//id("com.github.hierynomus.license").version("0.16.1")
	//id("org.cadixdev.licenser").version("0.6.1")

	// Plugin for checking security issues in dependencies of this project.
	id("org.owasp.dependencycheck").version("5.3.0") apply false

	// Open API generator for generating the Client code for Labracore.
	//id("org.openapi.generator").version("4.2.3")

    // Sass compiler plugin
//	id("com.unclezs.gradle.sass").version("1.0.10")

	// generate git info
	id("com.gorylenko.gradle-git-properties").version("2.4.0-rc1")
}

sourceSets {
    main {}

    test {}
}

/////// Plugins configurations ///////
java {
    sourceCompatibility = javaVersion
    targetCompatibility = javaVersion
}

publishing {
    publications {
        create<MavenPublication>("generatePom") {
            from(components.findByName("java"))
            pom {
                withXml {
                    val repos = asNode().appendNode("repositories")
                    fun repository(id: String, url: String) {
                        val repo = repos.appendNode("repository")
                        repo.appendNode("id", id)
                        repo.appendNode("url", url)
                    }

                    repository("shibboleth", "https://build.shibboleth.net/nexus/content/repositories/releases")
                    repository("librador", "https://gitlab.ewi.tudelft.nl/api/v4/projects/3634/packages/maven")
                    repository("labradoor", "https://gitlab.ewi.tudelft.nl/api/v4/projects/3611/packages/maven")
                    repository("chiuhahui", "https://gitlab.ewi.tudelft.nl/api/v4/projects/8633/packages/maven")
                }
            }
        }
    }
}

// Configure Jacoco testing plugin.
configure<JacocoPluginExtension> {
    toolVersion = "0.8.7"
}

// Configure license plugins.
//license {
//    header.set(resources.text.fromFile(file("$rootDir/LICENSE.header")))
	//properties {
	//	year.set(2021)
	//}
//	exclude("**/*.json")
	//"**/*.scss",
	//"**/*.ico",
	//"**/*.png",
	//"**/*.jks",
	//"**/*.css"
//}

//configure<DownloadLicensesExtension> {
//    includeProjectDependencies = true
//}
//
//configure<LicenseExtension> {
//    header = file("$rootDir/LICENSE.header")
//    skipExistingHeaders = false
//
//    mapping(mapOf(
//            "java" to "SLASHSTAR_STYLE",
//            "template" to "SCRIPT_STYLE"
//    ))
//
//    excludes(listOf(
//            "** /*.json",
//            "** /*.scss",
//            "** /*.ico",
//            "** /*.png",
//            "** /*.jks",
//            "** /*.css"
//    ))
//}

// Configure Spotless plugin for style checking Java code.
configure<SpotlessExtension> {
    format("frontend") {
        target("src/main/resources/**/*.html", "src/main/resources/**/*.js", "src/main/resources/scss/**/*.scss")

        prettier("2.6").config(mapOf(
            "tabWidth" to 4, "semi" to true,
            "printWidth" to 150,
            "bracketSameLine" to true,
            "arrowParens" to "avoid",
            "htmlWhitespaceSensitivity" to "ignore"))
    }

    java {
        // Use the eclipse formatter format and import order.
        eclipse().configFile(file("eclipse-formatter.xml"))
        importOrderFile(file("$rootDir/importorder.txt"))

        // Check for a license header in the form of LICENSE.header.java.
        licenseHeaderFile(file("$rootDir/LICENSE.header.java"))

        // Default added rules.
        //paddedCell()
        removeUnusedImports()
        trimTrailingWhitespace()
        endWithNewline()
    }
}

/////// TASKS ///////
val jacocoTestReport by tasks.getting(JacocoReport::class) {
    group = "Reporting"
    reports {
        xml.required.set(true)
        csv.required.set(true)

        html.outputLocation.set(file("$buildDir/reports/coverage"))
    }
}

val jar by tasks.getting(Jar::class) {
    // Set the name and version of the produced JAR
    archiveBaseName.set("queue")
    archiveVersion.set("2.0.0")
}

// generates BuildProperties bean (used by Sentry)
springBoot {
	buildInfo()
}

// Configure Spring Boot plugin task for running the application.
val bootRun by tasks.getting(BootRun::class) {
    sourceResources(sourceSets.main.get())
}

// Configure the sass compiling task to use the sass and css directories.
//sass {
//  cssPath = "static/css"
//  sassPath = "scss"
//}

tasks.register("ensureDirectory") {
    // Store target directory into a variable to avoid project reference in the configuration cache
    val directory = file("src/main/resources/static/css")

    doLast {
        Files.createDirectories(directory.toPath())
    }
}

task<Exec>("sassCompile") {
    dependsOn.add(tasks.getByName("ensureDirectory"))
    if (System.getProperty("os.name").contains("windows",true)) {
        commandLine("cmd", "/c", "sass", "src/main/resources/scss:src/main/resources/static/css")
    } else {
        commandLine("echo", "Checking for sass or sassc...")
        doLast {
            val res = exec {
                isIgnoreExitValue = true
                executable = "bash"
                args = listOf("-l", "-c", "sass --version")
            }
            if (res.exitValue == 0) {
                exec { commandLine("sass", "src/main/resources/scss:src/main/resources/static/css") }
            } else {
                File("src/main/resources/scss").listFiles()!!.filter { it.extension == "scss" && !it.name.startsWith("_") }.forEach {
                    exec { commandLine("sassc", "src/main/resources/scss/${it.name}", "src/main/resources/static/css/${it.nameWithoutExtension}.css") }
                }
            }
        }

    }
}

val processResources by tasks.getting(ProcessResources::class) {
    dependsOn.add(tasks.getByName("sassCompile"))
}

// we don't use the "plain"/light jar
tasks.getByName<Jar>("jar") {
    enabled = false
}

tasks.withType<Test>().configureEach {
    useJUnitPlatform()
    minHeapSize = "256m"
    maxHeapSize = "1024m"

    testLogging {
        // Turn this on when needing to debug gradle test runs
        showStandardStreams = false
    }
}
tasks.getByName<Test>("test") {
    filter {
        excludeTestsMatching("e2e.*")
    }
}
tasks.register<Test>("e2eTest") {
    filter {
        includeTestsMatching("e2e.*")
    }
}

dependencies {
    /////// Spring dependencies ///////

    // Generic Spring Boot starter dependencies
    implementation("org.springframework.boot:spring-boot-starter")
    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
    implementation("org.springframework.boot:spring-boot-starter-data-rest")
    implementation("org.springframework.boot:spring-boot-starter-mail")
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("org.springframework.boot:spring-boot-starter-websocket")
    implementation("org.springframework.boot:spring-boot-starter-webflux")
    implementation("org.springframework.boot:spring-boot-starter-validation")

    // Spring Boot and jedis dependencies for interacting with redis session stores.
    implementation("org.springframework.boot:spring-boot-starter-data-redis")
    implementation("redis.clients:jedis")
    implementation("org.springframework.session:spring-session-core")
    implementation("org.springframework.session:spring-session-data-redis")

    // Dependencies for enabling Spring security + SAML security in Spring
    implementation("org.springframework.boot:spring-boot-starter-security")

    // Dependency for websocket security by Spring
    implementation("org.springframework.security:spring-security-messaging")

    // Jaeger Spring dependencies for creating and sending Spans
    implementation("io.opentracing.contrib:opentracing-spring-jaeger-starter:3.1.2")
    implementation("io.opentracing.contrib:opentracing-spring-jaeger-web-starter:3.1.2")

    // Dependencies for enabling Thymeleaf templating language with Spring.
    implementation("org.springframework.boot:spring-boot-starter-thymeleaf")
    implementation("org.thymeleaf:thymeleaf-spring5")
    implementation("org.thymeleaf.extras:thymeleaf-extras-springsecurity5")
    implementation("org.thymeleaf.extras:thymeleaf-extras-java8time")
    implementation("nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect")

    /////// Other dependencies ///////
	implementation("io.swagger.core.v3:swagger-annotations:2.1.12")

    // Labrador project dependencies
    implementation("nl.tudelft.labrador:librador:$libradorVersion") {
        exclude("org.springframework.boot:spring-boot-starter-data-rest")
    }
    implementation("nl.tudelft.labrador:labradoor:$labradoorVersion")
    implementation("nl.tudelft.labrador:chihuahui:$chihuahUIVersion")

    // Java assist dependency
    implementation("org.javassist:javassist:3.25.0-GA")

    //    implementation("org.apache.httpcomponents", "fluent-hc", "4.5.5")

    // Bouncycastle for implementations of the Java Crypto API (JDK1.5-11)
    implementation("org.bouncycastle:bcpkix-jdk15on:1.64")
    implementation("org.bouncycastle:bcprov-jdk15on:1.64")

    // WebPush library for sending push notifications
    implementation("nl.martijndwars:web-push:5.1.1")

    //Jackson + JSON for parsing and (de-)serializing JSON objects
    implementation("org.json:json:20190722")
    implementation("com.fasterxml.jackson.core:jackson-core")
    implementation("com.fasterxml.jackson.core:jackson-databind")
    implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-csv")
    // 404? implementation("com.fasterxml.jackson.module:jackson-modules-java8")

    // Better Streams API than Java
    implementation("org.jooq:jool:0.9.14")

    // Apache commons for many helpful utility classes
    implementation("org.apache.commons:commons-lang3")

    // QueryDSL for providing a DSL based on Entity classes to write database queries
    implementation("com.querydsl:querydsl-jpa")

    // Database migration + database driver dependencies
    implementation("org.liquibase:liquibase-core")
    implementation("com.h2database:h2")
    implementation("mysql:mysql-connector-java")
    implementation("org.mariadb.jdbc:mariadb-java-client")
    implementation("org.postgresql:postgresql")

    // EE XML parsing and deserialization dependencies
    //    implementation("javax.xml.bind", "jaxb-api", "2.3.0")
    //    implementation("org.glassfish.jaxb", "jaxb-runtime", "2.3.0")

    // EE Jakarta
    implementation("com.sun.activation:jakarta.activation")

    // Sentry for writing error logs to a server for developer access
    implementation("io.sentry:sentry-spring-boot-starter:5.1.1")
    implementation("io.sentry:sentry-logback:5.1.1")

    // Flexmark for parsing Markdown into HTML
    implementation("com.vladsch.flexmark:flexmark-all:0.50.42")

    // International Unicode expansion for ordinal strings
    implementation("com.ibm.icu:icu4j:67.1")

    // Dependency for mapping one data class to another
    implementation("org.modelmapper:modelmapper:2.3.6")

    // Webjars to be loaded within HTML resources
    implementation("org.webjars:webjars-locator-core")
    implementation("org.webjars:jquery:3.5.1")
    implementation("org.webjars:jquery-cookie:1.4.1-1")
    implementation("org.webjars:font-awesome:6.4.0")
	implementation("org.webjars:sockjs-client:1.5.1")
    implementation("org.webjars:stomp-websocket:2.3.4")
    implementation("org.webjars:handlebars:4.0.14")
    implementation("org.webjars:chartjs:2.7.0")
    implementation("org.webjars:tempusdominus-bootstrap-4:5.1.2")
    implementation("org.webjars:momentjs:2.24.0")
    implementation("org.webjars:fullcalendar:5.9.0")
	implementation("org.webjars:codemirror:5.62.2")
    implementation("org.webjars.npm:simplemde:1.11.2")


    // Library for converting markdown to html
    implementation("org.commonmark:commonmark:0.18.1")


    /////// Test dependencies ///////
    testImplementation("org.springframework.boot:spring-boot-starter-test")
    testImplementation("org.springframework.security:spring-security-test")

    testImplementation("com.microsoft.playwright:playwright:1.38.0")

    /////// Annotation processing dependencies ///////
    annotationProcessor("javax.annotation:javax.annotation-api")

    annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
    annotationProcessor("org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.2.Final")
	// TODO how to get querydsl.version in here instead of hard coding?
    annotationProcessor("com.querydsl:querydsl-apt:$queryDslVersion:jpa")

    compileOnly("org.projectlombok:lombok")
    testCompileOnly("org.projectlombok:lombok")
    annotationProcessor("org.projectlombok:lombok")
    testAnnotationProcessor("org.projectlombok:lombok")
}

