plugins {
    id "java"
    id "org.springframework.boot" version "3.4.5"
    id "io.spring.dependency-management" version "1.1.7"
    id "org.springdoc.openapi-gradle-plugin" version "1.9.0"
    id "io.swagger.swaggerhub" version "1.3.2"
    id "edu.sc.seis.launch4j" version "3.0.6"
    id "com.diffplug.spotless" version "7.0.3"
    id "com.github.jk1.dependency-license-report" version "2.9"
    //id "nebula.lint" version "19.0.3"
    id("org.panteleyev.jpackageplugin") version "1.6.1"
    id "org.sonarqube" version "6.1.0.5360"
}

import com.github.jk1.license.render.*
import org.gradle.internal.os.OperatingSystem
import java.nio.file.Files
import java.time.Year

ext {
    springBootVersion = "3.4.5"
    pdfboxVersion = "3.0.5"
    imageioVersion = "3.12.0"
    lombokVersion = "1.18.38"
    bouncycastleVersion = "1.80"
    springSecuritySamlVersion = "6.4.5"
    openSamlVersion = "4.3.2"
    commonmarkVersion = "0.24.0"
    tempJrePath = null
}

// todo: package jar with option for enterprise features to be included
jar {
    enabled = false
    manifest {
        attributes "Implementation-Title": "Stirling-PDF",
            "Implementation-Version": project.version
    }
}

bootJar {
    enabled = false
}

allprojects {
    group = "stirling.software"
    version = "0.46.1"

    afterEvaluate {
        if (project == rootProject) return
        tasks.register('wrapper', Wrapper) {
            gradleVersion = '8.14'
            distributionType = Wrapper.DistributionType.ALL
        }
    }
}

subprojects {
    apply plugin: 'java'
    apply plugin: 'com.diffplug.spotless'
    apply plugin: 'org.springframework.boot'
    apply plugin: 'io.spring.dependency-management'



    java {
        // 17 is lowest but we support and recommend 21
        sourceCompatibility = JavaVersion.VERSION_17
    }

    repositories {
        mavenCentral()
    }

    configurations.configureEach {
        exclude group: 'commons-logging', module: 'commons-logging'
        exclude group: "org.springframework.boot", module: "spring-boot-starter-tomcat"
        // Exclude vulnerable BouncyCastle version used in tableau
        exclude group: 'org.bouncycastle', module: 'bcpkix-jdk15on'
        exclude group: 'org.bouncycastle', module: 'bcutil-jdk15on'
        exclude group: 'org.bouncycastle', module: 'bcmail-jdk15on'
    }

    dependencyManagement {
        imports {
            mavenBom "org.springframework.boot:spring-boot-dependencies:$springBootVersion"
        }
    }

    dependencies {
        implementation 'org.springframework.boot:spring-boot-starter-web'
        implementation 'org.springframework.boot:spring-boot-starter-actuator'
        implementation 'io.github.pixee:java-security-toolkit:1.2.1'

        //tmp for security bumps
        implementation 'ch.qos.logback:logback-core:1.5.18'
        implementation 'ch.qos.logback:logback-classic:1.5.18'
        compileOnly "org.projectlombok:lombok:$lombokVersion"
        annotationProcessor "org.projectlombok:lombok:$lombokVersion"

        testImplementation 'org.springframework.boot:spring-boot-starter-test'
        testRuntimeOnly 'org.mockito:mockito-inline:5.2.0'
    }

    tasks.withType(JavaCompile).configureEach {
        options.encoding = "UTF-8"
        dependsOn "spotlessApply"
    }

    compileJava {
        options.compilerArgs << "-parameters"
    }

    test {
        useJUnitPlatform()
    }
}

licenseReport {
    renderers = [new JsonReportRenderer()]
    allowedLicensesFile = new File("$projectDir/allowed-licenses.json")
}

// todo: test if needed here
sourceSets {
    main {
        java {
            if (System.getenv("ADDITIONAL_FEATURES") == "false") {
                exclude 'stirling/software/proprietary/security/controller/**'
                exclude 'stirling/software/proprietary/security/model/ApiKeyAuthenticationToken.java'
                exclude 'stirling/software/proprietary/security/model/AttemptCounter.java'
                exclude 'stirling/software/proprietary/security/model/Authority.java'
                exclude 'stirling/software/proprietary/security/model/BackupNotFoundException.java'
                exclude 'stirling/software/proprietary/security/model/PersistentLogin.java'
                exclude 'stirling/software/proprietary/security/model/SessionEntity.java'
                exclude 'stirling/software/proprietary/security/model/User.java'
                exclude 'stirling/software/proprietary/security/database/repository/**'
            }

            if (System.getenv("STIRLING_PDF_DESKTOP_UI") == "false") {
                exclude "stirling/software/spdf/UI/impl/**"
            }

        }
    }

    test {
        java {
            if (System.getenv("DOCKER_ENABLE_SECURITY") == "false") {
                exclude "stirling/software/spdf/config/security/**"
                exclude "stirling/software/spdf/model/ApiKeyAuthenticationTokenTest.java"
                exclude "stirling/software/spdf/controller/api/EmailControllerTest.java"
                exclude "stirling/software/spdf/repository/**"
            }

            if (System.getenv("STIRLING_PDF_DESKTOP_UI") == "false") {
                exclude "stirling/software/spdf/UI/impl/**"
            }
        }
    }
}

openApi {
    apiDocsUrl = "http://localhost:8080/v1/api-docs"
    outputDir = file("$projectDir")
    outputFileName = "SwaggerDoc.json"
    waitTimeInSeconds = 60 // Increase the wait time to 60 seconds
}

//0.11.5 to 2024.11.5
static def getMacVersion(String version) {
    def currentYear = Year.now().getValue()
    def versionParts = version.split("\\.", 2)
    return "${currentYear}.${versionParts.length > 1 ? versionParts[1] : versionParts[0]}"
}

jpackage {
    input = "build/libs"
    destination = "${projectDir}/build/jpackage"
    mainJar = "Stirling-PDF-${project.version}.jar"
    appName = "Stirling PDF"
    appVersion = project.version
    vendor = "Stirling PDF Inc"
    appDescription = "Stirling PDF - Your Local PDF Editor"
    icon = "src/main/resources/static/favicon.ico"
    verbose = true
//    mainClass = "org.springframework.boot.loader.launch.JarLauncher"

    // JVM Options
    javaOptions = [
        "-DBROWSER_OPEN=true",
        "-DSTIRLING_PDF_DESKTOP_UI=true",
        "-Djava.awt.headless=false",
        "-Dapple.awt.UIElement=true",
        "--add-opens=java.base/java.lang=ALL-UNNAMED",
        "--add-opens=java.desktop/java.awt.event=ALL-UNNAMED",
        "--add-opens=java.desktop/sun.awt=ALL-UNNAMED",
        "--add-opens=java.desktop/sun.awt.X11=ALL-UNNAMED",
        "--add-opens=java.desktop/sun.awt.windows=ALL-UNNAMED",
        "--add-opens=java.desktop/sun.lwawt=ALL-UNNAMED",
        "--add-opens=java.desktop/sun.lwawt.macosx=ALL-UNNAMED",
    ]

    // Windows-specific configuration
    windows {
        launcherAsService = false
        appVersion = project.version

        winConsole = false
        winMenu = true  // Creates start menu entry
        winShortcut = true  // Creates desktop shortcut
        winShortcutPrompt = true  // Lets user choose whether to create shortcuts
        winDirChooser = true  // Allows users to choose installation directory
        winPerUserInstall = false
        winMenuGroup = "Stirling PDF"
        winUpgradeUuid = "2a43ed0c-b8c2-40cf-89e1-751129b87641" // Unique identifier for updates
        winHelpUrl = "https://github.com/Stirling-Tools/Stirling-PDF"
        winUpdateUrl = "https://github.com/Stirling-Tools/Stirling-PDF/releases"
        type = "exe"
        installDir = "C:/Program Files/Stirling-PDF"
    }

    // MacOS-specific configuration
    mac {
        appVersion = getMacVersion(project.version.toString())
        icon = "src/main/resources/static/favicon.icns"
        type = "dmg"
        macPackageIdentifier = "Stirling PDF"
        macPackageName = "Stirling PDF"
        macAppCategory = "public.app-category.productivity"
        macSign = false // Enable signing
        macAppStore = false // Not targeting App Store initially

//        // Add license and other documentation to DMG
//        /*macDmgContent = [
//            "README.md",
//            "LICENSE",
//            "CHANGELOG.md"
//        ]*/
//
//        // Enable Mac-specific entitlements
//        //macEntitlements = "entitlements.plist" // You'll need to create this file
    }

    // Linux-specific configuration
    linux {
        appVersion = project.version
        icon = "src/main/resources/static/favicon.png"
        type = "deb" // Can also use "rpm" for Red Hat-based systems

        // Debian package configuration
        //linuxPackageName = "stirlingpdf"
        linuxDebMaintainer = "support@stirlingpdf.com"
        linuxMenuGroup = "Office;PDF;Productivity"
        linuxAppCategory = "Office"
        linuxAppRelease = "1"
        linuxPackageDeps = true

        installDir = "/opt/Stirling-PDF"

        // RPM-specific settings
        //linuxRpmLicenseType = "MIT"
    }

    // Common additional options
    //jLinkOptions = [
    //    "--strip-debug",
    //    "--compress=2",
    //    "--no-header-files",
    //    "--no-man-pages"
    //]

    // Add any additional modules required
    /*addModules = [
        "java.base",
        "java.desktop",
        "java.logging",
        "java.sql",
        "java.xml",
        "jdk.crypto.ec"
    ]*/

    // Add copyright and license information
    copyright = "Copyright © 2024 Stirling Software"
    licenseFile = "LICENSE"
}

tasks.wrapper {
    gradleVersion = "8.14"
    distributionType = Wrapper.DistributionType.ALL
}

tasks.register('jpackageMacX64') {
    group = 'distribution'
    description = 'Packages app for MacOS x86_64'

    println "Running jpackageMacX64 task"

    if (OperatingSystem.current().isMacOsX()) {
        println "MacOS detected. Downloading temp JRE."
        dependsOn("downloadTempJre")
    } else {
        return
    }

    doLast {
        def jrePath = project.ext.tempJrePath

        if (!jrePath) {
            throw new GradleException("JRE path not found.")
        }

        def outputStream = new ByteArrayOutputStream()
        def errorStream = new ByteArrayOutputStream()

        def result = exec {
            commandLine 'jpackage',
                '--type', 'dmg',
                '--name', 'Stirling PDF (x86_64)',
                '--input', 'build/libs',
                '--main-jar', "Stirling-PDF-${project.version}.jar",
                '--main-class', 'org.springframework.boot.loader.launch.JarLauncher',
                '--runtime-image', file(jrePath + "/zulu-17.jre/Contents/Home"),
                '--dest', 'build/jpackage/x86_64',
                '--icon', 'src/main/resources/static/favicon.icns',
                '--app-version', getMacVersion(project.version.toString()),
                '--mac-package-name', 'Stirling PDF (x86_64)',
                '--mac-package-identifier', 'Stirling PDF (x86_64)',
                '--mac-app-category', 'public.app-category.productivity',

                // Java options
                '--java-options', '-DBROWSER_OPEN=true',
                '--java-options', '-DSTIRLING_PDF_DESKTOP_UI=true',
                '--java-options', '-Djava.awt.headless=false',
                '--java-options', '-Dapple.awt.UIElement=true',
                '--java-options', '--add-opens=java.base/java.lang=ALL-UNNAMED',
                '--java-options', '--add-opens=java.desktop/java.awt.event=ALL-UNNAMED',
                '--java-options', '--add-opens=java.desktop/sun.awt=ALL-UNNAMED',
                '--java-options', '--add-opens=java.desktop/sun.awt.X11=ALL-UNNAMED',
                '--java-options', '--add-opens=java.desktop/sun.awt.windows=ALL-UNNAMED',
                '--java-options', '--add-opens=java.desktop/sun.lwawt=ALL-UNNAMED',
                '--java-options', '--add-opens=java.desktop/sun.lwawt.macosx=ALL-UNNAMED'

            standardOutput = outputStream
            errorOutput = errorStream
            ignoreExitValue = true
        }

        def stdout = outputStream.toString("UTF-8")
        def stderr = errorStream.toString("UTF-8")

        if (!stdout.isBlank()) {
            println "jpackage stdout:\n$stdout"
        }

        if (result.exitValue != 0) {
            throw new GradleException("jpackage failed with exit code ${result.exitValue}.\n\n$stderr")
        }
    }
}

tasks.register('downloadTempJre') {
    group = 'distribution'
    description = 'Downloads and extracts a temporary JRE'

    doLast {
        try {
            def jreUrl = 'https://cdn.azul.com/zulu/bin/zulu17.56.15-ca-jre17.0.14-macosx_x64.tar.gz'
            def tmpDir = Files.createTempDirectory('zulu-jre').toFile()
            def jreArchive = new File(tmpDir, 'jre.tar.gz')
            def jreDir = new File(tmpDir, 'jre')

            println "🔽 Downloading JRE to $jreArchive..."
            jreArchive.withOutputStream { out ->
                new URI(jreUrl).toURL().withInputStream { from -> out << from }
            }

            println "📦 Extracting JRE to $jreDir..."
            jreDir.mkdirs()
            providers.exec {
                commandLine 'tar', '-xzf', jreArchive.absolutePath, '-C', jreDir.absolutePath, '--strip-components=1'
            }.result.get()

            println "✅ JRE ready at: $jreDir"
            ext.tempJrePath = jreDir.absolutePath
            project.ext.tempJrePath = jreDir.absolutePath
        } catch (Exception e) {
            println "Failed to download JRE. ${e.getLocalizedMessage()}"
            cleanTempJre
        }
    }
}

tasks.register('cleanTempJre') {
    dependsOn('jpackageMacX64')
    group = 'distribution'
    description = 'Deletes the temporary JRE'

    doLast {
        def path = project.ext.tempJrePath

        if (path && new File("$path").exists()) {
            println "Cleaning up temporary JRE: $path"
            new File("$path").parentFile.deleteDir()
        }
    }
}

launch4j {
    icon = "${projectDir}/src/main/resources/static/favicon.ico"

    outfile="Stirling-PDF.exe"

    if(System.getenv("STIRLING_PDF_DESKTOP_UI") == 'true') {
        headerType = "gui"
    } else {
        headerType = "console"
    }
    jarTask = tasks.bootJar

    errTitle="Encountered error, do you have Java 21?"
    downloadUrl="https://download.oracle.com/java/21/latest/jdk-21_windows-x64_bin.exe"

    if(System.getenv("STIRLING_PDF_DESKTOP_UI") == 'true') {
        variables=["BROWSER_OPEN=true", "STIRLING_PDF_DESKTOP_UI=true"]
    } else {
        variables=["BROWSER_OPEN=true"]
    }

    jreMinVersion="17"

    mutexName="Stirling-PDF"
    windowTitle="Stirling-PDF"

    messagesStartupError="An error occurred while starting Stirling-PDF"
    // messagesJreNotFoundError="This application requires a Java Runtime Environment, Please download Java 17."
    messagesJreVersionError="You are running the wrong version of Java, Please download Java 21."
    messagesLauncherError="Java is corrupted. Please uninstall and then install  Java 21."
    messagesInstanceAlreadyExists="Stirling-PDF is already running."
}

spotless {
    java {
        target project.fileTree('src').include('**/*.java')

        googleJavaFormat("1.26.0").aosp().reorderImports(false)

        importOrder("java", "javax", "org", "com", "net", "io", "jakarta", "lombok", "me", "stirling")
        toggleOffOn()
        trimTrailingWhitespace()
        leadingTabsToSpaces()
        endWithNewline()
    }
}

sonar {
    properties {
        property "sonar.projectKey", "Stirling-Tools_Stirling-PDF"
        property "sonar.organization", "stirling-tools"

        property "sonar.exclusions", "**/build-wrapper-dump.json, src/main/java/org/apache/**, src/main/resources/static/pdfjs/**, src/main/resources/static/pdfjs-legacy/**, src/main/resources/static/js/thirdParty/**"
        property "sonar.coverage.exclusions", "src/main/java/org/apache/**, src/main/resources/static/pdfjs/**, src/main/resources/static/pdfjs-legacy/**, src/main/resources/static/js/thirdParty/**"
        property "sonar.cpd.exclusions", "src/main/java/org/apache/**, src/main/resources/static/pdfjs/**, src/main/resources/static/pdfjs-legacy/**, src/main/resources/static/js/thirdParty/**"
    }
}

swaggerhubUpload {
    // dependsOn = generateOpenApiDocs  // Depends on your task generating Swagger docs
    api = "Stirling-PDF"  // The name of your API on SwaggerHub
    owner = "${System.getenv().getOrDefault('SWAGGERHUB_USER', 'Frooodle')}"  // Your SwaggerHub username (or organization name)
    version = project.version  // The version of your API
    inputFile = file("SwaggerDoc.json")  // The path to your Swagger docs
    token = "${System.getenv("SWAGGERHUB_API_KEY")}"  // Your SwaggerHub API key, passed as an environment variable
    oas = "3.0.0"  // The version of the OpenAPI Specification you"re using
}

tasks.named("test") {
    useJUnitPlatform()
}

tasks.register('writeVersion') {
    def propsFile = file("$projectDir/stirling-pdf/src/main/resources/version.properties")
    def propsDir = propsFile.parentFile

    doLast {
        if (propsDir.exists()) {
            if (propsFile.exists()) {
                println "File exists: $propsFile"
            } else {
                println "$propsFile does not exist. Creating file."
                propsFile.createNewFile()
            }
        } else {
            println "Creating directory: $propsDir"
            propsDir.mkdirs()
            propsFile.createNewFile()
        }

        def props = new Properties()
        props.setProperty("version", version)
        props.store(propsFile.newWriter(), null)
    }
}

processResources.dependsOn(writeVersion)

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

tasks.register('printMacVersion') {
    doLast {
        println getMacVersion(project.version.toString())
    }
}

tasks.named('generateOpenApiDocs') {
    doNotTrackState("Tracking state is not supported for this task")
}