(.using
  [library
   [lux "*"
    ["_" test {"+" Test}]
    [abstract
     ["[0]" monad {"+" do}]]
    [control
     ["[0]" try {"+" Try} ("[1]#[0]" functor)]
     ["[0]" exception]
     [concurrency
      ["[0]" async {"+" Async}]]
     [parser
      ["[0]" environment]]]
    [data
     ["[0]" binary]
     ["[0]" text ("[1]#[0]" equivalence)
      ["%" format {"+" format}]]
     [collection
      ["[0]" set {"+" Set}]]]
    [math
     ["[0]" random]]
    [world
     ["[0]" file]
     ["[0]" program {"+" Program}]]]]
  [//
   ["$[0]" version]
   [//
    ["$[0]" profile]
    ["$[0]" artifact]]]
  [\\program
   ["[0]" /
    ["/[1]" // "_"
     ["/[1]" // "_"
      ["[1]" profile]
      ["[1][0]" action {"+" Action}]
      ["[1][0]" local]
      ["[1][0]" artifact
       ["[1]/[0]" extension]]
      ["[1][0]" repository "_"
       ["[1]/[0]" local]]]]]])

(def: .public (make_sources! fs sources)
  (-> (file.System Async) (Set file.Path) (Action (List Any)))
  (let [/ (# fs separator)
        ! ///action.monad]
    (|> sources
        set.list
        (monad.each ! (function (_ head)
                        (do !
                          [_ (: (Async (Try Any))
                                (file.make_directories async.monad fs head))]
                          (: (Async (Try Any))
                             (file.make_file async.monad fs (binary.empty 0) (format head / head ".lux")))))))))

(def: (execute! program fs sample)
  (-> (Program Async) (file.System Async) ///.Profile (Async (Try Text)))
  (do ///action.monad
    [.let [console ($version.echo "")]
     _ (..make_sources! fs (value@ ///.#sources sample))
     _ (/.do! console fs (///repository/local.repository program fs) sample)]
    (# console read_line [])))

(def: .public test
  Test
  (<| (_.covering /._)
      (do [! random.monad]
        [identity $artifact.random
         sample (# ! each (with@ ///.#identity {.#Some identity})
                   $profile.random)
         home (random.ascii/alpha 5)
         working_directory (random.ascii/alpha 5)
         .let [/ (# file.default separator)]]
        ($_ _.and
            (in (do [! async.monad]
                  [.let [fs (file.mock /)
                         program (program.async (program.mock environment.empty home working_directory))

                         artifact_path (///local.uri (value@ ///artifact.#version identity) identity)
                         library_path (format artifact_path ///artifact/extension.lux_library)
                         pom_path (format artifact_path ///artifact/extension.pom)]
                   verdict (do [! ///action.monad]
                             [succeeded! (# ! each (text#= /.success)
                                            (..execute! program fs sample))
                              library_exists! (|> library_path
                                                  (format home /)
                                                  (# fs file?)
                                                  (# async.monad each (|>> {try.#Success})))
                              pom_exists! (|> pom_path
                                              (format home /)
                                              (# fs file?)
                                              (# async.monad each (|>> {try.#Success})))]
                             (in (and succeeded!
                                      library_exists!
                                      pom_exists!)))]
                  (_.cover' [/.do! /.success]
                            (try.else false verdict))))
            (in (do [! async.monad]
                  [.let [fs (file.mock /)
                         program (program.async (program.mock environment.empty home working_directory))]
                   logging (..execute! program fs (with@ ///.#identity {.#None} sample))]
                  (_.cover' [/.failure]
                            (|> logging
                                (try#each (text#= /.failure))
                                (try.else false)))))
            ))))
