import com.diffplug.gradle.spotless.SpotlessExtension
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.4.0"

val javaVersion = JavaVersion.VERSION_21

val libradorVersion = "1.4.2-preview"
val labradoorVersion = "1.6.6-local"
val chihuahUIVersion = "1.2.3"
val csvVersion = "5.8"
val guavaVersion = "32.1.3-jre"

// 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")
    }
    maven {
        name = "GitLab TU Delft API repository"
        url = uri("https://gitlab.ewi.tudelft.nl/api/v4/projects/10478/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("3.3.2")
	id("io.spring.dependency-management").version("1.1.4")

	// 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.50.0")

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

	// 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("8.4.3") apply false

    // Sass compiler plugin
	//id("io.freefair.sass-java").version("8.1.0")
    //id("com.unclezs.gradle.sass") version "1.0.10"

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

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 license plugins.
//license {
//    header.set(resources.text.fromFile(file("$rootDir/LICENSE.header")))
	//properties {
	//	year.set(2021)
	//}
//	exclude("**/*.json")
	//"**/*.scss",
	//"**/*.ico",
	//"**/*.png",
	//"**/*.jks",
	//"**/*.css"
//}

// Configure license plugins.
configure<DownloadLicensesExtension> {
    includeProjectDependencies = true
}

configure<LicenseExtension> {
    header = file("$rootDir/LICENSE.header")
    skipExistingHeaders = false

    mapping(mapOf(
        "java" to "SLASHSTAR_STYLE"
    ))

    excludes(listOf(
        "**/*.json",
        "**/static/css/*.css",
        "**/labracore/api/**/*.java"
    ))
}

// 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()
}

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 {
                    executable = "bash"
                    args = listOf("-l", "-c", "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 {
                        executable = "bash"
                        args = listOf("-l", "-c", "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"))
}

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

// 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.*")
    }
}

dependencyManagement {
    imports {
        mavenBom("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom:2.7.0")
    }
}

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

    // Generic Spring Boot starter dependencies
    implementation("org.springframework.boot:spring-boot-starter")
    implementation("org.springframework.boot:spring-boot-starter-aop")
    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")

    // OpenTelemetry
    implementation("io.opentelemetry.instrumentation:opentelemetry-spring-boot-starter")

    // 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")

    // Dependencies for enabling Thymeleaf templating language with Spring.
    implementation("org.springframework.boot:spring-boot-starter-thymeleaf")
    implementation("org.thymeleaf.extras:thymeleaf-extras-springsecurity6")
    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")
    implementation("nl.tudelft.labrador:tudelft-api:0.0.3-local")

    // Java assist dependency
    implementation("org.javassist:javassist:3.29.2-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.70")
    implementation("org.bouncycastle:bcprov-jdk15on:1.70")

    // 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:20231013")
    implementation("com.fasterxml.jackson.core:jackson-core")
    implementation("com.fasterxml.jackson.core:jackson-databind")
    implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-csv")

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

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

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

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

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

    // Webjars to be loaded within HTML resources
    implementation("org.webjars:webjars-locator-core")
    implementation("org.webjars:jquery:3.7.1")
    implementation("org.webjars:jquery-cookie:1.4.1-1")
    implementation("org.webjars:font-awesome:6.4.2")
	implementation("org.webjars:sockjs-client:1.5.1")
    implementation("org.webjars:stomp-websocket:2.3.4")
    implementation("org.webjars:chartjs:4.1.2")
    implementation("org.webjars:handlebars:4.7.7")
    implementation("org.webjars:tempusdominus-bootstrap-4:5.1.2")
    implementation("org.webjars:momentjs:2.24.0")
    implementation("org.webjars:fullcalendar:6.1.9")
	implementation("org.webjars:codemirror:5.62.2")
    implementation("org.webjars.npm:chartjs-adapter-date-fns:3.0.0")

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

	// Open CSV
	implementation("com.opencsv:opencsv:$csvVersion")
	implementation("com.google.guava:guava:$guavaVersion")

    /////// Test dependencies ///////
    testImplementation("org.springframework.boot:spring-boot-starter-test") {
        exclude("junit", "junit")
        exclude("org.junit.vintage", "junit-vintage-engine")
    }
    testImplementation("org.springframework.security:spring-security-test") {
        exclude("junit", "junit")
        exclude("org.junit.vintage", "junit-vintage-engine")
    }

    testImplementation("com.microsoft.playwright:playwright:1.46.0")
    // https://mvnrepository.com/artifact/com.deque.html.axe-core/playwright
    testImplementation("com.deque.html.axe-core:playwright:4.9.1")

    testImplementation("org.testcontainers:testcontainers:1.20.1")
    testImplementation("org.testcontainers:junit-jupiter:1.20.1")

    /////// Annotation processing dependencies ///////
    annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")

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

