plugins {
    id 'distribution'
    id 'maven-publish'
}

configurations {
    lib
    mods
}

dependencies {
    lib project( ':launcher:launcher-main' )
    // JNA required for ElasticSearch but can't be refreshed. It should be part of lib
    lib libs.jna
}

dependencies {
    mods libs.nashorn
    mods libs.graalvm.polyglot
    mods libs.graalvm.js
    mods libs.graalvm.jsse
}

ext {
    bundleCopySpecs = []
}

addBundle( libs.jakarta.activation, 4 )
addBundle( libs.jakarta.mail, 4 )
addBundle( libs.jakarta.annotation, 4 )
addBundle( libs.jakarta.validation, 4 )
addBundle( libs.findbugs.jsr305, 4 )

// Core bundles
addBundle( libs.osgi.service.component, 5 )
addBundle( libs.osgi.service.cm, 5 )
addBundle( libs.osgi.util.promise, 5 )
addBundle( libs.osgi.util.function, 5 )

addBundle( libs.felix.metatype, 5 )
addBundle( libs.felix.eventadmin, 5 )
addBundle( libs.felix.configadmin, 5 )
addBundle( libs.felix.scr, 5 )

//Logging bridges
addBundle( libs.slf4j.jcloverslf4j, 6 )
addBundle( libs.slf4j.log4joverslf4j, 6 )
addBundle( libs.jboss.logging, 6 )

// Java Cryptography Extension
addBundle( libs.bcprov.jdk18on, 6 )

repackBundle( libs.micrometer.commons, 7 )
repackBundle( libs.micrometer.core, 7 )
repackBundle( libs.micrometer.registry.prometheus, 7 )

// Library dependencies
addBundle( libs.guava.guava, 8 )
addBundle( libs.guava.failureaccess, 8 )
addBundle( libs.commons.io, 8 )
addBundle( libs.commons.compress, 8 )
addBundle( libs.commons.lang3, 8 )
addBundle( libs.jackson.core, 8 )
addBundle( libs.jackson.annotations, 8 )
addBundle( libs.jackson.databind, 8 )
addBundle( libs.jackson.datatype.jsr310, 8 )
addBundle( libs.jackson.jakarta.base, 8 )
addBundle( libs.jackson.jakarta.jsonprovider, 8 )

repackBundle( libs.tika.core, 8 ) {
    forceOptional = ["org.apache.xerces"]
}
addBundle( project( ':repack:repack-tika' ), 8 )

repackTikaParserBundle( libs.tika.parser.apple, 8 )
repackTikaParserBundle( libs.tika.parser.audiovideo, 8 )
repackTikaParserBundle( libs.tika.parser.cad, 8 )
repackTikaParserBundle( libs.tika.parser.code, 8 )
repackTikaParserBundle( libs.tika.parser.crypto, 8 )
repackTikaParserBundle( libs.tika.parser.digestcommons, 8 )
repackTikaParserBundle( libs.tika.parser.font, 8 )
repackTikaParserBundle( libs.tika.parser.html, 8 )
repackTikaParserBundle( libs.tika.parser.image, 8 )
repackTikaParserBundle( libs.tika.parser.mail, 8 )
repackTikaParserBundle( libs.tika.parser.mailcommons, 8 )
repackTikaParserBundle( libs.tika.parser.microsoft, 8 )
repackTikaParserBundle( libs.tika.parser.miscoffice, 8 )
repackTikaParserBundle( libs.tika.parser.news, 8 )
repackTikaParserBundle( libs.tika.parser.ocr, 8 )
repackTikaParserBundle( libs.tika.parser.pdf, 8 )
repackTikaParserBundle( libs.tika.parser.pkg, 8 )
repackTikaParserBundle( libs.tika.parser.text, 8 )
repackTikaParserBundle( libs.tika.parser.webarchive, 8 )
repackTikaParserBundle( libs.tika.parser.xml, 8 )
repackTikaParserBundle( libs.tika.parser.xmpcommons, 8 )
repackTikaParserBundle( libs.tika.parser.zipcommons, 8 )

addBundle( libs.hazelcast.hazelcast, 8 )
addBundle( libs.jparsec, 8 )

addBundle( project( ':repack:repack-elasticsearch' ), 9 )
addBundle( project( ':core:core-internal' ), 9 )

// API bundles
addBundle( project( ':core:core-api' ), 10 )
addBundle( project( ':script:script-api' ), 10 )
addBundle( project( ':portal:portal-api' ), 10 )
addBundle( project( ':web:web-api' ), 10 )
addBundle( project( ':jaxrs:jaxrs-api' ), 10 )
addBundle( project( ':admin:admin-api' ), 10 )

// Core bundles
addBundle( project( ':core:core-event' ), 22 )
addBundle( project( ':core:core-schema' ), 22 )
addBundle( project( ':core:core-repo' ), 22 )
addBundle( project( ':core:core-security' ), 22 )
addBundle( project( ':core:core-image' ), 22 )
addBundle( project( ':core:core-export' ), 22 )
addBundle( project( ':core:core-mail' ), 22 )
addBundle( project( ':core:core-elasticsearch' ), 22 )
addBundle( project( ':core:core-hazelcast' ), 22 )
addBundle( project( ':core:core-content' ), 22 )
addBundle( project( ':core:core-site' ), 22 )
addBundle( project( ':core:core-i18n' ), 22 )
addBundle( project( ':core:core-media' ), 22 )
addBundle( project( ':core:core-app' ), 22 )
addBundle( project( ':core:core-service' ), 22 )
addBundle( project( ':core:core-blobstore' ), 22 )
addBundle( project( ':core:core-extractor' ), 22 )
addBundle( project( ':core:core-auth' ), 22 )
addBundle( project( ':core:core-macro' ), 22 )
addBundle( project( ':core:core-task' ), 22 )
addBundle( project( ':core:core-audit' ), 22 )
addBundle( project( ':core:core-project' ), 22 )
addBundle( project( ':core:core-scheduler' ), 22 )
addBundle( project( ':core:core-shared' ), 22 )
addBundle( project( ':core:core-cluster' ), 22 )

// BlobStore providers
addBundle( project( ':blobstore:blobstore-file' ), 23 )

// Server bundles
addBundle( project( ':server:server-config' ), 12 )
addBundle( project( ':server:server-deploy' ), 32 )
addBundle( project( ':server:server-status' ), 17 )
addBundle( project( ':server:server-udc' ), 17 )
addBundle( project( ':server:server-rest' ), 30 )
addBundle( project( ':server:server-trace' ), 17 )
addBundle( project( ':server:server-metrics' ), 7 )

// Web app
addBundle( project( ':web:web-jetty' ), 26 )
addBundle( project( ':web:web-impl' ), 26 )
addBundle( project( ':web:web-vhost' ), 26 )
addBundle( project( ':web:web-dos' ), 26 )
addBundle( project( ':web:web-dispatch' ), 26 )
addBundle( project( ':web:web-session' ), 26 )
addBundle( project( ':web:web-header' ), 26 )

addBundle( project( ':script:script-impl' ), 28 )
addBundle( project( ':portal:portal-impl' ), 28 )
addBundle( project( ':jaxrs:jaxrs-impl' ), 28 )

// Admin app
addBundle( project( ':admin:admin-event' ), 30 )
addBundle( project( ':admin:admin-impl' ), 30 )

// Applications
addBundle( project( ':app:app-system' ), 32 )

def repackTikaParserBundle( depProvider, level ) {
    repackBundle( depProvider, level) {
        fragmentHost = "org.apache.tika.bundle-standard;bundle-version=\"[3.2,4)\""
    }
}

def repackBundle( depProvider, level, Closure config = null ) {
    def context = [:]
    if (config)
    {
        config.delegate = context
        config.resolveStrategy = Closure.DELEGATE_FIRST
        config()
    }

    def levelStr = "$level".padLeft( 2, '0' )
    def dep = depProvider.get()
    def modifiedJarConfig = configurations.create("modifiedBundle@${dep.name}") {
        transitive = false
    }
    dependencies.add( modifiedJarConfig.name, depProvider )

    def modifyManifestTask = tasks.register("modifiedBundleManifest@${dep.name}", Jar) {

        archiveFileName = "${dep.name}-${dep.version}-repack.jar"
        destinationDirectory = layout.buildDirectory.dir( "tmp/modified-bundles" )

        def artifact = modifiedJarConfig.resolve().first()

        java.util.jar.JarFile jar = new java.util.jar.JarFile( artifact )
        java.util.jar.Manifest originalManifest = jar.manifest


        def modifiedImportPackage = originalManifest.getMainAttributes().getValue( "Import-Package" ).split(/,(?=(?:[^"]*"[^"]*")*[^"]*$)/)
            .collect {

                if (context.forceOptional)  {
                    it = (it.startsWithAny( context.forceOptional as CharSequence[]) && !it.contains( ";resolution:=" ))
                        ? it + ";resolution:=optional" : it
                }
                it = it.startsWithAny( "org.slf4j" ) ? it.replace( "version=\"[1.7,2)", "version=\"[1.7,3)" ) : it
                return it;
            }.join( ',' )

        def modifiedDynamicImportPackage = (originalManifest.getMainAttributes().getValue("DynamicImport-Package") ?: "").split(/,(?=(?:[^"]*"[^"]*")*[^"]*$)/)
            .collect {
                it = it.startsWithAny( "org.slf4j" ) ? it.replace( "version=\"[1.7,2)", "version=\"[1.7,3)" ) : it
                return it;
            }.join( ',' )

        from {
            zipTree(artifact)
        }

        with copySpec {
            exclude "META-INF/MANIFEST.MF"
        }

        manifest {
            attributes originalManifest.mainAttributes.collectEntries { key, value ->
                if (key.toString() == "Import-Package") {
                    ["Import-Package": modifiedImportPackage]
                } else if (key.toString() == "DynamicImport-Package") {
                    ["DynamicImport-Package": modifiedDynamicImportPackage]
                } else {
                    [(key.toString()): value.toString()]
                }
            }  + (context.fragmentHost ? ["Fragment-Host": context.fragmentHost] : [:])
        }
    }

    ext.bundleCopySpecs += project.copySpec {
        from modifyManifestTask
        into levelStr
    }
}

def addBundle( dep, level )
{
    def levelStr = "$level".padLeft( 2, '0' )
    def configName = "bundle@$levelStr"

    def config = configurations.findByName( configName )

    if ( config == null )
    {
        config = configurations.create( configName ) {
            transitive = false
            description = "Bundles for run-level $level"
            attributes {
                attribute( Attribute.of("org.gradle.jvm.environment", String), "standard-jvm" )
            }
        }
        ext.bundleCopySpecs += project.copySpec {
            from config
            into levelStr
        }
    }
    dependencies.add( configName, dep )
}

distributions {
    main {
        contents {
            into( '/system' ) {
                with( bundleCopySpecs as CopySpec[] )
            }
            into( '/lib' ) {
                from( configurations.lib )
            }
            into( '/mods' ) {
                from( configurations.mods )
            }
            into( '/' ) {
                from( 'src' ) {
                    filesMatching( '**/*.sh' ) {
                        permissions { unix '0755' }
                    }
                }
                from( rootDir ) {
                    include 'LICENSE.txt'
                    include 'NOTICE.txt'
                }
            }
        }
    }
}

tasks.distTar.enabled = false

installDist {
    into( layout.buildDirectory.dir( "install" ) )
}

build.dependsOn installDist

publishing.publications {
    mavenDist( MavenPublication ) {
        artifact distZip
    }
}
