(ns wanijo.instance.routes
  (:require [compojure.core :refer [defroutes wrap-routes
                                    GET POST DELETE]]
            [ring.util.response :as resp]
            [formulare.core :as form]
            [wanijo.instance.view
             [edit :refer [edit]]
             [instances :refer [instances]]
             [show :refer [show]]
             [link-selection :refer [link-selection]]
             [bulk-link-selection :refer [bulk-link-selection]]
             [starred :refer [starred]]]
            [wanijo.instance.view.starred :refer [starred]]
            [wanijo.instance.db :as domain]
            [wanijo.instance.forms :as forms-inst]
            [wanijo.schema.db :as domain-schema]
            [wanijo.schema.middleware :as middleware-schema]
            [wanijo.link.db :as domain-link]
            [wanijo.infrastructure.routing :refer [register! path]]
            [wanijo.attribute.db :as db-attr]))

(defn route-list! [schema-uuid req]
  (instances (domain-schema/find-by-uuid! schema-uuid)
             (domain/find-by-schema! schema-uuid)
             (forms-inst/with-attributes (db-attr/required! schema-uuid))
             req))

(defn route-new! [req]
  (let [schema-uuid (get-in req [:params :schema-uuid])
        user-uuid (get-in req [:session :uuid])
        req-attrs (db-attr/required! schema-uuid)
        form-def (forms-inst/with-attributes req-attrs)]
    (if (form/valid? form-def req)
      (let [form-data (form/form-data form-def req)
            req-attrs (db-attr/required! schema-uuid)
            instance (forms-inst/form-data->instance form-data
                                                     req-attrs)]
        (domain/create! user-uuid
                        schema-uuid
                        instance)
        (resp/redirect (path :instance-list
                             (:params req))))
      (route-list! schema-uuid req))))

(defn instance! [uuid]
  (domain/full-instance-by-uuid! uuid))

(defn route-show! [uuid req]
  (let [user-uuid (-> req :session :uuid)
        instance (assoc (instance! uuid)
                        :starred
                        (domain/is-starred! uuid
                                            user-uuid))]
    (show instance
          (domain-schema/accessible-schemas! user-uuid)
          req)))

(defn form! [attrs]
  (forms-inst/with-attributes attrs))

(defn route-edit-form! [uuid req]
  (let [instance (instance! uuid)
        attrs (db-attr/find-by-instance! uuid)
        user-uuid (get-in req [:session :uuid])]
    (edit instance
          (form! attrs)
          (forms-inst/instance->form-data instance)
          (domain-schema/accessible-schemas! user-uuid)
          req)))

(defn route-edit! [uuid req]
  (let [attrs (db-attr/find-by-instance! uuid)
        form-def (form! attrs)]
    (if (form/valid? form-def req)
      (let [form-data (form/form-data form-def req)
            form-instance (forms-inst/form-data->instance form-data attrs)
            instance (assoc form-instance :uuid uuid)]
        (domain/edit! instance)
        (resp/redirect (path :instance-show instance)))
      (route-show! uuid req))))

(defn route-delete! [uuid]
  (let [schema (domain-schema/find-by-instance! uuid)]
    (domain/delete! uuid)
    (resp/redirect (path :instance-list
                         {:schema-uuid (:uuid schema)}))))

(defn link-form! [schema-uuid]
  (forms-inst/link-form
    (domain/find-by-schema! schema-uuid)))

(defn route-link-selection! [uuid schema-uuid req]
  (link-selection (instance! uuid)
                  (domain-schema/find-by-uuid! schema-uuid)
                  (link-form! schema-uuid)
                  req))

(defn route-create-link! [uuid schema-uuid req]
  (let [form (link-form! schema-uuid)]
    (if (form/valid? form req)
      (let [form-data (form/form-data form req)]
        (domain-link/create! {:from uuid
                              :name (:name form-data)
                              :to (:instances form-data)
                              :by (get-in req [:session :uuid])})
        (resp/redirect (path :instance-edit-form {:uuid uuid})))
      (route-link-selection! uuid schema-uuid req))))

(defn route-delete-link! [uuid link-uuid]
  (domain-link/delete! link-uuid)
  (resp/redirect (path :instance-edit-form {:uuid uuid})))

(defn route-mark-starred! [uuid req]
  (domain/mark-starred! uuid
                        (-> req :session :uuid))
  (resp/redirect (path :instance-show {:uuid uuid})))

(defn route-remove-starred! [uuid req]
  (domain/remove-starred! uuid
                          (-> req :session :uuid))
  (resp/redirect (path :instance-show {:uuid uuid})))

(defn route-list-starred! [req]
  (starred
    (domain/starred-by-user! (-> req :session :uuid))
    req))

(defn route-bulk-link-selection! [uuid req]
  (let [user-uuid (-> req :session :uuid)]
    (bulk-link-selection (domain/full-instance-by-uuid! uuid)
                         (->> (domain-schema/accessible-schemas!
                                user-uuid)
                              (map (fn [schema]
                                     {:form (link-form! (:uuid schema))
                                      :schema schema}))
                              (forms-inst/bulk-link-form))
                         req)))

(defn route-create-bulk-link! [uuid req]
  (clojure.pprint/pprint req)
  (resp/redirect (path :instance-show {:uuid uuid})))

(defroutes routes
  (wrap-routes
    (GET (register! :instance-list "/instance/list/:schema-uuid")
         [schema-uuid :as req]
         (route-list! schema-uuid req))
    (middleware-schema/wrap-allowed-to-read!
      #(get-in % [:params :schema-uuid])))
  (POST (register! :instance-new "/instance/new") []
    route-new!)
  (GET (register! :instance-show "/instance/:uuid")
       [uuid :as req]
       (route-show! uuid req))
  (GET (register! :instance-edit-form "/instance/:uuid/edit")
       [uuid :as req]
       (route-edit-form! uuid req))
  (POST (register! :instance-edit "/instance/:uuid")
        [uuid :as req]
    (route-edit! uuid req))
  (DELETE (register! :instance-delete "/instance/:uuid")
          [uuid]
    (route-delete! uuid))
  (GET (register! :instance-link-selection
                  "/instance/:uuid/link/:schema-uuid")
       [uuid schema-uuid :as req]
       (route-link-selection! uuid schema-uuid req))
  (POST (register! :instance-link-create
                   "/instance/:uuid/link/:schema-uuid")
        [uuid schema-uuid :as req]
    (route-create-link! uuid schema-uuid req))
  (DELETE (register! :instance-link-delete
                     "/instance/:uuid/link/:link-uuid")
          [uuid link-uuid]
    (route-delete-link! uuid link-uuid))
  (POST (register! :instance-mark-starred
                   "/instance/:uuid/starred")
        [uuid :as req]
    (route-mark-starred! uuid req))
  (DELETE (register! :instance-remove-starred
                     "/instance/:uuid/starred")
          [uuid :as req]
    (route-remove-starred! uuid req))
  (GET (register! :instance-list-starred "/instance/starred/list")
       [:as req]
       (route-list-starred! req))
  (GET (register! :instance-bulk-link-selection "/instance/:uuid/bulk-link")
       [uuid :as req]
       (route-bulk-link-selection! uuid req))
  (POST (register! :instance-bulk-link-create "/instance/:uuid/bulk-link")
        [uuid :as req]
    (route-create-bulk-link! uuid req)))
