             [frontend.components.drawings :as drawings]
             [frontend.components.shared :as shared]
             [frontend.env :as env]
+            [frontend.scroll :as scroll]
             [frontend.state :as state]
             [frontend.stefon :as stefon]
             [frontend.utils :as utils :include-macros true]
             [frontend.utils.github :refer [auth-url]]
+            [frontend.utils.seq :refer [select-in]]
             [goog.events]
             [goog.dom]
             [goog.style]

            [sablono.core :as html :refer-macros [html]])
  (:require-macros [frontend.utils :refer [defrender]]
                   [cljs.core.async.macros :as am :refer [go go-loop alt!]]
                   [dommy.macros :refer [sel1 node]]))

(defn maybe-set-state! [owner korks value]
  (when (not= (om/get-state owner korks) value)
    (om/set-state! owner korks value)))

(defn mount-scroll-handler [owner]
  (let [logo (om/get-node owner "center-logo")
        prolog-cta (om/get-node owner "prolog-cta")
        home-prolog (om/get-node owner "home-prolog")
        epilog-cta (om/get-node owner "epilog-cta")
        home-epilog (om/get-node owner "home-epilog")
        purpose-article (om/get-node owner "purpose-article")
        potential-article (om/get-node owner "potential-article")
        scroll-ch (om/get-state owner [:scroll-ch])
        scroll-handler #(let [vh (.-height (goog.dom/getViewportSize))
                              nav-height 70]
                          ;; we could optimize these, but calculating this is surprisingly fast (less than 10 ms)

                          (maybe-set-state! owner [:header-logo-visible] (neg? (.-bottom (.getBoundingClientRect logo))))
                          (maybe-set-state! owner [:header-cta-visible] (neg? (.-bottom (.getBoundingClientRect prolog-cta))))
                          (maybe-set-state! owner [:header-bkg-visible] (< (.-bottom (.getBoundingClientRect home-prolog)) nav-height))
                          (maybe-set-state! owner [:header-cta-invisible] (< (.-top (.getBoundingClientRect epilog-cta)) vh))
                          (maybe-set-state! owner [:header-bkg-invisible] (< (.-top (.getBoundingClientRect home-epilog)) nav-height))
                          (maybe-set-state! owner [:first-fig-animate] (< (.-bottom (.getBoundingClientRect purpose-article)) vh))
                          (maybe-set-state! owner [:second-fig-animate] (< (.-bottom (.getBoundingClientRect potential-article)) vh))
                          (maybe-set-state! owner [:header-bkg-scroller] (min (js/Math.abs (.-top (.getBoundingClientRect home-epilog)))
                                                                              (js/Math.abs (- nav-height (.-bottom (.getBoundingClientRect home-prolog))))
                                                                              nav-height)))]
    (om/set-state! owner [:scroll-key]
                   (goog.events/listen
                    js/window
                    "scroll"
                    #(put! scroll-ch %)))
    (go-loop []
             (when-let [event (<! scroll-ch)]
               (utils/swallow-errors (scroll-handler))
               (recur)))
    (scroll-handler)))

(def circle-logo
  (html

                 :tools #{:ruby :rails :postgres :javascript :node}
                 :position 4}))

(def nav-height 70)

(defn nav [data owner]
  (reify
    om/IDisplayName (display-name [_] "Home Nav")
    om/IRender
    (render [_]
      (let [controls-ch (om/get-shared owner [:comms :controls])]
        (html
         [:nav.home-nav {:style (if (> 70 (:header-bkg-scroller data))
                                  {:background-size (str "100% " (:header-bkg-scroller data) "px")}
                                  {})
                         :class (concat
                                 (when (:header-logo-visible data) ["logo-visible"])
                                 (when (:header-cta-visible data) ["cta-visible"])
                                 (when (:header-bkg-visible data) ["bkg-visible"])
                                 (when (:header-bkg-invisible data) ["bkg-invisible"])
                                 (when (:header-cta-invisible data) ["cta-invisible"]))}
          [:a.promo {:href "http://blog.circleci.com/continuous-delivery-with-docker-containers/"}
                                        ; "What is Continuous Integration?"
           "Learn how we support Docker."]
          [:a.login {:href (auth-url)
                     :on-click #(put! controls-ch [:track-external-link-clicked
                                                   {:event "Auth GitHub"
                                                    :properties {:source "header-log-in"}
                                                    :path (auth-url)}])}
           "Log In"]
          [:a.logo-circleci {:on-click #(put! controls-ch [:home-scroll-logo-clicked])}
           [:figure circle-logo]]
          [:a.action {:href (auth-url)
                      :role "button"
                      :on-click #(put! controls-ch [:track-external-link-clicked
                                                    {:event "Auth GitHub"
                                                     :properties {:source "header-cta"}
                                                     :path (auth-url)}])}
           "Sign Up Free"]])))))

(defn prolog [data owner {:keys [logo-visibility-callback
                                 cta-visibility-callback
                                 prolog-visibility-callback
                                 header-overlap-callback]}]
  (reify
    om/IDisplayName (display-name [_] "Home Prolog")
    om/IInitState (init-state [_] {:scroll-id (.getNextUniqueId (.getInstance IdGenerator))
                                   :logo-visible? (atom nil)
                                   :cta-visible? (atom nil)
                                   :prolog-visible? (atom nil)
                                   :header-overlap-px (atom 0)})
    om/IDidMount
    (did-mount [_]
      (scroll/register-fn
       (om/get-state owner :scroll-id)
       #(let [logo (om/get-node owner "center-logo")
              cta (om/get-node owner "prolog-cta")
              prolog (om/get-node owner "home-prolog")
              logo-visible? (neg? (.-bottom (.getBoundingClientRect logo)))
              cta-visible? (neg? (.-bottom (.getBoundingClientRect cta)))
              prolog-visible? (>= (.-bottom (.getBoundingClientRect prolog)) nav-height)
              cta-visible? (neg? (.-bottom (.getBoundingClientRect cta)))
              header-overlap-px (- nav-height (.-bottom (.getBoundingClientRect prolog)))
              ;; normalize the overlap
              header-overlap-px (min nav-height (max 0 header-overlap-px))]
          (when-not (= logo-visible? @(om/get-state owner :logo-visible?))
            (reset! (om/get-state owner :logo-visible?) logo-visible?)
            (logo-visibility-callback logo-visible?))
          (when-not (= cta-visible? @(om/get-state owner :cta-visible?))
            (reset! (om/get-state owner :cta-visible?) cta-visible?)
            (cta-visibility-callback cta-visible?))
          (when-not (= prolog-visible? @(om/get-state owner :prolog-visible?))
            (reset! (om/get-state owner :prolog-visible?) prolog-visible?)
            (prolog-visibility-callback prolog-visible?))
          (when-not (= header-overlap-px @(om/get-state owner :header-overlap-px))
            (reset! (om/get-state owner :header-overlap-px) header-overlap-px)
            (header-overlap-callback header-overlap-px)))))
    om/IWillUnmount (will-unmount [_] (scroll/deregister-fn (om/get-state owner :scroll-id)))
    om/IRender
    (render [_]
      (let [controls-ch (om/get-shared owner [:comms :controls])]
        (html
         [:section.home-prolog {:ref "home-prolog"}
          [:a.home-action {:href (auth-url)
                           :role "button"
                           :ref "prolog-cta"
                           :on-click #(put! controls-ch [:track-external-link-clicked {:event "Auth GitHub"
                                                                                       :properties {:source "prolog-cta"}
                                                                                       :path (auth-url)}])}
           "Sign Up Free"]
          [:div.home-cover]
          [:div.home-top-shelf]
          [:div.home-slogans
           [:h1.slogan.proverb {:item-prop "Ship better code, faster."
                                :alt       "Let's just authorize first."}
            "Ship better code, faster."]
           [:h3.slogan.context {:item-prop "You have a product to focus on, let Circle handle your"
                                :alt       "Signing up using your GitHub login lets us start really fast."}
            "You have a product to focus on, let Circle handle your"]
           [:h3.slogan.context {:item-prop "Continuous Integration & Deployment."
                                :alt       "Currently, we must request permissions in bulk."}
            "Continuous Integration & Deployment."]]
          [:div.home-avatars
           [:div.avatars
            [:div.avatar-github
             (common/ico :github)]
            [:div.avatar-circle {:ref "center-logo"}
             (common/ico :logo)]]]
          [:div.home-bottom-shelf
           [:a {:on-click #(put! controls-ch [:home-scroll-1st-clicked])}
            "Learn more"
            (common/ico :chevron-down)]]])))))

(defn purpose [data owner]
  (reify
    om/IDisplayName (display-name [_] "Home Purpose")
    om/IInitState (init-state [_] {:scroll-id (.getNextUniqueId (.getInstance IdGenerator))})
    om/IDidMount
    (did-mount [_]
      (scroll/register-fn
       (om/get-state owner :scroll-id)
       #(let [article (om/get-node owner "purpose-article")
              vh (.-height (goog.dom/getViewportSize))
              animate? (< (.-bottom (.getBoundingClientRect article)) vh)]
          (maybe-set-state! owner [:first-fig-animate] animate?))))
    om/IWillUnmount (will-unmount [_] (scroll/deregister-fn (om/get-state owner :scroll-id)))
    om/IRender
    (render [_]
      (let [controls-ch (om/get-shared owner [:comms :controls])]
        (html
         [:section.home-purpose {:class (when (om/get-state owner [:first-fig-animate]) "animate")}
          [:div.home-top-shelf]
          [:div.home-purpose-content
           [:div.home-drawings
            [:figure]
            [:figure]
            [:figure drawings/drawing-dashboard]]
           [:div.home-articles
            [:article {:ref "purpose-article"}
             [:h1 "Launches are dead, long live iteration."]
             [:p "We believe that rapid iteration, tight feedback loops, and team communication are the keys to a great product workflow.
                       That's why we designed the world's leading continuous integration and delivery solution.
                       Continuous integration and delivery is revolutionizing the way development teams operate by reducing barriers between your ideas and your production code.
                       Remember, it doesn't count until it ships."]
             [:p
              [:a.shopify-link {:href "/stories/shopify"}
               "See how Shopify does it"
               (common/ico :slim-arrow-right)]]]]]
          [:div.home-bottom-shelf
           [:a {:on-click #(put! controls-ch [:home-scroll-2nd-clicked])}
            ;; "Continue" ; hold off on this line of copy, it's cleanr w/o
            (common/ico :chevron-down)]]])))))

(defn practice [app owner]
  (reify
    om/IDisplayName (display-name [_] "Home Practice")
    om/IRender
    (render [_]
      (let [controls-ch (om/get-shared owner [:comms :controls])
            selected-customer (get-in app state/customer-logo-customer-path :shopify)
            selected-toolset (get-in app state/selected-toolset-path :languages)]
        (html
         [:section.home-practice
          (let [hovered-customer (om/get-state owner [:hovered-customer])
                tools (get-in customer-brands [hovered-customer :tools] #{})]
            [:div.practice-tools
             [:article
              (for [[toolset template] supported-tools]
                (html ; use html in for loops for perf
                 [:div.supported-tools {:class (when (= selected-toolset toolset) "active")}
                  [:div.supported-tools-upper
                   (for [tool (:upper template)]
                     (html
                      [:div.supported-tool {:class (when (contains? tools tool) "hover")
                                            :alt (name tool)}
                       [:figure
                        [:svg {:class (str "tool-logo-" (name tool))
                               :x "0" :y "0" :view-box "0 0 100 100"}
                         [:path {:d (get tools-logos tool)}]]]]))]
                  [:div.supported-tools-lower
                   (for [tool (:lower template)]
                     (html
                      [:div.supported-tool {:class (when (contains? tools tool) "hover")
                                            :alt (name tool)}
                       [:figure
                        [:svg {:class (str "tool-logo-" (name tool))
                               :x "0" :y "0" :view-box "0 0 100 100"}
                         [:path {:d (get tools-logos tool)}]]]]))]]))]])

          [:div.practice-articles
           [:article
            [:h1 "Devs rely on us to just work; we support the right tools."]
            [:p
             (for [toolset ["Languages" "databases" "queues" "browsers" "deployment"]]
               (html
                [:a {:on-mouse-enter #(put! controls-ch [:toolset-clicked {:toolset (keyword (str/lower-case toolset))}])} toolset] ", "))
             "we support all of your tools.
              If it runs on Linux, then it will work on CircleCI.
              We'll even be around to help you install your own tools.
              The best development teams in the world trust us as their continuous integration and delivery solution because of our unmatched support and our ability to scale with them.
              We're built for teams."]]]
          [:div.practice-customers
           [:article
            [:div.customers-brands {:class (str "selected-" (get-in customer-brands [selected-customer :position]))}
             (for [[customer template] customer-brands]
               (html
                [:a.customers-brand {:on-click #(put! controls-ch [:customer-logo-clicked {:customer customer}])
                                     :on-mouse-enter #(om/set-state! owner [:hovered-customer] customer)
                                     :on-mouse-leave #(om/set-state! owner [:hovered-customer] nil)}
                 (get customer-logos customer)]))]
            [:div.quote-card
             [:p (get-in customer-brands [selected-customer :quote])]
             [:footer
              [:img {:src (stefon/asset-path (get-in customer-brands [selected-customer :cite-avatar]))}]
              [:cite
               (get-in customer-brands [selected-customer :cite])
               [:br]
               (get-in customer-brands [selected-customer :cite-title])
               " at "
               (get-in customer-brands [selected-customer :name])]]]]]
          [:div.home-bottom-shelf
           [:a {:on-click #(put! controls-ch [:home-scroll-3rd-clicked])}
            ;; "Continue" ; hold off on this line of copy, it's cleanr w/o
            (common/ico :chevron-down)]]])))))

(defn potential [data owner]
  (reify
    om/IDisplayName (display-name [_] "Home Potential")
    om/IInitState (init-state [_] {:scroll-id (.getNextUniqueId (.getInstance IdGenerator))})
    om/IDidMount
    (did-mount [_]
      (scroll/register-fn
       (om/get-state owner :scroll-id)
       #(let [article (om/get-node owner "potential-article")
              vh (.-height (goog.dom/getViewportSize))
              animate? (< (.-bottom (.getBoundingClientRect article)) vh)]
          (maybe-set-state! owner [:second-fig-animate] animate?))))
    om/IWillUnmount (will-unmount [_] (scroll/deregister-fn (om/get-state owner :scroll-id)))
    om/IRender
    (render [_]
      (let [controls-ch (om/get-shared owner [:comms :controls])]
        (html
         [:section.home-potential {:class (when (om/get-state owner [:second-fig-animate]) "animate")}
          [:div.home-top-shelf]
          [:div.home-potential-content
           [:div.home-articles
            [:article {:ref "potential-article"}
             [:h1 "Look under the hood & check the bullet points."]
             [:div.home-potential-bullets
              [:ul
               [:li "Quick & easy setup"]
               [:li "Lightning fast builds"]
               [:li "Deep Customization"]
               [:li "Easy debugging"]]
              [:ul
               [:li "Smart notifications"]
               [:li "Loving support"]
               [:li "Automatic parallelization"]
               [:li "Continuous Deployment"]]
              [:ul
               [:li "Build artifacts"]
               [:li "Clean build environments"]
               [:li "GitHub Integration"]
               [:li "Open Source Support"]]]]]
           [:div.home-drawings
            [:figure]
            [:figure]
            [:figure drawings/draw-build-large]]]
          [:div.home-bottom-shelf
           [:a {:on-click #(put! controls-ch [:home-scroll-4th-clicked])}
            ;; "Continue" ; hold off on this line of copy, it's cleanr w/o
            (common/ico :chevron-down)]]])))))

(defn epilog [data owner {:keys [cta-visibility-callback
                                 epilog-visibility-callback
                                 header-overlap-callback]}]
  (reify
    om/IDisplayName (display-name [_] "Home Epilog")
    om/IInitState (init-state [_] {:scroll-id (.getNextUniqueId (.getInstance IdGenerator))
                                   :cta-visible? (atom nil)
                                   :epilog-visible? (atom nil)
                                   :header-overlap-px (atom 0)})
    om/IDidMount
    (did-mount [_]
      (scroll/register-fn
       (om/get-state owner :scroll-id)
       #(let [vh (.-height (goog.dom/getViewportSize))
              cta (om/get-node owner "epilog-cta")
              epilog (om/get-node owner "home-epilog")
              cta-visible? (< (.-top (.getBoundingClientRect cta)) vh)
              epilog-visible? (< (.-top (.getBoundingClientRect epilog)) nav-height)
              header-overlap-px (Math/abs (.-top (.getBoundingClientRect epilog)))
              ;; normalize the overlap
              header-overlap-px (utils/inspect (min nav-height (max 0 header-overlap-px)))]
          (when-not (= cta-visible? @(om/get-state owner :cta-visible?))
            (reset! (om/get-state owner :cta-visible?) cta-visible?)
            (cta-visibility-callback cta-visible?))
          (when-not (= epilog-visible? @(om/get-state owner :epilog-visible?))
            (reset! (om/get-state owner :epilog-visible?) epilog-visible?)
            (epilog-visibility-callback epilog-visible?))
          (when-not (= header-overlap-px @(om/get-state owner :header-overlap-px))
            (reset! (om/get-state owner :header-overlap-px) header-overlap-px)
            (header-overlap-callback header-overlap-px)))))
    om/IWillUnmount (will-unmount [_] (scroll/deregister-fn (om/get-state owner :scroll-id)))
    om/IRender
    (render [_]
      (let [controls-ch (om/get-shared owner [:comms :controls])]
        (html
         [:section.home-epilog {:ref "home-epilog"}
          [:a.home-action {:href (auth-url)
                           :ref "epilog-cta"
                           :role "button"
                           :on-click #(put! controls-ch [:track-external-link-clicked {:event "Auth GitHub"
                                                                                       :properties {:source "epilog-cta"}
                                                                                       :path (auth-url)}])}
           "Sign Up Free"]
          [:div.home-cover]
          [:div.home-top-shelf]
          [:div.home-slogans
           [:h1.slogan.proverb {:item-prop "So, ready to ship faster?"
                                :alt       "Let's just authorize first."}
            "So, ready to ship faster?"]
           [:h3.slogan.context {:item-prop "Next you'll just need to sign in using your GitHub account."
                                :alt       "Signing up using your GitHub login lets us start really fast."}
            "Next you'll just need to sign in using your GitHub account."]
           [:h3.slogan.context {:item-prop "Still not convinced yet? Check out our pricing."
                                :alt       "Currently, we must request permissions in bulk."}
            "Still not convinced yet? Check out our "
            [:a {:href "pricing"} "pricing"]
            "."]]
          [:div.home-avatars
           [:div.avatars
            [:div.avatar-github
             (common/ico :github)]
            [:div.avatar-circle
             (common/ico :logo)]]]
          [:div.home-bottom-shelf
           [:span.home-footer-bait
            "About Us"
            (common/ico :chevron-down)]
           [:div.home-footer
            [:div.home-footer-logo
             (common/ico :logo)]
            [:nav.home-footer-about
             [:h5 "CircleCI"]
             [:a {:href "/tour"} "Tour"]
             [:a {:href "/about"} "About"]
             [:a "Support"]
             [:a {:href "/about#contact"} "Press"]
             [:a {:href "/jobs"} "Jobs"]
             [:a {:href "http://blog.circleci.com"} "Blog"]]
            [:nav.home-footer-product
             [:h5 "Product"]
             [:a {:href "/pricing"} "Pricing"]
             [:a {:href "/docs"} "Documentation"]
             [:a {:href "/privacy"} "Privacy"]
             [:a {:href "/security"} "Security"]
             [:a {:href "/enterprise"} "Enterprise"]
             [:a {:href "/changelog"} "Changelog"]]
            [:nav.home-footer-contact
             [:h5 "Contact"]
             [:a {:href "https://twitter.com/circleci"} "Twitter"]
             [:a {:href "mailto:sayhi@circleci.com"} "Email"]
             [:a {:href ""} "Support Chat"]
             [:a {:href ""} "Phone"]
             [:a {:href "https://goo.gl/maps/uhkLn"} "San Francisco, CA"]]]]])))))

(defn home [app owner]
  (reify
    om/IDisplayName (display-name [_] "Homepage B")
    om/IInitState
    (init-state [_]
      {:header-logo-visible false
       :header-cta-visible false
       :header-bkg-visible false
       :header-cta-invisible false
       :header-bkg-invisible false})
    om/IRender
    (render [_]
      (html
       [:div.home.page
        ;; xxx less stuff in here
        (om/build nav (om/get-state owner))
        (om/build prolog {} {:opts {:logo-visibility-callback
                                    (fn [visible?]
                                      (om/set-state! owner :header-logo-visible visible?))
                                    :cta-visibility-callback
                                    (fn [visible?]
                                      (om/set-state! owner :header-cta-visible visible?))
                                    :prolog-visibility-callback
                                    (fn [visible?]
                                      (om/set-state! owner :header-bkg-visible (not visible?)))
                                    :header-overlap-callback
                                    (fn [visible-px]
                                      (om/set-state! owner :header-bkg-scroller visible-px))}})
        (om/build purpose {})
        (om/build practice (select-in app [state/customer-logo-customer-path
                                           state/selected-toolset-path]))
        ;; xxx: use state and determine animate elsewhere
        (om/build potential {})
        (om/build epilog {} {:opts {:cta-visibility-callback
                                    (fn [visible?]
                                      (om/set-state! owner :header-cta-invisible visible?))
                                    :epilog-visibility-callback
                                    (fn [visible?]
                                      (om/set-state! owner :header-bkg-invisible visible?))
                                    :header-overlap-callback
                                    (fn [visible-px]
                                      (om/set-state! owner :header-bkg-scroller visible-px))}})]))))
