xquery version "3.1";

module namespace import="http://ahiqar.uni-goettingen.de/ns/import";

import module namespace commons="http://ahiqar.uni-goettingen.de/ns/commons" at "commons.xqm";
import module namespace connect="https://sade.textgrid.de/ns/connect" at "/db/apps/textgrid-connect/modules/connect.xqm";
import module namespace rest="http://exquery.org/ns/restxq";

declare namespace output="http://www.w3.org/2010/xslt-xquery-serialization";
declare namespace ore="http://www.openarchives.org/ore/terms/";
declare namespace rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";


declare variable $import:maps :=  
            array {
                map {
                    "uri": "textgrid:3r132",
                    "recursive": "false",
                    "cleanup": "true", (: inital cleanup :)
                    "timeout": ()},
                map {
                    "uri": "textgrid:3r84g",
                    "recursive": "true",
                    "cleanup": "false",
                    "timeout": "30"},
                map {
                    "uri": "textgrid:3r84h",
                    "recursive": "true",
                    "cleanup": "false",
                    "timeout": "30"},
                map {
                    "uri": "textgrid:3r9ps",
                    "recursive": "true",
                    "cleanup": "false",
                    "timeout": "30"}
            };

declare
    %rest:GET
    %rest:HEAD
    %rest:path("/import-data-all")
    %rest:query-param("token", "{$token}", "1234")
    %output:method("json")
function import:main($token) {
    if( $token ne commons:get-secret("APP_DEPLOY_TOKEN" )) then
        error(QName("error://1", "deploy"), "Deploy token incorrect.")
    else
        let $log := local:log("STARTING IMPORT ALL RESOURCES")
        let $lock := xmldb:store("/db", "import-lock.xml", <lock dateTime="{util:system-dateTime()}"/>)
    for $map in ($import:maps?*)[1]
    (: this module aims for parallel processing. we are going back to serial processing
        and alter the incomming map in this way. :)
    return (
        local:log("IMPORTING " || $map("uri")), 
        let $url :=
            "http://localhost:8080/exist/restxq/import-data/" 
            || $map("uri")
            || "?token="
            || $token
            || "&amp;recursive="
            || "true"
            || "&amp;cleanup="
            || $map("cleanup")

        let $request := 
            element hc:request {
                attribute method {"GET"},
                attribute href {$url},
                if($map("timeout") ne "") then attribute timeout {$map("timeout")} else ()
            }
        return
            try {
                hc:send-request($request)
            } catch * {
                "started import with $request: " || serialize($request)
            }
            
), xmldb:remove("/db", "import-lock.xml")
};

(:~
 : Remove all data present. Mainly used to cleanup sample data.
 : To not interfere with the collection trigger we are going to remove all
 : resources and not the collections themself.
 :)
declare function local:cleanup() {
    for $collection in ($commons:data, $commons:agg, $commons:meta, $commons:tile, $commons:json, $commons:html, $commons:tmp)
    where xmldb:collection-available($collection)
    let $resources := xmldb:get-child-resources($collection)
    for $resource in $resources
    return
        xmldb:remove($collection, $resource)
};

declare function local:publish($uri) {
    let $sid := commons:get-textgrid-session-id()
    let $user := "admin"
    let $password := commons:get-secret("EXIST_ADMIN_PW")
    return
        connect:publish($uri, $sid, $user, $password, false())
};

declare function local:log($message as xs:string) {
    util:log-system-out( util:system-time() || " ::: " || $message )
};

declare
    %rest:GET
    %rest:HEAD
    %rest:path("/import-data/{$uri}")
    %rest:query-param("token", "{$token}", "1234")
    %rest:query-param("cleanup", "{$cleanup}")
    %rest:query-param("recursive", "{$recursive}")
    %output:method("json")
function import:publish-uri($uri, $token, $cleanup, $recursive) {
    if( $token ne commons:get-secret("APP_DEPLOY_TOKEN" )) then
        error(QName("error://1", "deploy"), "Deploy token incorrect.")
    else
        let $cleanup := if($cleanup eq "true") then local:cleanup() else ()
        let $sid := commons:get-textgrid-session-id()
        let $user := "admin"
        let $password := commons:get-secret("EXIST_ADMIN_PW")
        let $r := $recursive => xs:boolean()
        let $strictValidation := false()
        return
            connect:publish($uri, $sid, $user, $password, $strictValidation, $r)
};

declare function import:continue() {
    if (not( doc-available("/db/import-lock.xml") )) then util:log-system-out("no locked import. good.") else
    
    (: create a list containing all resources to import:
        - Restart the very last Edition where we suspect the import broke
        - Language Editions import not started at all
        - Editions we are missing from the last run
    :)
    
    
    let $removeLastModified := 
    (: remove edition created last to make it available completely as we suspect import broke here :)
        let $resourceLastModifiedTimestamp := xmldb:get-child-resources($commons:agg) ! xmldb:last-modified($commons:agg, .) => max()
        for $resource in xmldb:get-child-resources($commons:agg)
        return
            if(xmldb:last-modified($commons:agg, $resource) eq $resourceLastModifiedTimestamp)
            then xmldb:remove($commons:agg, $resource)
            else $resource

    let $allLanguages := $import:maps?*?uri[not(. eq "textgrid:3r132")] => distinct-values()
    let $urisTodoLanguages := 
        for $uri in $allLanguages
        where $uri != collection($commons:agg)//rdf:Description/substring-before(@rdf:about, ".")
        return $uri

    (: since we removed the last modified resource, we will restart the very last :)
    let $urisTodoEditions  := 
        let $wantedEditions := collection($commons:agg)//rdf:Description[substring-before(@rdf:about, ".") = $allLanguages]/ore:aggregates/string(@rdf:resource)
        let $availableEditions := collection($commons:agg)//rdf:Description[substring-before(@rdf:about, ".") = $wantedEditions]/substring-before(@rdf:about, ".")
        return
            $wantedEditions[. != $availableEditions]
    let $log := util:log-system-out("continue last import with the following URIs: " || string-join(($urisTodoEditions, $urisTodoLanguages), ", "))
    return (
    for $uriEdition in ($urisTodoEditions, $urisTodoLanguages)
    return
        import:publish-uri($uriEdition, commons:get-secret("APP_DEPLOY_TOKEN" ), "false", "true")
        
    ), xmldb:remove("/db", "import-lock.xml")
};