;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC Sucursal en España SL

(ns frontend-tests.data.uploads-test
  "Integration tests for the generic chunked-upload logic in
  app.main.data.uploads."
  (:require
   [app.common.uuid :as uuid]
   [app.config :as cf]
   [app.main.data.uploads :as uploads]
   [beicon.v2.core :as rx]
   [cljs.test :as t :include-macros true]
   [frontend-tests.helpers.http :as http]))

;; ---------------------------------------------------------------------------
;; Local helpers
;; ---------------------------------------------------------------------------

(defn- make-blob
  "Creates a JS Blob of exactly `size` bytes."
  [size]
  (let [buf (js/Uint8Array. size)]
    (js/Blob. #js [buf] #js {:type "application/octet-stream"})))

;; ---------------------------------------------------------------------------
;; upload-blob-chunked tests
;; ---------------------------------------------------------------------------

(t/deftest upload-blob-chunked-creates-session-and-uploads-chunks
  (t/testing "upload-blob-chunked calls create-upload-session then upload-chunk for each slice"
    (t/async done
      (let [session-id  (uuid/next)
            chunk-size  cf/upload-chunk-size
            ;; Exactly two full chunks
            blob-size   (* 2 chunk-size)
            blob        (make-blob blob-size)
            calls       (atom [])

            fetch-mock
            (fn [url _opts]
              (let [cmd (http/url->cmd url)]
                (swap! calls conj cmd)
                (js/Promise.resolve
                 (case cmd
                   :create-upload-session
                   (http/make-transit-response
                    {:session-id session-id})

                   :upload-chunk
                   (http/make-transit-response
                    {:session-id session-id :index 0})

                   (http/make-json-response
                    {:error (str "unexpected cmd: " cmd)})))))

            orig (http/install-fetch-mock! fetch-mock)]

        (->> (uploads/upload-blob-chunked blob)
             (rx/subs!
              (fn [{:keys [session-id]}]
                (t/is (uuid? session-id)))
              (fn [err]
                (t/is false (str "unexpected error: " (ex-message err)))
                (done))
              (fn []
                (http/restore-fetch! orig)
                (let [cmd-seq @calls]
                  ;; First call must create the session
                  (t/is (= :create-upload-session (first cmd-seq)))
                  ;; Two chunk uploads
                  (t/is (= 2 (count (filter #(= :upload-chunk %) cmd-seq))))
                  ;; No assemble call here — that's the caller's responsibility
                  (t/is (not (some #(= :assemble-file-media-object %) cmd-seq))))
                (done))))))))

(t/deftest upload-blob-chunked-chunk-count-matches-blob
  (t/testing "number of upload-chunk calls equals ceil(blob-size / chunk-size)"
    (t/async done
      (let [session-id  (uuid/next)
            chunk-size  cf/upload-chunk-size
            ;; Three chunks: 2 full + 1 partial
            blob-size   (+ (* 2 chunk-size) 1)
            blob        (make-blob blob-size)
            chunk-calls (atom 0)

            fetch-mock
            (fn [url _opts]
              (let [cmd (http/url->cmd url)]
                (js/Promise.resolve
                 (case cmd
                   :create-upload-session
                   (http/make-transit-response
                    {:session-id session-id})

                   :upload-chunk
                   (do (swap! chunk-calls inc)
                       (http/make-transit-response
                        {:session-id session-id :index 0}))

                   (http/make-json-response
                    {:error (str "unexpected cmd: " cmd)})))))

            orig (http/install-fetch-mock! fetch-mock)]

        (->> (uploads/upload-blob-chunked blob)
             (rx/subs!
              (fn [_] nil)
              (fn [err]
                (t/is false (str "unexpected error: " (ex-message err)))
                (done))
              (fn []
                (http/restore-fetch! orig)
                (t/is (= 3 @chunk-calls))
                (done))))))))
