plugins {
    id 'java'
    id 'application'
}

/*▼ CHANGE PLUGIN VERSION HERE ▼*/
version = '__version__'
/*▲ CHANGE PLUGIN VERSION HERE ▲*/

ext {
    displayNameCustom = project.name.replaceAll('-', ' ').split(' ').collect { it.capitalize() }.join('')
}

def buildDir = layout.buildDirectory.asFile.get()
def javaBuildDir = project(':sources:backend').getLayout().buildDirectory.asFile.get()
def nodeBuildDir = 'sources/frontend/dist'

ext.zipVersion = project.version

def npmBuildCommand = 'build'

ext.gitLabTokenName = project.hasProperty('gitLabTokenName') ? project.getProperty('gitLabTokenName') : 'Private-Token'

repositories {
    mavenCentral()
}

dependencies {
    implementation project(':sources:backend')
}

tasks.register('prepareFiles', Copy) {
    from('sources/resources') {
        exclude '**/.keep', '**/*.iml'
    }

    from('sources/frontend') {
        exclude '**/.keep',
                '**/*.iml',
                '**/dist',
                '**/node_modules',
                '**/package-lock.json',
                '**/package.json',
                '**/README.md',
                '**/*.js',
                '**/src',
                '**/css'

        into 'ui'
    }


    from(nodeBuildDir) { // Add NPM build output directory
        into 'ui/generated' // Adjust the destination directory within the package
    }


    into("${buildDir}/plugin")

    filter { line -> line.replace('%%VERSION%%', project.version) }

    dependsOn 'npmBuild' // Ensure NPM build is completed before copying files
}

tasks.register('npmInstall', Exec) {
    group = 'Ventum Plugin Internal NPM'

    workingDir 'sources/frontend'
    commandLine npmCommand(), 'install'
}

// Utility method to determine the npm command for the OS
static def npmCommand() {
    return isWindows() ? 'npm.cmd' : 'npm'
}

static def isWindows() {
    return System.getProperty('os.name').toLowerCase().contains('win')
}

tasks.register('npmBuild', Exec) {
    group = 'Ventum Plugin Internal NPM'

    workingDir 'sources/frontend'
    commandLine npmCommand(), 'run', npmBuildCommand

    // Run npm install only if node_modules directory is missing
    if (!file('sources/frontend/node_modules').exists()) {
        dependsOn 'npmInstall'
    }
}

jar {
    archiveBaseName.set(displayNameCustom)
    //noinspection GroovyAssignabilityCheck
    archiveVersion.set(project.version)
    destinationDirectory.set(file("${buildDir}/plugin/lib"))

    from("${javaBuildDir}/classes/java/main")

    dependsOn prepareFiles
}

tasks.register('createZip', Zip) {
    dependsOn processResources, prepareFiles, jar
    archiveBaseName.set(displayNameCustom)
    //noinspection GroovyAssignabilityCheck
    archiveVersion.set(zipVersion)
    destinationDirectory.set(file(buildDir))
    from("${buildDir}/plugin")

}

clean {
    group = 'Ventum Plugin Internal'
    doFirst {
        logger.lifecycle("Deleting: ${buildDir}")
        delete file("${buildDir}")
        delete file("${nodeBuildDir}")
    }
}


// Full package task
tasks.register('package') {
    dependsOn 'prepareFiles', 'classes', 'jar', 'createZip'
    group = 'Ventum Plugin Internal'
    description = 'Builds the full package including JAR and ZIP. Obfuscates the JS files. Generates css from scss.'
}

tasks.register('packageDev') {
    //noinspection GrReassignedInClosureLocalVar
    zipVersion = "DEV"
    npmBuildCommand = 'build:dev'


    // Read ./dev/dev.properties file
    def devProperties = new Properties()


    // Check if the file exists, if not, create it

    def devPropertiesFile = 'dev/dev.properties'

    if (file(devPropertiesFile).exists()) {
        devProperties.load(new FileInputStream(file(devPropertiesFile)))
    } else {
        file('dev').mkdirs()
        file(devPropertiesFile).createNewFile()
    }

    def major = devProperties.getProperty('buildmajor', '0')
    def minor = devProperties.getProperty('buildminor', '0')
    def patch = devProperties.getProperty('buildpatch', '1')

    version = "${major}.${minor}.${patch}"

    logger.lifecycle("Preparing DEV package with version: ${version}")

    patch = patch.toInteger() + 1

    devProperties.setProperty('buildpatch', patch.toString())

    // Write ./dev/dev.properties file
    devProperties.store(new FileOutputStream(file(devPropertiesFile)), null)


    dependsOn 'package'
    group = 'Ventum Plugin Internal'
    description = 'Builds the plugin, just like the \'package\'  task. Additionally, with each build, the patch version is incremented. Files are not obfuscated.'
}

// Clean and package task
tasks.register('packageClean') {
    dependsOn 'clean', 'package'
    group = 'Ventum Plugin'
    description = 'Cleans and builds the full package including JAR and ZIP.'
}

// Clean and package task
tasks.register('packageDevClean') {
    dependsOn 'clean', 'packageDev'
    group = 'Ventum Plugin'
    description = 'DEV Cleans and builds the full package including JAR and ZIP.'
}

tasks.register('printVersion') {
    doLast {
        println project.version
    }
}

tasks.register('printZipName') {
    doLast {
        println "${displayNameCustom}-${zipVersion}"
    }
}

tasks.register('printDisplayName') {
    doLast {
        println "${displayNameCustom}"
    }
}

// Custom tasks for SailPoint IdentityIQ plugin upload

import groovy.json.JsonSlurper

// Define the custom Gradle task
class GetAccessToken extends DefaultTask {
    @TaskAction
    void makePostRequest() {

        def iiqUrl = project.findProperty('iiqUrl')

        if (!iiqUrl) {
            throw new RuntimeException("Property 'iiqUrl' is not set. Please provide it in the './gradle.properties'.")
        }

        if (!iiqUrl.endsWith('/')) {
            iiqUrl += '/'
        }

        def url = iiqUrl + 'oauth2/token'

        def connection = new URL(url).openConnection()
        connection.with {
            requestMethod = 'POST'
            doOutput = true
            setRequestProperty('Content-Type', 'application/x-www-form-urlencoded')
            setRequestProperty('Accept', 'application/json')

            def iiqClientId = project.findProperty('iiqClientId')
            def iiqClientSecret = project.findProperty('iiqClientSecret')

            if (!iiqClientId) {
                throw new RuntimeException("Property 'iiqClientId' is not set. Please provide it in the './gradle.properties'.")
            }

            if (!iiqClientSecret) {
                throw new RuntimeException("Property 'iiqClientSecret' is not set. Please provide it in the './gradle.properties'.")
            }

            def iiqCredentials = "${iiqClientId}:${iiqClientSecret}".bytes.encodeBase64().toString()

            setRequestProperty('Authorization', "Basic ${iiqCredentials}")

            def postData = 'grant_type=client_credentials'
            outputStream.withWriter('UTF-8') { writer ->
                writer << postData
            }

            def responseCode = responseCode
            println "Response Code: $responseCode"

            if (responseCode == 200 || responseCode == 201) {
                def responseStream = inputStream
                def responseText = responseStream.text

                def responseJson = new JsonSlurper().parseText(responseText)
                def accessToken = responseJson.access_token

                println "Access Token: $accessToken"
                project.ext.set('accessToken', accessToken) // Store token for use in other tasks
            } else {
                throw new RuntimeException("Request failed with response code $responseCode")
            }
        }


    }
}
// Define the custom Gradle task for file upload
class UploadFileTask extends DefaultTask {
    @TaskAction
    void uploadFile() {
        def zip_name = "${project.displayNameCustom}-${project.zipVersion}"

        def url = project.findProperty('iiqUrl') + '/rest/plugins'
        def accessToken = project.findProperty('accessToken') ?: ''

        if (!accessToken) {
            println "Access token not found. Ensure the 'postRequest' task is executed first."
            return
        }

        def connection = new URL(url).openConnection()
        connection.with {
            requestMethod = 'POST'
            doOutput = true
            setRequestProperty('Accept', 'application/json, text/plain, */*')
            setRequestProperty('Authorization', "Bearer $accessToken")

            def boundary = "Boundary-${System.currentTimeMillis()}"
            setRequestProperty('Content-Type', "multipart/form-data; boundary=$boundary")

            def output = outputStream
            output.withWriter('UTF-8') { writer ->

                writer.write("--$boundary\r\n")
                writer.write("Content-Disposition: form-data; name=\"file\"; filename=\"${zip_name}.zip\"\r\n")
                writer.write("Content-Type: application/zip\r\n\r\n")
                writer.flush()


                new File("build/${zip_name}.zip").withInputStream { input ->
                    output << input
                }
                output.flush()

                writer.write("\r\n--$boundary\r\n")
                writer.write("Content-Disposition: form-data; name=\"fileName\"\r\n\r\n")
                writer.write("${zip_name}.zip\r\n")
                writer.write("--$boundary--\r\n")
            }

            def responseCode = responseCode
            println "Response Code: $responseCode"

            if (responseCode == 200 || responseCode == 201) {
                def responseStream = inputStream
                def responseText = responseStream.text

                println "Response Body: $responseText"
            } else {
                println "Request failed with response code $responseCode"
            }
        }
    }
}

// Add the custom task to the project
tasks.register('getAccessToken', GetAccessToken) {
    dependsOn 'packageDevClean'
}
tasks.register('buildAndUploadPlugin', UploadFileTask) {
    group = 'Ventum Plugin'

    dependsOn 'getAccessToken'
}
