(in-package #:cl-deck-builder2.web)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Helper Functions
(defun upload-deck-by-content (name content &optional (sort t))
  "Helper Function. Create a new YDK deck with CREATED-BY set, a new deck name of NAME, with deck CONTENT. Optionally if SORT is T (which it is by default), sort the deck with YDK-SORTED before committing it to the database, with YDK-SYNC."
  ;; TODO RATIFY:WITH-PARSED-FORMS here?
  (assert (and name content))

  ;; Insert the Deck
  (let ((ydk (make-instance 'ydk :created-by "UPLOAD-DECK-BY-CONTENT"
                                 :content content :name name)))
    (unless ydk
      (flash-error (_ "Something went wrong. Try again?"))
      (redirect "/ydk"))
    
    (if sort
        (setf ydk (ydk-sorted ydk)))

    (let ((deck (ignore-errors
                 (ydk-sync ydk))))
      (if deck
          (redirect (format nil "/decks/~d/view" (mito:object-id deck)))
          (progn
            (flash-error (_ "Something went wrong. Try again?"))
            (redirect "/ydk"))))))

;; TODO Since we now accept multiple file uploads, we'll also either have to:
;; 1) Allow multiple file names
;; 2) Disallow naming multiple file uploads
;; 3) Something else
(defun process-uploaded-files (files query query-filename &optional (random-filename nil))
  "Helper Function. Process FILES uploaded in the YDK POST route."
  (v:info :ydk "PROCESS-UPLOADED-FILES: ~a ~a ~a" files query query-filename)
  (if files
      (dolist (file files)
        (destructuring-bind (content filename content-type)
            file

          ;; First - if the user specified a filename, use that as the file name.
          (ignore-errors
           (ratify:with-parsed-forms
               ((:string query-filename))
             (setf filename query-filename)))

          ;; If RANDOM-FILENAME is T, just use a random file key anyway.
          (if random-filename
              (setf filename
                    (random-pathname-name
                     :type (pathname-type filename))))

          ;; Then - Try to save whatever was uploaded using CREATE-ATTACHMENT-FROM-UPLOAD
          (let ((attachment (create-attachment content filename content-type)))
            ;; Then - If that was successful, use *that* newly
            ;; created ATTACHMENT and pass it to
            ;; UPLOAD-DECK-BY-CONTENT which is the old mechanism we
            ;; first wrote, that handles everything nicely with
            ;; YDK-SYNC and YDK-SORTED abstracting things.
            (if attachment
                (upload-deck-by-content filename
                                        (uiop:slurp-stream-string
                                         (mito-attachment:get-object attachment)))
                (progn
                  (flash :errors "YDK Upload failed! Try again?")
                  (redirect "/ydk" 302))))))
      (progn
        ;; If QUERY-FILENAME is set, supersede FILENAME with that.
        ;; If we got here something went wrong with the FILE
        ;; parse. Try to use QUERY before flashing an error.  We do
        ;; the same thing - enfore :STRING with
        ;; RATIFY:WITH-PARSED-FORMS. Maybe this is a good case for
        ;; RESTART-CASE?
        (handler-case
            (ratify:with-parsed-forms
                ((:string query)
                 (:string query-filename))
              (flash :messages "YDK-SUBMIT: using QUERY instead of FILE-QUERY")
              (upload-deck-by-content query-filename query))
          (ratify:combined-error (e)
            (flash :errors (format nil "YDK Upload failed! Try again?~%~a" e))
            (redirect "/ydk" 302))))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; YDK Upload
(defroute ("/ydk" :method :GET) ()
  "YDK Upload Main Route"
  (v:info :ydk "GET /ydk")

  (with-logged-in-user
    (render-with-env #P"ydk/index.html"
                     `(:active "/ydk"))))


(defroute ("/ydk" :method :POST) (&key _parsed)
  "YDK Upload POST Processing Route"
  (v:info :ydk "POST /ydk => ~a" _parsed)

  (with-logged-in-user
    (process-uploaded-files (query-param "files" _parsed)
                            (query-param "query" _parsed)
                            (query-param "filename" _parsed))))
