import "./vendor"
import sound from "./sound"
import Fire from "./fire"
import DB from "./db"
import $ from "jquery"
import _ from "ramda"
import Notifications from "./notifications"
import cryptoRandomString from "crypto-random-string"
import localforage from "localforage"
import MutationSummary from "mutation-summary"
import {Kefir} from "kefir"
import {Main} from "elm/Main.elm"

const isDevelopmentMode = process.env["NODE_ENV"] === "development"
const env = process.env
const npmPackageVersion = env["npm_package_version"]

const mutationObserverFocusSelectorStream = Kefir.stream(emitter => {
  
  const focusableEntityListItemSelector = ".focusable-list-item[tabindex=0]"
  const autoFocusSelector = ".auto-focus"
  const observer = new MutationSummary({
    callback: summaries => {
      // console.log(summaries)
      
      const autoFocusSummaryAdded = summaries[0].added
      if (!_.isEmpty(autoFocusSummaryAdded)) {
        //note: delaying auto-focus to ensure that it takes priority.
        setTimeout(() => emitter.emit(".auto-focus"), 0)
      }
      
      const focusInEntitySummary = summaries[1]
      const focusInEntitySummaryAdded = focusInEntitySummary.added
      if (!_.isEmpty(focusInEntitySummaryAdded)) {
        // console.log("focusInEntitySummary.added", focusInEntitySummaryAdded)
        emitter.emit(".focusable-list-item[tabindex=0]")
      }
    },
    queries: [{element: autoFocusSelector},
      {element: focusableEntityListItemSelector},
    ],
  })
})

window.appBoot = async function appBoot(elmMain = Main) {
  
  const deviceId = getOrCreateDeviceId()
  const $elm = $("#elm-container")
  // $elm.trap();
  
  $elm.on("keydown", `.entity-list`, e => {
    // console.log(e.keyCode, e.key, e.target, e);
    
    // prevent document scrolling
    if (e.key === " " || e.key === "ArrowUp" || e.key === "ArrowDown") {
      e.preventDefault()
    }
    
  })
  
  
  const db = await DB()
  
  const store = localforage.createInstance({
    name: "SimpleGTD.com offline store",
  });
  
  
  const getOfflineStore = async () => {
    const storeKeys = await store.keys()
    const storeValues = await _.compose(
        ps => Promise.all(ps), _.map(k => store.getItem(k)),
    )(storeKeys)
    return _.zipObj(storeKeys, storeValues)
  }
  const initialOfflineStore = await getOfflineStore()
  // console.log(initialOfflineStore)
  
  const flags = _.merge({
    now: Date.now(),
    pouchDBRemoteSyncURI: localStorage.getItem("pouchdb.remote-sync-uri") || "",
    developmentMode: isDevelopmentMode,
    config: {
      debug: WEBPACK_DEV_SERVER,
      deviceId,
      npmPackageVersion,
      isDevelopmentMode,
      initialOfflineStore,
    },
  }, db.allDocsMap)
  
  
  const app = elmMain
      .embed(document.getElementById("elm-container"), flags)
  
  
  const fire = Fire.setup(app, _.values(db.list), deviceId)
  
  db.setupApp(app)
  
  
  app.ports["persistToOfflineStore"].subscribe(([key, value]) => {
    store.setItem(key, value).catch(console.error)
  });
  
  
  Notifications.setup(fire, app).catch(console.error)
  
  const portFocusSelectorStream =
      Kefir.stream(emitter => {
        app.ports["focusSelector"].subscribe((selector) => {
          // console.log("port: focusSelector received selector", selector)
          emitter.emit(selector)
        })
      })
  
  const addMetadataToFocusSelectorStream =
      (stream, streamName) => stream.map(selector => ({streamName, selector}))
  
  const focusSelectorStreams =
      [addMetadataToFocusSelectorStream(
          portFocusSelectorStream,
          "portFocusSelectorStream",
      ),
       addMetadataToFocusSelectorStream(
           mutationObserverFocusSelectorStream,
           "mutationObserverFocusSelectorStream",
       )]
  Kefir.merge(focusSelectorStreams)
       .observe({
         value(options) {
           const $toFocus = $(options.selector).first()
      
           // console.log("[Kefir] focusSelector", _.merge(options, {
           // dataKey: $toFocus.data("key"),
           // }))
      
           $toFocus.focus()
         },
       })
  
  app.ports["positionPopupMenu"].subscribe((ofSelector) => {
    requestAnimationFrame(() => {
      const $popup = $("#popup-menu")
      $popup.position({
        my: "right top",
        at: "right top",
        of: $(ofSelector),
        within: ".overlay",
        collision: "fit",
      })
      $popup.find(".auto-focus").first().focus()
      
      const focusableSelector = ":focusable, input:focusable"
      $popup.on("keydown", focusableSelector, function (e) {
        if (e.key !== "Tab") return
        const $focusable = $popup.find(focusableSelector)
        
        const first = $focusable.first().get(0)
        const last = $focusable.last().get(0)
        const dateTimeInputSelector = `input[type="date"], input[type="time"]`
        
        if (e.shiftKey) {
          
          if (this === first) {
            e.preventDefault()
            e.stopPropagation()
            last.focus()
          } else if ($(this).is(dateTimeInputSelector)) {
            e.preventDefault()
            e.stopPropagation()
            $focusable.get($.inArray(this, $focusable) - 1).focus()
          }
        }
        else {
          
          
          if (this === last) {
            e.preventDefault()
            e.stopPropagation()
            first.focus()
          } else if ($(this).is(dateTimeInputSelector)) {
            e.preventDefault()
            e.stopPropagation()
            $focusable.get($.inArray(this, $focusable) + 1).focus()
          }
        }
      })
    })
  })
  
  
  app.ports["startAlarm"].subscribe(() => {
    sound.start()
  })
  
  
  app.ports["stopAlarm"].subscribe(() => {
    sound.stop()
  })
}

function getOrCreateDeviceId() {
  let deviceId = localStorage.getItem("device-id")
  if (!deviceId) {
    deviceId = cryptoRandomString(64)
    localStorage.setItem("device-id", deviceId)
  }
  return deviceId
}

function getOrCreateFirstVisit() {
  let firstVisit = localStorage.getItem("first-visit")
  if (!firstVisit) {
    localStorage.setItem("first-visit", "false")
  }
  return !!firstVisit
}

@@ -3288,32 +3288,34 @@
 ctor)%0A          
+  
 emitter.emit(sel
@@ -3847,24 +3847,332 @@
 (options) %7B%0A
+           // todo: adding any delay causes entity list focus to go haywire.%0A           // even in focus selector port.%0A           // we need to completely control focus on entity list.%0A           // can't depended on mutation observer for the same.%0A           // can't have%0A           // setTimeout(()=%3E%7B%0A  
            c
@@ -4213,29 +4213,27 @@
 ).first()%0A  
-  
+%0A
   
-%0A
            /
@@ -4301,16 +4301,18 @@
         
+  
 // dataK
@@ -4348,16 +4348,18 @@
         
+  
 // %7D))%0A 
@@ -4355,29 +4355,27 @@
    // %7D))%0A  
-  
+%0A
   
-%0A
            $
@@ -4382,32 +4382,51 @@
 toFocus.focus()%0A
+           // %7D,0)%0A
          %7D,%0A    

fix focus entity list