apply plugin: 'org.springframework.boot'

import org.apache.tools.ant.taskdefs.condition.Os

repositories {
    maven { url = 'https://build.shibboleth.net/maven/releases' }
    maven { url = 'https://maven.pkg.github.com/jcefmaven/jcefmaven' }
}

configurations {
    developmentOnly
    runtimeClasspath {
        extendsFrom developmentOnly
    }
}

spotless {
    java {
        target 'src/**/java/**/*.java'
        targetExclude 'src/main/resources/static/**'
        googleJavaFormat(googleJavaFormatVersion).aosp().reorderImports(false)

        importOrder("java", "javax", "org", "com", "net", "io", "jakarta", "lombok", "me", "stirling")
        toggleOffOn()
        trimTrailingWhitespace()
        leadingTabsToSpaces()
        endWithNewline()
    }
    yaml {
        target '**/*.yml', '**/*.yaml'
        targetExclude 'src/main/resources/static/**'
        trimTrailingWhitespace()
        leadingTabsToSpaces()
        endWithNewline()
    }
    format 'gradle', {
        target '**/gradle/*.gradle', '**/*.gradle'
        targetExclude 'src/main/resources/static/**'
        trimTrailingWhitespace()
        leadingTabsToSpaces()
        endWithNewline()
    }
}

dependencies {
    if (System.getenv('STIRLING_PDF_DESKTOP_UI') != 'false'
        || (project.hasProperty('STIRLING_PDF_DESKTOP_UI')
        && project.getProperty('STIRLING_PDF_DESKTOP_UI') != 'false')) {
        implementation 'org.openjfx:javafx-controls:21'
        implementation 'org.openjfx:javafx-swing:21'
    }

    if (System.getenv('DISABLE_ADDITIONAL_FEATURES') != 'true'
        || (project.hasProperty('DISABLE_ADDITIONAL_FEATURES')
        && System.getProperty('DISABLE_ADDITIONAL_FEATURES') != 'true')) {
        implementation project(':proprietary')
    }

    implementation project(':common')
    implementation 'org.springframework.boot:spring-boot-starter-jetty'
    implementation 'com.posthog.java:posthog:1.2.0'
    implementation 'org.telegram:telegrambots:6.9.7.1'
    implementation 'commons-io:commons-io:2.21.0'
    implementation "org.bouncycastle:bcprov-jdk18on:$bouncycastleVersion"
    implementation "org.bouncycastle:bcpkix-jdk18on:$bouncycastleVersion"
    implementation 'io.micrometer:micrometer-core:1.16.1'
    implementation 'com.google.zxing:core:3.5.4'
    implementation "org.commonmark:commonmark:$commonmarkVersion" // https://mvnrepository.com/artifact/org.commonmark/commonmark
    implementation "org.commonmark:commonmark-ext-gfm-tables:$commonmarkVersion"

    // General PDF dependencies
    implementation "org.apache.pdfbox:preflight:$pdfboxVersion"
    implementation "org.apache.pdfbox:xmpbox:$pdfboxVersion"

    implementation 'org.verapdf:validation-model:1.28.2'

    // veraPDF still uses javax.xml.bind, not the new jakarta namespace
    implementation 'javax.xml.bind:jaxb-api:2.3.1'
    implementation 'com.sun.xml.bind:jaxb-impl:2.3.9'
    implementation 'com.sun.xml.bind:jaxb-core:2.3.0.1'

    // https://mvnrepository.com/artifact/technology.tabula/tabula
    implementation ('technology.tabula:tabula:1.0.5')  {
        exclude group: 'org.slf4j', module: 'slf4j-simple'
        exclude group: 'org.bouncycastle', module: 'bcprov-jdk15on'
        exclude group: 'com.google.code.gson', module: 'gson'
    }
    implementation 'org.apache.pdfbox:jbig2-imageio:3.0.4'
    implementation 'com.opencsv:opencsv:5.12.0' // https://mvnrepository.com/artifact/com.opencsv/opencsv

    // Batik
    implementation 'org.apache.xmlgraphics:batik-all:1.19'

    // TwelveMonkeys
    runtimeOnly "com.twelvemonkeys.imageio:imageio-batik:$imageioVersion"
    runtimeOnly "com.twelvemonkeys.imageio:imageio-bmp:$imageioVersion"
    runtimeOnly "com.twelvemonkeys.imageio:imageio-jpeg:$imageioVersion"
    runtimeOnly "com.twelvemonkeys.imageio:imageio-tiff:$imageioVersion"
    runtimeOnly "com.twelvemonkeys.imageio:imageio-webp:$imageioVersion"
    // runtimeOnly "com.twelvemonkeys.imageio:imageio-hdr:$imageioVersion"
    // runtimeOnly "com.twelvemonkeys.imageio:imageio-icns:$imageioVersion"
    // runtimeOnly "com.twelvemonkeys.imageio:imageio-iff:$imageioVersion"
    // runtimeOnly "com.twelvemonkeys.imageio:imageio-pcx:$imageioVersion@
    // runtimeOnly "com.twelvemonkeys.imageio:imageio-pict:$imageioVersion"
    // runtimeOnly "com.twelvemonkeys.imageio:imageio-pnm:$imageioVersion"
    runtimeOnly "com.twelvemonkeys.imageio:imageio-psd:$imageioVersion"
    // runtimeOnly "com.twelvemonkeys.imageio:imageio-sgi:$imageioVersion"
    // runtimeOnly "com.twelvemonkeys.imageio:imageio-tga:$imageioVersion"
    // runtimeOnly "com.twelvemonkeys.imageio:imageio-thumbsdb:$imageioVersion"
    // runtimeOnly "com.twelvemonkeys.imageio:imageio-xwd:$imageioVersion"

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

sourceSets {
    main {
        resources {
            srcDirs += ['../configs']
        }
        java {
            if (System.getenv('STIRLING_PDF_DESKTOP_UI') == 'false') {
                exclude 'stirling/software/SPDF/UI/impl/**'
            }

        }
    }
    test {
        java {
            if (System.getenv('STIRLING_PDF_DESKTOP_UI') == 'false') {
                exclude 'stirling/software/SPDF/UI/impl/**'
            }
        }
    }

}


// Disable regular jar
jar {
    enabled = false
}

// Configure and enable bootJar for this project
bootJar {
    enabled = true
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
    zip64 = true

    // Don't include all dependencies directly like the old jar task did
    // from {
    //     configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
    // }

    // Exclude signature files to prevent "Invalid signature file digest" errors
    exclude 'META-INF/*.SF'
    exclude 'META-INF/*.DSA'
    exclude 'META-INF/*.RSA'
    exclude 'META-INF/*.EC'

    manifest {
        attributes(
            'Implementation-Title': 'Stirling-PDF',
            'Implementation-Version': project.version
        )
    }
}

// Configure main class for Spring Boot
springBoot {
    mainClass = 'stirling.software.SPDF.SPDFApplication'
}

// Frontend build tasks - only enabled with -PbuildWithFrontend=true
def buildWithFrontend = project.hasProperty('buildWithFrontend') && project.property('buildWithFrontend') == 'true'
def frontendDir = file('../../frontend')
def frontendDistDir = file('../../frontend/dist')
def resourcesStaticDir = file('src/main/resources/static')
def generatedFrontendPaths = [
    'assets',
    'index.html',
    'locales',
    'Login',
    'classic-logo',
    'modern-logo',
    'og_images',
    'samples',
    'manifest-classic.json'
]

tasks.register('npmInstall', Exec) {
    enabled = buildWithFrontend
    group = 'frontend'
    description = 'Install frontend dependencies'
    workingDir frontendDir
    commandLine = Os.isFamily(Os.FAMILY_WINDOWS) ? ['cmd', '/c', 'npm', 'ci', '--prefer-offline'] : ['npm', 'ci', '--prefer-offline']
    inputs.file(new File(frontendDir, 'package.json'))
    inputs.file(new File(frontendDir, 'package-lock.json'))
    outputs.dir(new File(frontendDir, 'node_modules'))

    // Show live output
    standardOutput = System.out
    errorOutput = System.err

    // Skip if node_modules exists and is up-to-date
    onlyIf {
        def nodeModules = new File(frontendDir, 'node_modules')
        if (!nodeModules.exists()) {
            println "node_modules not found, will install..."
            return true
        }

        // if required devDependency is missing, reinstall
        def iconifyPkg = new File(frontendDir, 'node_modules/@iconify-json/material-symbols/package.json')
        if (!iconifyPkg.exists()) {
            println "@iconify-json/material-symbols missing, will reinstall..."
            return true
        }

        def packageJson = new File(frontendDir, 'package.json')
        def packageLock = new File(frontendDir, 'package-lock.json')
        def isOutdated = nodeModules.lastModified() < packageJson.lastModified() ||
                        nodeModules.lastModified() < packageLock.lastModified()
        if (isOutdated) {
            println "package.json or package-lock.json changed, will reinstall..."
        } else {
            println "node_modules is up-to-date, skipping npm install"
        }
        return isOutdated
    }

    doFirst {
        println "Installing npm dependencies in ${frontendDir}..."
    }
}

tasks.register('npmBuild', Exec) {
    enabled = buildWithFrontend
    group = 'frontend'
    description = 'Build frontend application'
    workingDir frontendDir
    commandLine = Os.isFamily(Os.FAMILY_WINDOWS) ? ['cmd', '/c', 'npm', 'run', 'build'] : ['npm', 'run', 'build']
    dependsOn npmInstall
    inputs.dir(new File(frontendDir, 'src'))
    inputs.file(new File(frontendDir, 'package.json'))
    outputs.dir(frontendDistDir)

    // Show live output
    standardOutput = System.out
    errorOutput = System.err

    // Override VITE_API_BASE_URL to use relative paths for production builds
    // This ensures JARs work regardless of how they're deployed (direct, proxied, etc.)
    environment 'VITE_API_BASE_URL', '/'

    doFirst {
        println "Building frontend application for production (VITE_API_BASE_URL=/)"
    }
}

tasks.register('copyFrontendAssets', Copy) {
    enabled = buildWithFrontend
    group = 'frontend'
    description = 'Copy frontend build to static resources'
    dependsOn npmBuild
    from(frontendDistDir) {
        // Exclude files that conflict with backend static resources
        exclude 'robots.txt'  // Backend already has this
        exclude 'favicon.ico' // Backend already has this
    }
    into resourcesStaticDir
    duplicatesStrategy = DuplicatesStrategy.INCLUDE  // Let frontend overwrite when needed
    doFirst {
        println "Copying frontend build from ${frontendDistDir} to ${resourcesStaticDir}..."
        println "Backend static resources will be preserved"
    }
    doLast {
        println "Frontend assets copied successfully!"
    }
}

tasks.register('cleanFrontendAssets', Delete) {
    group = 'frontend'
    description = 'Remove previously generated frontend assets from static resources'
    delete generatedFrontendPaths.collect { new File(resourcesStaticDir, it) }
}

tasks.register('copyApiLandingPage', Copy) {
    group = 'frontend'
    description = 'Copy API landing page to index.html for backend-only mode'
    from(new File(resourcesStaticDir, 'api-landing.html'))
    into(resourcesStaticDir)
    rename('api-landing.html', 'index.html')
    dependsOn cleanFrontendAssets
    doFirst {
        println "Copying API landing page to index.html for backend-only mode..."
    }
}

// Ensure copyFrontendAssets runs after spotless tasks
tasks.named('copyFrontendAssets').configure {
    mustRunAfter tasks.matching { it.name.startsWith('spotless') }
}

if (buildWithFrontend) {
    println "Frontend build enabled - JAR will include React frontend"
    processResources.dependsOn copyFrontendAssets
} else {
    println "Frontend build disabled - JAR will be backend-only with API landing page"
    // When not building the UI, ensure any stale frontend assets are removed and use API landing page
    processResources.dependsOn copyApiLandingPage
}

bootJar.dependsOn ':common:jar'
bootJar.dependsOn ':proprietary:jar'
