(.using [library [lux (.except Type) [abstract [monad (.only do)] [equivalence (.only Equivalence)]] [control ["[0]" pipe] ["[0]" try (.only Try)] ["[0]" exception (.only exception:)] ["<>" parser (.only) ["<[0]>" xml (.only Parser)]] [concurrency ["[0]" async (.only Async)]]] [data ["[0]" product] ["[0]" text (.only) ["%" format] ["<[1]>" \\parser] [encoding ["[0]" utf8]]] [format ["[0]" xml (.only XML)]] [collection ["[0]" list (.open: "[1]#[0]" functor)]]] [math [number ["n" nat]]] ["[0]" time (.only Time) ["[0]" instant (.only Instant)] ["[0]" date (.only Date)] ["[0]" year] ["[0]" month]] [world [net ["[0]" uri (.only URI)]]]]] ["[0]" // (.only) ["/[1]" // [repository (.only Repository)] ["[1][0]" artifact (.only Group Name Version Artifact) ["[1]/[0]" time] ["[1]/[0]" type (.only Type)] ["[1]/[0]" versioning (.only Versioning)] ["[1]/[0]" snapshot (.only) ["[1]/[0]" version] ["[1]/[0]" stamp]]]]]) (type: .public Metadata (Record [#artifact Artifact #versioning Versioning])) (with_template [ ] [(def: xml.Tag ["" ])] [ "groupId"] [ "artifactId"] [ "version"] [ "metadata"] ) (with_template [
]
  [(def: 
     (->  XML)
     (|>> 
 {xml.#Text} list {xml.#Node  xml.attributes}))]

  [group_format Group .. (|>)]
  [name_format Name .. (|>)]
  [version_format Version .. (|>)]
  )

(def: .public (format (open "/[0]"))
  (-> Metadata XML)
  (let [(open "//[0]") /#artifact]
    {xml.#Node ..
               xml.attributes
               (list (..group_format //#group)
                     (..name_format //#name)
                     (..version_format //#version)
                     (///artifact/versioning.format /#versioning))}))

(def: (text tag)
  (-> xml.Tag (Parser Text))
  (<| (.node tag)
      .text))

(def: .public parser
  (Parser Metadata)
  (<| (.node ..)
      (do [! <>.monad]
        [group (.somewhere (..text ..))
         name (.somewhere (..text ..))
         version (.somewhere (..text ..))
         versioning (with_expansions [ [///artifact/snapshot/version.#extension ///artifact/type.jvm_library
                                                         ///artifact/snapshot/version.#value version
                                                         ///artifact/snapshot/version.#updated ///artifact/time.epoch]]
                      (|> (.somewhere ///artifact/versioning.parser)
                          (at ! each
                              (revised ///artifact/versioning.#versions
                                       (is (-> (List ///artifact/snapshot/version.Version)
                                               (List ///artifact/snapshot/version.Version))
                                           (|>> (pipe.case
                                                  (pattern (list))
                                                  (list )

                                                  versions
                                                  versions)))))
                          (<>.else [///artifact/versioning.#snapshot {///artifact/snapshot.#Local}
                                    ///artifact/versioning.#last_updated ///artifact/time.epoch
                                    ///artifact/versioning.#versions (list )])))]
        (in [#artifact [///artifact.#group group
                        ///artifact.#name name
                        ///artifact.#version version]
             #versioning versioning]))))

(def: .public equivalence
  (Equivalence Metadata)
  (all product.equivalence
       ///artifact.equivalence
       ///artifact/versioning.equivalence
       ))

(def: .public uri
  (-> Artifact URI)
  //.remote_artifact_uri)

(def: .public (read repository artifact)
  (-> (Repository Async) Artifact (Async (Try Metadata)))
  (do async.monad
    [project (at repository download (..uri artifact))]
    (case project
      {try.#Success project}
      (in (|> project
              (pipe.do try.monad
                [(at utf8.codec decoded)]
                [(at xml.codec decoded)]
                [list (.result ..parser)])))
      
      {try.#Failure error}
      (in {try.#Success
           [#artifact artifact
            #versioning ///artifact/versioning.init]}))))

(def: .public (write repository artifact metadata)
  (-> (Repository Async) Artifact Metadata (Async (Try Any)))
  (|> metadata
      ..format
      (at xml.codec encoded)
      (at utf8.codec encoded)
      (at repository upload (..uri artifact))))