/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you 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.
 */
description = 'Fineract Provider'

apply plugin: 'org.zeroturnaround.gradle.jrebel'
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'com.gorylenko.gradle-git-properties'
apply plugin: 'io.swagger.core.v3.swagger-gradle-plugin'
apply plugin: 'com.google.cloud.tools.jib'
apply plugin: 'org.springframework.boot'
apply plugin: 'se.thinkcode.cucumber-runner'

check.dependsOn('cucumber')

// Static weaving is now configured in gradle/static-weaving.gradle
// This ensures consistent configuration across all modules with JPA entities

// Add dependency on avro schemas
compileJava {
    dependsOn ':fineract-avro-schemas:buildJavaSdk'
}

// Configuration for Swagger documentation generation task
// https://github.com/swagger-api/swagger-core/tree/master/modules/swagger-gradle-plugin
import org.apache.tools.ant.filters.ReplaceTokens

tasks.register('prepareInputYaml') {
    outputs.file("${buildDir}/tmp/swagger/fineract-input.yaml")

    doLast {
        copy {
            from file("${projectDir}/config/swagger/fineract-input.yaml.template")
            into file("${buildDir}/tmp/swagger")
            rename { String filename -> return 'fineract-input.yaml' }
            filter(ReplaceTokens, tokens: [VERSION: "${project.version}".toString()])
        }
    }
}

resolve {
    logging.captureStandardOutput LogLevel.INFO
    outputFileName = 'fineract'
    outputFormat = 'JSONANDYAML'
    prettyPrint = false
    classpath = sourceSets.main.runtimeClasspath
    buildClasspath = classpath
    outputDir = file("${buildDir}/resources/main/static")
    openApiFile = file("${buildDir}/tmp/swagger/fineract-input.yaml")
    sortOutput = true
    dependsOn(prepareInputYaml)
}

configurations {
    providedRuntime // needed for Spring Boot executable WAR
    providedCompile
    implementation
    testImplementation
    cucumberRuntime {
        extendsFrom testImplementation
    }
    compile() {
        exclude module: 'hibernate-entitymanager'
        exclude module: 'hibernate-validator'
        exclude module: 'activation'
        exclude module: 'bcmail-jdk14'
        exclude module: 'bcprov-jdk14'
        exclude module: 'bctsp-jdk14'
        exclude module: 'c3p0'
        exclude module: 'stax-api'
        exclude module: 'jaxb-api'
        exclude module: 'jaxb-impl'
        exclude module: 'jboss-logging'
        exclude module: 'itext-rtf'
        exclude module: 'classworlds'
    }
    runtime
}

dependencies {
    implementation project(':fineract-core')
    implementation 'org.springframework.boot:spring-boot-starter-test'
    implementation 'org.mockito:mockito-core'
    implementation 'org.mockito:mockito-junit-jupiter'
    implementation 'org.junit.jupiter:junit-jupiter-api'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.liquibase:liquibase-core'
}

apply from: 'dependencies.gradle'

// Configuration for the modernizer plugin
// https://github.com/andygoossens/gradle-modernizer-plugin
modernizer {
    ignoreClassNamePatterns = [
        '.*AbstractPersistableCustom',
        '.*EntityTables',
        '.*domain.*'
    ]
}

// If we are running Gradle within Eclipse to enhance classes with OpenJPA,
// set the classes directory to point to Eclipse's default build directory
if (project.hasProperty('env') && project.getProperty('env') == 'eclipse') {
    sourceSets.main.java.outputDir = new File(rootProject.projectDir, "fineract-provider/bin/main")
}

eclipse {
    project {
        buildCommand([ LaunchConfigHandle: "<project>/.externalToolBuilders/OpenJPA Enhance Builder.launch" ],  'org.eclipse.ui.externaltools.ExternalToolBuilder')
    }
}

if (!(project.hasProperty('env') && project.getProperty('env') == 'dev')) {
    sourceSets {
        test {
            java {
                exclude '**/core/boot/tests/**'
            }
        }
    }
}

// Configuration for SQL tasks
// https://docs.groovy-lang.org/latest/html/api/groovy/sql/Sql.html
import groovy.sql.Sql

project.ext.mysqlUser='root'
project.ext.mysqlPassword='mysql'
project.ext.pgUser='root'
project.ext.pgPassword='postgres'

configurations {
    driver
}
dependencies {
    driver 'org.mariadb.jdbc:mariadb-java-client'
    driver 'org.postgresql:postgresql'
    driver 'com.mysql:mysql-connector-j'
}

URLClassLoader loader = GroovyObject.class.classLoader
configurations.driver.each {File file ->
    loader.addURL(file.toURL())
}

tasks.register('createDB') {
    description = "Creates the MariaDB Database. Needs database name to be passed (like: -PdbName=someDBname)"
    doLast {
        def sql = Sql.newInstance('jdbc:mariadb://localhost:3306/', mysqlUser, mysqlPassword, 'org.mariadb.jdbc.Driver')
        sql.execute('CREATE DATABASE ' + "`$dbName` CHARACTER SET utf8mb4")
    }
}

tasks.register('dropDB') {
    description = "Drops the specified MariaDB database. The database name has to be passed (like: -PdbName=someDBname)"
    doLast {
        def sql = Sql.newInstance('jdbc:mariadb://localhost:3306/', mysqlUser, mysqlPassword, 'org.mariadb.jdbc.Driver')
        sql.execute('DROP DATABASE ' + "`$dbName`")
    }
}

tasks.register('createPGDB') {
    description = "Creates the PostgreSQL Database. Needs database name to be passed (like: -PdbName=someDBname)"
    doLast {
        def sql = Sql.newInstance('jdbc:postgresql://localhost:5432/', pgUser, pgPassword, 'org.postgresql.Driver')
        sql.execute('create database ' + "$dbName")
    }
}

tasks.register('dropPGDB') {
    description = "Drops the specified PostgreSQL database. The database name has to be passed (like: -PdbName=someDBname)"
    doLast {
        def sql = Sql.newInstance('jdbc:postgresql://localhost:5432/', pgUser, pgPassword, 'org.postgresql.Driver')
        sql.execute('DROP DATABASE ' + "$dbName")
    }
}

tasks.register('createMySQLDB') {
    description = "Creates the MySQL Database. Needs database name to be passed (like: -PdbName=someDBname)"
    doLast {
        def sql = Sql.newInstance('jdbc:mysql://localhost:3306/', mysqlUser, mysqlPassword, 'com.mysql.cj.jdbc.Driver')
        sql.execute('CREATE DATABASE ' + "`$dbName` CHARACTER SET utf8mb4")
    }
}

tasks.register('dropMySQLDB') {
    description = "Drops the specified MySQL database. The database name has to be passed (like: -PdbName=someDBname)"
    doLast {
        def sql = Sql.newInstance('jdbc:mysql://localhost:3306/', mysqlUser, mysqlPassword, 'com.mysql.cj.jdbc.Driver')
        sql.execute('DROP DATABASE ' + "`$dbName`")
    }
}

tasks.register('setBlankPassword') {
    doLast {
        def sql = Sql.newInstance('jdbc:mariadb://localhost:3306/', mysqlUser, mysqlPassword, 'org.mariadb.jdbc.Driver')
        sql.execute('USE `fineract_tenants`')
        sql.execute('UPDATE fineract_tenants.tenants SET schema_server = \'localhost\', schema_server_port = \'3306\', schema_username = \'mifos\', schema_password = \'mysql\' WHERE id=1;')
    }
}

bootRun {
    jvmArgs = [
            "-Dspring.output.ansi.enabled=ALWAYS"
    ]

    dependencies {
        implementation 'org.mariadb.jdbc:mariadb-java-client'
        implementation 'org.postgresql:postgresql'
    }
}

springBoot {
    mainClass = 'org.apache.fineract.ServerApplication'
}

bootJar {
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
    manifest {
        attributes('Main-Class': 'org.springframework.boot.loader.launch.PropertiesLauncher', 'Implementation-Title': 'Apache Fineract', 'Implementation-Version': project.version)
    }
    archiveClassifier = ''
    dependsOn resolve
}

jib {
    from {
        image = 'azul/zulu-openjdk-alpine:21'
        platforms {
            platform {
                architecture = System.getProperty("os.arch").equals("aarch64")?"arm64":"amd64"
                os = 'linux'
            }
        }
    }

    to {
        image = 'fineract'
        tags = [
            "${project.version}",
            'latest'
        ]
    }

    container {
        creationTime = 'USE_CURRENT_TIMESTAMP'
        mainClass = 'org.apache.fineract.ServerApplication'
        extraClasspath = ['/app/plugins/*']
        args = [
            '-Duser.home=/tmp',
            '-Dfile.encoding=UTF-8',
            '-Duser.timezone=UTC',
            '-Djava.security.egd=file:/dev/./urandom'
        ]
        ports = ['8080/tcp', '8443/tcp']
        labels = [maintainer: 'Aleksandar Vidakovic <aleks@apache.org>']
        user = 'nobody:nogroup'
    }

    allowInsecureRegistries = true

    dependencies {
        implementation 'org.mariadb.jdbc:mariadb-java-client'
        implementation 'org.postgresql:postgresql'
    }
}

tasks.register('migrateDatabase') {
    doFirst {
        println 'Executing liquibase database migration to version ' + "$dbVersion"

        def dbUrl = 'jdbc:' + "$dbType" + '://' + "$dbHost" + ':' + "$dbPort" + '/' + "$dbName"
        def changeLogFilePath = 'fineract-provider/src/main/resources/db/changelog/tenant/upgrades/0000_upgrade_to_' + "$dbVersion" + '.xml'

        liquibase {
            activities {
                main {
                    changeLogFile changeLogFilePath
                    url dbUrl
                    username project.ext.mysqlUser
                    password project.ext.mysqlPassword
                }
            }
        }
    }
}

cucumber {
    tags = 'not @ignore'
    main = 'io.cucumber.core.cli.Main'
    shorten = 'argfile'
    plugin = [
        'pretty',
        'html:build/reports/cucumber/report.html',
        'json:build/reports/cucumber/report.json',
        'junit:build/reports/cucumber/report.xml'
    ]
}

tasks.jib.dependsOn(bootJar, resolve)
tasks.jibDockerBuild.dependsOn(bootJar, resolve)

// Configuration for git properties gradle plugin
// https://github.com/n0mer/gradle-git-properties
gitProperties {
    gitPropertiesResourceDir = file("$buildDir/classes/java/main")
    dateFormat = "yyyy-MM-dd'T'HH:mmZ"
    dateFormatTimeZone = "GMT"
    failOnNoGitDirectory = false
}

// make sure the generateGitProperties task always executes (even when git.properties is not changed)
generateGitProperties.outputs.upToDateWhen { false }

// NOTE: Gradle suggested these dependencies
jar.dependsOn resolve
test.dependsOn resolve
checkstyleMain.dependsOn resolve
checkstyleTest.dependsOn resolve
rat.dependsOn prepareInputYaml
spotbugsTest.dependsOn resolve
compileTestJava.dependsOn ':fineract-client:processResources', ':fineract-avro-schemas:processResources'
resolveMainClassName.dependsOn resolve

javadoc {
    dependsOn resolve
}

tasks.register('devRun', org.springframework.boot.gradle.tasks.run.BootRun) {
    description = 'Runs the application quickly for development by skipping quality checks'
    group = 'Application'

    // Configure the build to skip quality checks
    gradle.taskGraph.whenReady { graph ->
        if (graph.hasTask(devRun)) {
            tasks.matching { task ->
                task.name in ['checkstyle', 'checkstyleMain', 'checkstyleTest',
                              'spotlessCheck', 'spotlessApply',
                              'spotbugsMain', 'spotbugsTest',
                              'javadoc', 'javadocJar',
                              'modernizer',
                              'testClasses']
            }.configureEach {
                enabled = false
            }
            // Also disable error prone compilation flags
            tasks.withType(JavaCompile).configureEach {
                options.errorprone.enabled = false
            }
        }
    }

    // Inherit all bootRun settings
    classpath = bootRun.classpath
    mainClass = bootRun.mainClass
    jvmArgs = bootRun.jvmArgs

    doFirst {
        println "Running in development mode - quality checks are disabled"
    }
}
