xquery version "3.1";

import module namespace commons="http://ahiqar.uni-goettingen.de/ns/commons" at "modules/commons.xqm";
import module namespace functx="http://www.functx.com";

import module namespace import="http://ahiqar.uni-goettingen.de/ns/import" at "/db/apps/ahiqar/modules/import-data-api.xqm";


declare namespace conf = "http://exist-db.org/Configuration";
declare namespace pkg="http://expath.org/ns/pkg";

(: the target collection into which the app is deployed :)
declare variable $target external; (: := "/db/apps/ahiqar"; :)
declare variable $appsTarget := '/' || tokenize($target, '/')[position() lt last()] => string-join('/');
declare variable $tg-base := $commons:tg-collection;
declare variable $isTest := doc("expath-pkg.xml")/pkg:package/@abbrev => contains("-test");

declare function local:move-and-rename($filename as xs:string) as item()* {
    let $data-file-path := $target || "/data/"
    let $target-data-collection := $commons:data
    let $target-meta-collection := $commons:meta
    let $target-agg-collection := $commons:agg
    let $target-tile-collection := $commons:tile

    let $file-type := functx:substring-after-last($filename, "_")
        => substring-before(".xml")

    return

        switch ($file-type)
            case "meta" return
                let $new-filename := substring-before($filename, "_meta") || ".xml"
                return
                    (
                        xmldb:move($data-file-path, $target-meta-collection, $filename),
                        xmldb:rename($target-meta-collection, $filename, $new-filename)
                    )
            case "tile" return
                xmldb:move($data-file-path, $target-tile-collection, $filename)
            case "teixml" return
                xmldb:move($data-file-path, $target-data-collection, $filename)
            default return
                xmldb:move($data-file-path, $target-agg-collection, $filename)
};

(:~
 : get absolute path to all resources (xml and binary) in a collection, recursively.
 : @param $target path to a collection as xs:string
 : @return sequence of all resources as xs:string
 :)
declare function local:get-child-resources-recursive($target as xs:string)
as xs:string* {
    xmldb:get-child-resources($target) ! ($target || "/" || .),
    xmldb:get-child-collections($target) ! local:get-child-resources-recursive($target || "/" || .)
};

declare function local:prepare-index($targetCollection as xs:string, $indexFile as xs:string) {
        if (xmldb:collection-available($targetCollection)) then
        (
            let $contents := doc($target || "/" || $indexFile)/*
            let $store := xmldb:store($targetCollection, "collection.xconf", $contents)
            return
                xmldb:remove($target, $indexFile)
        )
    else
        (
            xmldb:create-collection("/db/system/config/db/", substring-after($targetCollection, "/db/system/config/db/")),
            let $contents := doc($target || "/" || $indexFile)/*
            let $store := xmldb:store($targetCollection, "collection.xconf", $contents)
            return
                xmldb:remove($target, $indexFile)
        )
};

(:  set admin password on deployment. Convert to string
    so local development will not fail because of missing
    env var. :)
((
    let $adminDoc := doc('/db/system/security/exist/accounts/admin.xml')
    let $secret := commons:get-secret("EXIST_ADMIN_PW_RIPEMD160")
    return
        if($secret)
        then
            (update replace $adminDoc//conf:password/text() with text{ replace($secret, '"', '') },
            if($adminDoc//conf:digestPassword) then
                update replace $adminDoc//conf:digestPassword/text() with text{ string( commons:get-secret("EXIST_ADMIN_PW_DIGEST")) }
            else
                let $element :=
                    element conf:digestPassword {
                        text { string(commons:get-secret("EXIST_ADMIN_PW_DIGEST")) }
                    }
                return
                    update insert $element into $adminDoc/conf:account
            )
        else (: we do not have the env vars available, so we leave the configuration as it is :)
            true()
),
(: set target URL from env var :)
(
    if (available-environment-variables() = 'AHIQAR_TEXTAPI_URL')
    then
        update value doc("expath-pkg.xml")/pkg:package/@api-base-url with environment-variable('AHIQAR_TEXTAPI_URL')
    else
        util:log-system-out('🐡 no env var present: AHIQAR_TEXTAPI_URL === fallback to default (' ||
            string( doc("expath-pkg.xml")/pkg:package/@api-base-url ) || ')' )
),
(
    (: register REST APIs :)
    for $uri in local:get-child-resources-recursive($target)[ends-with(., ".xqm")]
        let $content := $uri => util:binary-doc() => util:base64-decode()
        where contains($content, "%rest:")
        return
            exrest:register-module(xs:anyURI($uri))
),
(: set owner and mode for modules :)
(
    (
        $target || "/modules/tapi.xqm",
        $target || "/modules/deploy.xqm",
        $target || "/modules/testtrigger.xqm",
        $target || "/modules/apitesttrigger.xqm",
        $target || "/modules/import-data-api.xqm",
        $target || "/modules/AnnotationAPI/save-annotations.xqm"
    ) ! (sm:chown(., "admin"), sm:chmod(., "rwsrwxr-x"))
),
(: create trigger and index config.
 : simply moving the file from one place to the other doesn't cause eXist-db to recognize the
 : config. neither does reindexing after moving the file.
 : therefore we have to create a new file and copy the contents of /db/apps/ahiqar/collection-*.xconf. :)
(
    local:prepare-index("/db/system/config/db/data/textgrid/data", "collection-data.xconf"),
    local:prepare-index("/db/system/config/db/data/textgrid/agg", "collection-agg.xconf")
),
(: move the sample XMLs to /db/data/textgrid to be available in the viewer (only for new installation. Skip this step when data is present to not install
    sample data by updating exposed instances.) :)
(
    if(count(xmldb:get-child-resources($commons:data)) gt 0) then (util:log-system-out("🐡 not moving sample data.")) else

       (
            util:log-system-out("🐡 moving sample data."),
            xmldb:get-child-resources($target || "/data")[ends-with(., ".xml")]
            ! local:move-and-rename(.)
       )
),
(: create data collections :)
(
    xmldb:create-collection($commons:tg-collection, "html"),
    xmldb:create-collection($commons:tg-collection, "json"),
    xmldb:create-collection($commons:tg-collection, "tile"),
    xmldb:create-collection($commons:tg-collection, "tmp")
),
(: move CSS to /db/data/resources/css :)
(
    xmldb:create-collection("/db/data", "resources"),
    xmldb:create-collection("/db/data/resources", "css"),
    xmldb:move($target || "/resources/css", "/db/data/resources/css", "ahiqar.css")
),

(: move audio files to /db/data/resources/mp3 :)
(
    xmldb:move($target || "/resources/mp3", "/db/data/resources/")
),
(: move fonts to /db/data/resources/fonts :)
(
    xmldb:move($target || "/resources/fonts", "/db/data/resources/"),
    xmldb:remove($target || "/resources")
),

(: make Ahiqar specific OpenAPI config available to the OpenAPI app :)
(
    if (xmldb:collection-available($appsTarget || "/openapi")) then
        (xmldb:remove($appsTarget || "/openapi", "openapi-config.xml"),
        xmldb:move($target, $appsTarget || "/openapi", "openapi-config.xml"))
    else
        ()
),
(: move collation results to data collection (that is exposed via REST)
 : and create XML files with index :)
(
    xmldb:move($target || "/data/collation-results", $commons:tg-collection || "/../")
),
(
    let $collation := "/db/data/collation-results/"
    let $collation-xml-path := xmldb:create-collection($commons:tg-collection || "/../", "collation-results-xml")
    for $json-file in xmldb:get-child-resources($collation) return
        if (ends-with($json-file, ".json")) then
            let $doc := util:binary-doc($collation || $json-file)
                => util:base64-decode()
                => json-to-xml()
                => serialize(map{"method": "microxml"})
            let $filename := substring-before($json-file, ".json") || ".xml"
            return xmldb:store($collation-xml-path, $filename, $doc)
        else
            ()
),
(
    local:prepare-index("/db/system/config/db/data/collation-results-xml", "collection-collation.xconf"),
    xmldb:reindex("/db/data/collation-results-xml")
),

( if (available-environment-variables() = 'CI_SERVICE')
    then (
        util:log-system-out("🐡 preparing CI Service"),
        for $uri at $pos in ( "textgrid:3r132", "textgrid:3r84g", "textgrid:3r84h", "textgrid:3r9ps", "textgrid:40xnp", "textgrid:41np5")
        let $cleanup := if ($pos eq 1) then "true" else "false" (: has to be string :)
        let $token := "1234"
        let $recursive := "false" (: has to be string :)
        return
            import:publish-uri($uri, $token, $cleanup, $recursive)
        )
    else ()
    ),

(   if( not( exists( file:list("/")//*[@name eq "export"] ))) then () else
    let $dir := "/export"
    let $cleanup := (xmldb:remove("/db/data/textgrid"), xmldb:create-collection("/db/data", "textgrid"))
    let $log := util:log-system-out("💾 loading data from directory…")
    for $name in file:list($dir)//file:directory/string(@name)
    return (
        xmldb:store-files-from-pattern("/db/data/textgrid", $dir || "/" || $name, "**/*.json", "application/json", true()),
        xmldb:store-files-from-pattern("/db/data/textgrid", $dir || "/" || $name, "**/*.html", "application/xml", true()),
        xmldb:store-files-from-pattern("/db/data/textgrid", $dir || "/" || $name, "**/*.xml", "application/xml", true())
    )
),

util:log-system-out("🐡 FIN!")
)