/*
 * Copyright (c) 2022 Ford Motor Company
 * All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

plugins {
    id 'java'
    id 'org.springframework.boot' version '2.6.4'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'jacoco'
    id 'org.gradle.test-retry' version '1.2.1'
    id 'com.avast.gradle.docker-compose' version '0.14.3'
    id "rkennel.withdb" version "1.0.6"
    id 'com.github.ben-manes.versions'
}

group = 'com.ford.labs'
archivesBaseName = 'retroquest'

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

repositories {
    mavenCentral()
}

ext {
    set('springCloudVersion', "2021.0.1")
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
    }
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-websocket'
    implementation 'org.springframework.boot:spring-boot-starter-validation'
    implementation 'org.springframework.boot:spring-boot-starter-mail'
    implementation 'org.springframework.cloud:spring-cloud-starter-bootstrap'
    implementation 'org.springframework.cloud:spring-cloud-starter-config'

    implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
    implementation 'commons-io:commons-io:2.9.0'
    implementation 'io.jsonwebtoken:jjwt:0.9.1'
    implementation 'io.micrometer:micrometer-registry-statsd'
    implementation 'org.apache.commons:commons-csv:1.8'
    implementation 'org.apache.commons:commons-lang3:3.12.0'
    implementation 'org.apache.httpcomponents:httpclient:4.5.13'
    implementation 'org.liquibase:liquibase-core:4.8.0'
    implementation 'org.springdoc:springdoc-openapi-ui:1.7.0'

    // https://mvnrepository.com/artifact/com.google.code.findbugs/jsr305
    compileOnly 'com.google.code.findbugs:jsr305:3.0.2'

    compileOnly "org.projectlombok:lombok:${lombokVersion}"
    annotationProcessor "org.projectlombok:lombok:${lombokVersion}"

    testImplementation 'com.h2database:h2:1.4.200'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework.security:spring-security-test'

    developmentOnly 'org.springframework.boot:spring-boot-devtools'

    runtimeOnly 'org.postgresql:postgresql:42.4.3'
}

static def noProfileOrDbDefined(tasks) {

    def envProfile = System.getenv("SPRING_PROFILES_ACTIVE")
    def systemProfile = System.getProperty("spring.profiles.active")

    if (envProfile != null || systemProfile != null) {
        return false
    }

    boolean dbDeclared = false
    tasks.forEach { task ->
        if (task.name.contains('with')) {
            dbDeclared = true
        }
    }

    if (dbDeclared) {
        return false
    }

    return true

}

bootRun {
    sourceResources sourceSets.main

    gradle.taskGraph.whenReady { graph ->

        if (noProfileOrDbDefined(graph.getAllTasks())) {
            logger.lifecycle('>>> Setting spring.profiles.active == "local" <<<')
            bootRun {
                dependencies {
                    implementation 'com.h2database:h2:1.4.200'
                }
                System.setProperty("spring.profiles.active", "local")
                systemProperties System.properties
            }
        }
    }
}

task bootRunDockerDb(type: Exec) {
    dependsOn 'withPostgres'
    dependsOn 'bootRun'

    tasks.findByName('bootRun').mustRunAfter 'withPostgres'

    group 'Application'
    description 'Runs this project as a Spring Boot application using containerized database'

    gradle.taskGraph.whenReady { graph ->
        if (graph.hasTask(bootRunDockerDb)) {
            logger.lifecycle('>>> Setting spring.profiles.active == "dockerdb" <<<')
            bootRun {
                systemProperty "spring.profiles.active", "dockerdb"
            }
        }
    }
}

test {
    useJUnitPlatform {
        excludeTags 'api'
        maxParallelForks = (int) (Runtime.getRuntime().availableProcessors() / 2)
    }
}

task apiTest(type: Test) {
    group 'Verification'
    description 'Runs API Tests against h2 database'
    testLogging.exceptionFormat = 'full'
    useJUnitPlatform {
        includeTags 'api'
        maxParallelForks = (int) (Runtime.getRuntime().availableProcessors() / 2)
    }
}

task apiTestDockerDb(type: Test) {
    dependsOn 'composeUp'
    dependsOn 'withPostgres'
    dependsOn 'apiTest'
    finalizedBy 'composeDown'

    tasks.findByName('withPostgres').mustRunAfter 'composeUp'
    tasks.findByName('apiTest').mustRunAfter 'withPostgres'

    group 'Verification'
    description 'Runs API Tests against docker database'

    gradle.taskGraph.whenReady { graph ->
        if (graph.hasTask(apiTestDockerDb)) {
            logger.lifecycle('>>> Setting spring.profiles.active == "dockerdb" <<<')
            systemProperty "spring.profiles.active", "dockerdb"
        }
    }
}

dockerCompose {
    useComposeFiles = ['docker-compose.yml']
    waitForTcpPorts = true
}

jacoco {
    toolVersion = '0.8.7'
}

jacocoTestReport {
    executionData.setFrom(fileTree("${project.buildDir}/jacoco").include("*.exec"))
    reports {
        xml.enabled true
        xml.destination file("${project.buildDir}/jacoco-xml/jacoco.xml")
        html.destination file("${project.buildDir}/jacoco-html")
    }
}

tasks.withType(Test) {
    retry {
        maxRetries = 3
        maxFailures = 1
        failOnPassedAfterRetry = false
    }
    finalizedBy('jacocoTestReport')
}
