// If you want to use Phoenix channels, run `mix help phx.gen.channel`
// to get started and then uncomment the line below.
// import "./user_socket.js"

// You can include dependencies in two ways.
//
// The simplest option is to put them in assets/vendor and
// import them using relative paths:
//
//     import "../vendor/some-package.js"
//
// Alternatively, you can `npm install some-package --prefix assets` and import
// them using a path starting with the package name:
//
//     import "some-package"
//
// If you have dependencies that try to import CSS, esbuild will generate a separate `app.css` file.
// To load it, simply add a second `<link>` to your `root.html.heex` file.

// Include phoenix_html to handle method=PUT/DELETE in forms and buttons.
import "phoenix_html"
// Establish Phoenix Socket and LiveView configuration.
import {Socket} from "phoenix"
import {LiveSocket} from "phoenix_live_view"
import {hooks as colocatedHooks} from "phoenix-colocated/simpleshop_theme"
import topbar from "../vendor/topbar"

// Hook to sync color picker and text input
const ColorSync = {
  mounted() {
    const picker = this.el.querySelector('input[type="color"]')
    const text = this.el.querySelector('input[type="text"]')

    if (picker && text) {
      picker.addEventListener('input', (e) => {
        text.value = e.target.value
      })

      text.addEventListener('input', (e) => {
        picker.value = e.target.value
      })
    }
  }
}

// Hook to persist cart to session via API
const CartPersist = {
  mounted() {
    this.handleEvent("persist_cart", ({items}) => {
      const csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
      fetch("/api/cart", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "x-csrf-token": csrfToken
        },
        body: JSON.stringify({items})
      })
    })
  }
}

// Hook for accessible cart drawer (WAI-ARIA dialog pattern)
const CartDrawer = {
  mounted() {
    this.triggerElement = null
    this.boundKeydown = this.handleKeydown.bind(this)
    this.boundTouchmove = this.handleTouchmove.bind(this)
    this.scrollY = 0
    this.isOpen = this.el.classList.contains('open')

    if (this.isOpen) {
      this.lockScroll()
      document.addEventListener('keydown', this.boundKeydown)
    }
  },

  updated() {
    const nowOpen = this.el.classList.contains('open')
    if (nowOpen && !this.isOpen) {
      this.onOpen()
    } else if (!nowOpen && this.isOpen) {
      this.onClose()
    }
    this.isOpen = nowOpen
  },

  lockScroll() {
    // Store current scroll position
    this.scrollY = window.scrollY

    // Lock body scroll (works on mobile too)
    document.body.style.position = 'fixed'
    document.body.style.top = `-${this.scrollY}px`
    document.body.style.left = '0'
    document.body.style.right = '0'
    document.body.style.overflow = 'hidden'

    // Prevent touchmove on document (extra safety for iOS)
    document.addEventListener('touchmove', this.boundTouchmove, { passive: false })
  },

  unlockScroll() {
    // Restore body scroll
    document.body.style.position = ''
    document.body.style.top = ''
    document.body.style.left = ''
    document.body.style.right = ''
    document.body.style.overflow = ''

    // Restore scroll position
    window.scrollTo(0, this.scrollY)

    // Remove touchmove listener
    document.removeEventListener('touchmove', this.boundTouchmove)
  },

  handleTouchmove(e) {
    // Allow scrolling inside the drawer itself
    if (this.el.contains(e.target)) {
      return
    }
    e.preventDefault()
  },

  onOpen() {
    // Store trigger for focus return
    this.triggerElement = document.activeElement

    // Lock scroll
    this.lockScroll()

    // Focus first focusable element (close button)
    const firstFocusable = this.el.querySelector(
      'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
    )
    if (firstFocusable) {
      setTimeout(() => firstFocusable.focus(), 50)
    }

    // Enable focus trap and Escape handling
    document.addEventListener('keydown', this.boundKeydown)
  },

  onClose() {
    // Unlock scroll
    this.unlockScroll()

    // Remove keyboard listener
    document.removeEventListener('keydown', this.boundKeydown)

    // Return focus to trigger element
    if (this.triggerElement) {
      this.triggerElement.focus()
    }
  },

  handleKeydown(e) {
    // Close on Escape - let server handle the state change
    if (e.key === 'Escape') {
      this.pushEvent("close_cart_drawer")
      return
    }

    // Focus trap on Tab
    if (e.key === 'Tab') {
      const focusable = this.el.querySelectorAll(
        'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
      )
      const first = focusable[0]
      const last = focusable[focusable.length - 1]

      if (e.shiftKey && document.activeElement === first) {
        e.preventDefault()
        last.focus()
      } else if (!e.shiftKey && document.activeElement === last) {
        e.preventDefault()
        first.focus()
      }
    }
  },

  destroyed() {
    document.removeEventListener('keydown', this.boundKeydown)
    document.removeEventListener('touchmove', this.boundTouchmove)
    document.body.style.position = ''
    document.body.style.top = ''
    document.body.style.left = ''
    document.body.style.right = ''
    document.body.style.overflow = ''
  }
}

// Hook for PDP image lightbox
const Lightbox = {
  mounted() {
    const dialog = this.el
    const lightboxImage = dialog.querySelector('#lightbox-image')
    const lightboxCounter = dialog.querySelector('#lightbox-counter')

    // Get images from data attribute
    const getImages = () => {
      try {
        return JSON.parse(dialog.dataset.images || '[]')
      } catch {
        return []
      }
    }

    const getCurrentIndex = () => parseInt(dialog.dataset.currentIndex || '0', 10)
    const setCurrentIndex = (idx) => { dialog.dataset.currentIndex = idx.toString() }

    const updateImage = () => {
      const images = getImages()
      const idx = getCurrentIndex()
      if (images.length > 0 && lightboxImage) {
        lightboxImage.src = images[idx]
        if (lightboxCounter) {
          lightboxCounter.textContent = `${idx + 1} / ${images.length}`
        }
      }
    }

    const nextImage = () => {
      const images = getImages()
      const newIdx = (getCurrentIndex() + 1) % images.length
      setCurrentIndex(newIdx)
      updateImage()
    }

    const prevImage = () => {
      const images = getImages()
      const newIdx = (getCurrentIndex() - 1 + images.length) % images.length
      setCurrentIndex(newIdx)
      updateImage()
    }

    const openLightbox = () => {
      updateImage()
      dialog.showModal()
    }

    const closeLightbox = () => {
      dialog.close()
    }

    // Event listeners for custom events dispatched from LiveView.JS
    dialog.addEventListener('pdp:open-lightbox', openLightbox)
    dialog.addEventListener('pdp:close-lightbox', closeLightbox)
    dialog.addEventListener('pdp:next-image', nextImage)
    dialog.addEventListener('pdp:prev-image', prevImage)

    // Close on clicking backdrop
    dialog.addEventListener('click', (e) => {
      if (e.target === dialog) {
        closeLightbox()
      }
    })

    // Keyboard navigation
    dialog.addEventListener('keydown', (e) => {
      if (e.key === 'ArrowRight') {
        nextImage()
      } else if (e.key === 'ArrowLeft') {
        prevImage()
      } else if (e.key === 'Escape') {
        closeLightbox()
      }
    })

    // Store cleanup function
    this.cleanup = () => {
      dialog.removeEventListener('pdp:open-lightbox', openLightbox)
      dialog.removeEventListener('pdp:close-lightbox', closeLightbox)
      dialog.removeEventListener('pdp:next-image', nextImage)
      dialog.removeEventListener('pdp:prev-image', prevImage)
    }
  },

  destroyed() {
    if (this.cleanup) {
      this.cleanup()
    }
  }
}

const ProductImageScroll = {
  mounted() {
    const container = this.el.parentElement
    const dots = container.querySelector('.product-image-dots')
    const spans = dots ? dots.querySelectorAll('.product-image-dot') : []
    const lightbox = container.parentElement.querySelector('dialog')
    const thumbs = container.parentElement.querySelector('.pdp-gallery-thumbs')
    const thumbButtons = thumbs ? thumbs.querySelectorAll('.pdp-thumbnail') : []
    const imageCount = this.el.children.length

    this.el.addEventListener('scroll', () => {
      const index = Math.round(this.el.scrollLeft / this.el.offsetWidth)
      spans.forEach((dot, i) => {
        dot.classList.toggle('product-image-dot-active', i === index)
      })
      thumbButtons.forEach((btn, i) => {
        btn.classList.toggle('pdp-thumbnail-active', i === index)
      })
      if (lightbox) lightbox.dataset.currentIndex = index.toString()
    }, {passive: true})

    this.el.addEventListener('pdp:scroll-to', (e) => {
      const index = e.detail.index
      this.el.scrollTo({left: index * this.el.offsetWidth, behavior: 'smooth'})
    })

    this.el.addEventListener('pdp:scroll-prev', () => {
      const current = Math.round(this.el.scrollLeft / this.el.offsetWidth)
      const target = (current - 1 + imageCount) % imageCount
      this.el.scrollTo({left: target * this.el.offsetWidth, behavior: 'smooth'})
    })

    this.el.addEventListener('pdp:scroll-next', () => {
      const current = Math.round(this.el.scrollLeft / this.el.offsetWidth)
      const target = (current + 1) % imageCount
      this.el.scrollTo({left: target * this.el.offsetWidth, behavior: 'smooth'})
    })
  }
}

// Hook for search modal keyboard navigation and shortcuts
const SearchModal = {
  mounted() {
    this.selectedIndex = -1

    this._globalKeydown = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key === "k") {
        e.preventDefault()
        if (this.isOpen()) {
          this.close()
        } else {
          this.open()
        }
      }
    }
    document.addEventListener("keydown", this._globalKeydown)

    this.el.addEventListener("keydown", (e) => {
      if (!this.isOpen()) return

      switch (e.key) {
        case "Escape":
          e.preventDefault()
          this.close()
          break
        case "ArrowDown":
          e.preventDefault()
          this.moveSelection(1)
          break
        case "ArrowUp":
          e.preventDefault()
          this.moveSelection(-1)
          break
        case "Enter":
          e.preventDefault()
          this.navigateToSelected()
          break
      }
    })
  },

  destroyed() {
    document.removeEventListener("keydown", this._globalKeydown)
  },

  updated() {
    this.selectedIndex = -1
    this.updateHighlight()
  },

  isOpen() {
    return this.el.style.display !== "none" && this.el.style.display !== ""
  },

  open() {
    this.el.style.display = "flex"
    this.pushEvent("open_search", {})
    const input = this.el.querySelector("#search-input")
    if (input) {
      input.focus()
      input.select()
    }
    this.selectedIndex = -1
    this.updateHighlight()
  },

  close() {
    this.el.style.display = "none"
    this.pushEvent("clear_search", {})
    this.selectedIndex = -1
    this.updateHighlight()
  },

  getResults() {
    return this.el.querySelectorAll('[role="option"]')
  },

  moveSelection(delta) {
    const results = this.getResults()
    if (results.length === 0) return

    this.selectedIndex += delta
    if (this.selectedIndex < -1) this.selectedIndex = results.length - 1
    if (this.selectedIndex >= results.length) this.selectedIndex = 0

    this.updateHighlight()
  },

  updateHighlight() {
    const results = this.getResults()
    results.forEach((r, i) => {
      const isSelected = i === this.selectedIndex
      r.style.background = isSelected ? "var(--t-surface-sunken)" : ""
      r.setAttribute("aria-selected", isSelected)
    })

    if (this.selectedIndex >= 0 && results[this.selectedIndex]) {
      results[this.selectedIndex].scrollIntoView({ block: "nearest" })
    }
  },

  navigateToSelected() {
    const results = this.getResults()
    const index = this.selectedIndex >= 0 ? this.selectedIndex : 0
    if (results[index]) {
      const link = results[index].querySelector("a")
      if (link) {
        this.el.style.display = "none"
        link.click()
      }
    }
  }
}

const csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
const liveSocket = new LiveSocket("/live", Socket, {
  params: {_csrf_token: csrfToken},
  hooks: {...colocatedHooks, ColorSync, Lightbox, CartPersist, CartDrawer, ProductImageScroll, SearchModal},
})

// Show progress bar on live navigation and form submits
topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"})
window.addEventListener("phx:page-loading-start", _info => topbar.show(300))
window.addEventListener("phx:page-loading-stop", _info => topbar.hide())

// Scroll preview frame to top when changing pages
window.addEventListener("phx:scroll-preview-top", (e) => {
  const previewFrame = document.querySelector('.preview-frame')
  if (previewFrame) {
    previewFrame.scrollTop = 0
  }
})

// connect if there are any LiveViews on the page
liveSocket.connect()

// expose liveSocket on window for web console debug logs and latency simulation:
// >> liveSocket.enableDebug()
// >> liveSocket.enableLatencySim(1000)  // enabled for duration of browser session
// >> liveSocket.disableLatencySim()
window.liveSocket = liveSocket

// The lines below enable quality of life phoenix_live_reload
// development features:
//
//     1. stream server logs to the browser console
//     2. click on elements to jump to their definitions in your code editor
//
if (process.env.NODE_ENV === "development") {
  window.addEventListener("phx:live_reload:attached", ({detail: reloader}) => {
    // Enable server log streaming to client.
    // Disable with reloader.disableServerLogs()
    reloader.enableServerLogs()

    // Open configured PLUG_EDITOR at file:line of the clicked element's HEEx component
    //
    //   * click with "c" key pressed to open at caller location
    //   * click with "d" key pressed to open at function component definition location
    let keyDown
    window.addEventListener("keydown", e => keyDown = e.key)
    window.addEventListener("keyup", e => keyDown = null)
    window.addEventListener("click", e => {
      if(keyDown === "c"){
        e.preventDefault()
        e.stopImmediatePropagation()
        reloader.openEditorAtCaller(e.target)
      } else if(keyDown === "d"){
        e.preventDefault()
        e.stopImmediatePropagation()
        reloader.openEditorAtDef(e.target)
      }
    }, true)

    window.liveReloader = reloader
  })
}

