(ns sekai.core.space
  (:require [sekai.core.gamestate :refer [game-state]]
            [sekai.math.vectors :as vect]
            [sekai.entity.entity :as entity]))

(defn coords->vec [point]
  [(or (:x point) 0) (or (:y point) 0) (or (:z point) 0)])

(defn vec->coords [vec]
  (let [vec (vect/vecn->m 3 vec)]
    {:x (nth vec 0) :y (nth vec 1) :z (nth vec 2)}))

(defn camera->world
  "Position of camera in world-coordinates."
  [] (:camera @game-state))

(defn canvas-size [] (-> @game-state :canvas :size))

(defn camera->screen
  "Camera position in screen-coordinates <-> center of screen."
  [] (let [cs (canvas-size)]
       (->> [(:width cs) (:height cs) 0] (vect/div-s 2)
            first vec->coords)))

(defn translate-screen
  "Translate screenspace coords by (x y) in blockspace."
  [s-orig b-trans]
  (let [tile (-> @game-state :settings :tile-size)
        halftile (/ tile 2)
        [trans-x] (vect/mult-s (:x b-trans) [tile (- halftile) 0])
        [trans-y] (vect/mult-s (:y b-trans) [(- tile) (- halftile) 0])
        [trans-z] (vect/mult-s (:z b-trans) [0 tile 0])]

    (->> s-orig coords->vec
         (vect/add trans-x) (vect/add trans-y) (vect/add trans-z)
         vec->coords)))

(defn world->screen
  "World-coordinates to screen-coordinates."
  [w-coords]
  (let [pos (coords->vec w-coords)
        rel (vect/sub pos [0 0 0])]
    (translate-screen (camera->screen) (vec->coords rel))))

(defn entity->world
  "Entity position in world-coordinates."
  [eid]
  (entity/get-component eid :position))

(defn entity->screen
  "Entity position in screen-coordinates."
  [eid]
  (world->screen (entity->world eid)))

(defn dist2screen
  "Distance between entity and screen in world-coordinates."
  [eid]
  (reduce + (coords->vec (entity->world eid))))

(defn move-entity!
  [eid position]
  (entity/update-component!
   eid :position
   (fn [old] (merge old position))))
