(ns advent.screens.scene
  (:require [play-clj.core :refer :all]
            [play-clj.ui :refer :all]
            [play-clj.utils :refer :all]
            [play-clj.g2d :refer :all]
            [clojure.pprint]
            [advent.pathfind]
            [advent.actions :as actions]
            [advent.zone :as zone]
            [advent.screens.dialogue :refer [talking-screen]])
  (:import [com.badlogic.gdx.graphics Pixmap Pixmap$Filter Texture Texture$TextureFilter]
          [com.badlogic.gdx.graphics.g2d TextureRegion] ))

(def +screen-width+ 320)
(def +screen-height+ 240)
(def +num-cursors+ 4)
(def +next-cursor+ (into {} (map vector [:walk :touch :look :talk] (drop 1 (cycle [:walk :touch :look :talk])))))
(def +all-cursors+ [:walk :touch :look :talk :right :down :left :up])

(def +cursor-defaults+ {:walk (fn [screen entities [x y]]
                                (assoc-in entities [:ego :actions] (actions/from-path screen entities :ego [x y])))
                        :look (fn [screen entities _]
                                (assoc-in entities [:ego :actions] [(actions/stop :ego)
                                                                    (actions/talk :ego "Looks pretty uninteresting to me.")]))
                        :touch (fn [screen entities _]
                                 (assoc-in entities [:ego :actions] [(actions/stop :ego)
                                                                     (actions/talk :ego "Can't do anything with it.")]))
                        :talk (fn [screen entities _]
                                (assoc-in entities [:ego :actions] [(actions/stop :ego)
                                                                    (actions/talk :ego "It's not much of a conversationalist.")]))})

(defn cursor [filename which]
  (let [scale 2
        base-cursor (pixmap filename)
        target-width (* 16 scale)
        target-height (* 16 scale)
        resized (Pixmap. target-width target-height (.getFormat base-cursor))
        index (.indexOf +all-cursors+ which)]
    (Pixmap/setFilter Pixmap$Filter/NearestNeighbour)
    (pixmap! resized :draw-pixmap base-cursor (* index 16) 0 16 16
             0 0 target-width target-height)
    resized ))

(defn right-click [screen entities]
  (let [entities (update-in entities [:cursor] #(assoc % :current (+next-cursor+ (:current %))))]
    (input! :set-cursor-image (cursor "cursor.png" (get-in entities [:cursor :current])) 0 0)
    entities))


(defn walk-override-click [screen entities [x y]]
  (let [target-location (->> (get-in entities [:background :mouse-overrides])
                             (filter #((:mouse-in? %) x y))
                             first
                             :go-to)]
    (assoc-in entities [:ego :actions] (actions/from-path screen entities :ego target-location))))

(defn left-click [screen entities]
  (let [{:keys [x y]} (input->screen screen {:x (:input-x screen) :y (:input-y screen)})
        interaction (first (filter #((:mouse-in? %) x y) (get-in entities [:background :interactions])))
        current-cursor (get-in entities [:cursor :current])
        interaction-fn (when interaction
                         (interaction current-cursor))]
    (cond (get-in entities [:cursor :override]) (walk-override-click screen entities [x y])
          (and interaction interaction-fn) (interaction-fn screen entities [x y])
          :else
          ((+cursor-defaults+ current-cursor) screen entities [x y])))) 

(defn get-ego [screen]
  (let [player-sheet (texture! (texture "player.png") :split 18 36)
        talk-sheet (texture! (texture "ego/talk.png") :split 16 36)
        ego {:right  (animation 0.075 (for [i (range 8)]
                                        (texture  (aget player-sheet 0 i))))
             :left (animation 0.075 (for [i (range 8)]
                                      (texture  (aget player-sheet 1 i))))
             :talk (animation 0.2 (for [i (range 8)]
                                      (texture  (aget talk-sheet 0 i))))
             
             :baseline 95
             :origin-x 9 
             :origin-y 0 
             :scaled true
             :actions []
             :x 150 :y 95
             :id "ego"}]
    (merge (texture (animation! (:right ego) :get-key-frame 0.25)) ego)))

(defn update-ego [screen entities ego]
  (if-let [action (first (:actions ego))]
    (action screen entities)
    entities))

(defn scaler-fn-with-baseline [baseline minimum-size & [maximum-size]]
  (let [maximum-size (or maximum-size 1.0)]
    (fn [y]
      (if (< y baseline) maximum-size
          (let [percent-complete (- 1.0 (/ (- y baseline) (- +screen-height+ baseline)))
                range (+ (* percent-complete (- maximum-size minimum-size)) minimum-size)]
            range)))))


(defscreen scene
  :on-show
  (fn [screen entities]
    (update! screen :renderer (stage) :camera (orthographic))
    (let [
          _ (input! :set-cursor-image (cursor "cursor.png" :walk) 0 0)
          background (texture "bg5.png")
          background-trees (texture "background-trees.png")
          house (texture "house.png")
          overdirt (texture "overdirt.png")
          music (sound "town-music.mp3")
          ;; _ (sound! music :loop)
          ]
      {
       :cursor {:id "cursor" :current :walk }
       :background (assoc {} 
                     :collision (advent.pathfind/map-from-resource "pathfind-test-big.png")
                     :baseline 0
                     :mouse-overrides [{:mouse-in? (zone/box 300 131 320 224) 
                                        :cursor-override :right
                                        :go-to [319 160]}
                                       {:mouse-in? (zone/box 60 180 224 240) 
                                        :cursor-override :up
                                        :go-to [137 204]}
                                       {:mouse-in? (zone/box 0 40 20 140) 
                                        :cursor-override :left
                                        :go-to [0 80]}]
                     :interactions [{:mouse-in? (zone/box 258 100 281 160)
                                     :look (fn [screen entities [x y]]
                                                (assoc-in entities [:ego :actions] [(actions/stop :ego)
                                                                                    (actions/talk :ego (str "The last time I went through that door, Fangald turned me into a frog."))]))}]
                     :scale-fn (scaler-fn-with-baseline 110 0.10 1.00)
                     :layers [(assoc background :x 0 :y 0 :baseline 0)
                              (assoc house :x 0 :y 0 :baseline 122)
                              (assoc overdirt :x 0 :y 0 :baseline 240)
                              (assoc background-trees :x 0 :y 0 :baseline 44)])
       :ego (get-ego screen)
       :fps (assoc (label "0" (color :white) ) :x 5 :baseline 9000)
       }))
  
  :on-render
  (fn [screen [entities]]
    (clear!)
    (let [entities (update-ego screen entities (:ego entities))
          _ (label! (:fps entities) :set-text (str (game :fps)))
          entities (if (get-in entities [:ego :anim])
                     (update-in entities [:ego] #(merge % (animation->texture screen (:anim %))))
                     entities)]
      (render! screen (sort-by :baseline (concat (vals entities) (get-in entities [:background :layers]))))
      entities))

  :on-resize (fn [screen entities]
               (size! screen 320 240))

  :on-mouse-moved
  (fn [screen [entities]]
    (let [{:keys [x y]} (input->screen screen {:x (:input-x screen) :y (:input-y screen)})]
      (if-let [mouse-override (first (filter #((:mouse-in? %) x y) (get-in entities [:background :mouse-overrides])))]
        (when (not (get-in entities [:cursor :override]))
          (do (input! :set-cursor-image (cursor "cursor.png" (:cursor-override mouse-override)) 0 0)
              (assoc-in entities [:cursor :override] true)))

        (when (get-in entities [:cursor :override])
          (do (input! :set-cursor-image (cursor "cursor.png" (get-in entities [:cursor :current])) 0 0)
              (assoc-in entities [:cursor :override] false))))))

  :on-touch-down (fn [screen [entities]]
                   (if (= (button-code :right) (:button screen))
                     (right-click screen entities)
                     (left-click screen entities))))
