async function customerStall(path) {
  const template = await loadTemplateAsync(path)

  Vue.component('customer-stall', {
    name: 'customer-stall',
    template,

    props: [
      'account',
      'login-dialog',
      'stall',
      'products',
      'stall-products',
      'product-detail',
      'change-page',
      'relays',
      'pool',
      'styles'
    ],
    data: function () {
      return {
        loading: false,
        isPwd: true,
        cart: {
          total: 0,
          size: 0,
          products: new Map()
        },
        cartMenu: [],
        hasNip07: false,
        customerPubkey: null,
        customerPrivkey: null,
        customerUseExtension: null,
        activeOrder: null,
        banner: null,
        checkoutDialog: {
          show: false,
          data: {
            pubkey: null
          }
        },
        qrCodeDialog: {
          data: {
            payment_request: null
          },
          dismissMsg: null,
          show: false
        },
        downloadOrderDialog: {
          show: false,
          data: {}
        }
      }
    },
    computed: {
      product() {
        if (this.productDetail) {
          return this.products.find(p => p.id == this.productDetail)
        }
      },
      finalCost() {
        if (!this.checkoutDialog.data.shippingzone) return this.cart.total

        let zoneCost = this.stall.shipping.find(
          z => z.id == this.checkoutDialog.data.shippingzone
        )
        return +this.cart.total + zoneCost.cost
      }
    },
    methods: {
      changePageS(page, opts) {
        if (page === 'stall' && opts?.product) {
          document.getElementById('product-focus-area')?.scrollIntoView()
        }
        this.$emit('change-page', page, opts)
      },
      makeLogin() {
        this.resetCheckout()
        this.$emit('login-dialog')
      },
      copyText: function (text) {
        var notify = this.$q.notify
        Quasar.utils.copyToClipboard(text).then(function () {
          notify({
            message: 'Copied to clipboard!',
            position: 'bottom'
          })
        })
      },
      getAmountFormated(amount, unit = 'USD') {
        return LNbits.utils.formatCurrency(amount, unit)
      },
      addToCart(item) {
        this.$emit('add-to-cart', item)
      },

      resetCart() {
        this.cart = {
          total: 0,
          size: 0,
          products: new Map()
        }
        this.$q.localStorage.remove(`diagonAlley.carts.${this.stall.id}`)
      },
      async downloadOrder() {
        let created_at = Math.floor(Date.now() / 1000)
        let orderData = this.checkoutDialog.data
        let orderObj = {
          name: orderData?.username,
          address: orderData.address,
          message: orderData?.message,
          contact: {
            nostr: orderData.pubkey,
            phone: null,
            email: orderData?.email
          },
          items: Array.from(this.cart.products, p => {
            return { product_id: p[0], quantity: p[1].quantity }
          }),
          shipping_id: orderData.shippingzone
        }
        orderObj.id = await hash(
          [orderData.pubkey, created_at, JSON.stringify(orderObj)].join(':')
        )
        this.downloadOrderDialog.data = orderObj
        this.downloadOrderDialog.show = true
        this.resetCheckout()
        this.resetCart()
      },
      async getFromExtension() {
        this.customerPubkey = await window.nostr.getPublicKey()
        this.customerUseExtension = true
        this.checkoutDialog.data.pubkey = this.customerPubkey
      },

      checkLogIn() {
        this.customerPubkey = this.account?.pubkey
        this.customerPrivkey = this.account?.privkey
        this.customerUseExtension = this.account?.useExtension
      },
      resetCheckout() {
        this.loading = false
        this.checkoutDialog = {
          show: false,
          data: {
            pubkey: null
          }
        }
      },
      openQrCodeDialog() {
        this.qrCodeDialog = {
          data: {
            payment_request: null,
            message: null
          },
          dismissMsg: this.$q.notify({
            message: 'Waiting for invoice from merchant...'
          }),
          show: true
        }
      },
      closeQrCodeDialog() {
        this.qrCodeDialog.show = false
        this.qrCodeDialog.data = {
          payment_request: null,
          message: null
        }
        setTimeout(() => {
          this.qrCodeDialog.dismissMsg()
        }, 1000)
      },
      async placeOrder() {
        this.loading = true
        let orderData = this.checkoutDialog.data
        let orderObj = {
          name: orderData?.username,
          address: orderData.address,
          message: orderData?.message,
          contact: {
            nostr: this.customerPubkey,
            phone: null,
            email: orderData?.email
          },
          items: Array.from(this.cart.products, p => {
            return { product_id: p[0], quantity: p[1].quantity }
          }),
          shipping_id: orderData.shippingzone,
          type: 0
        }
        let created_at = Math.floor(Date.now() / 1000)
        orderObj.id = await hash(
          [this.customerPubkey, created_at, JSON.stringify(orderObj)].join(':')
        )
        this.activeOrder = orderObj.id
        let event = {
          ...(await NostrTools.getBlankEvent()),
          kind: 4,
          created_at,
          tags: [['p', this.stall.pubkey]],
          pubkey: this.customerPubkey
        }
        if (this.customerPrivkey) {
          event.content = await NostrTools.nip04.encrypt(
            this.customerPrivkey,
            this.stall.pubkey,
            JSON.stringify(orderObj)
          )
        } else if (this.customerUseExtension && this.hasNip07) {
          event.content = await window.nostr.nip04.encrypt(
            this.stall.pubkey,
            JSON.stringify(orderObj)
          )
          let userRelays = Object.keys(
            (await window.nostr?.getRelays?.()) || []
          )
          if (userRelays.length != 0) {
            userRelays.map(r => this.relays.add(r))
          }
        }
        event.id = NostrTools.getEventHash(event)
        if (this.customerPrivkey) {
          event.sig = await NostrTools.signEvent(event, this.customerPrivkey)
        } else if (this.customerUseExtension && this.hasNip07) {
          event = await window.nostr.signEvent(event)
        }
        this.resetCheckout()
        await this.sendOrder(event)
      },
      async sendOrder(order) {
        let pub = this.pool.publish(Array.from(this.relays), order)
        pub.on('ok', () => console.debug(`Order event was sent`))
        pub.on('failed', error => console.error(error))

        this.loading = false
        this.resetCart()
        this.openQrCodeDialog()
        this.listenMessages()
      },
      async listenMessages() {
        this.loading = true
        try {
          const filters = [
            {
              kinds: [4],
              authors: [this.stall.pubkey]
            },
            {
              kinds: [4],
              '#p': [this.customerPubkey]
            }
          ]
          let relays = Array.from(this.relays)
          let subs = this.pool.sub(relays, filters)
          subs.on('event', async event => {
            let mine = event.pubkey == this.customerPubkey
            let sender = mine
              ? event.tags.find(([k, v]) => k === 'p' && v && v !== '')[1]
              : event.pubkey
            try {
              let plaintext
              if (this.customerPrivkey) {
                plaintext = await NostrTools.nip04.decrypt(
                  this.customerPrivkey,
                  sender,
                  event.content
                )
              } else if (this.customerUseExtension && this.hasNip07) {
                plaintext = await window.nostr.nip04.decrypt(
                  sender,
                  event.content
                )
              }

              this.messageFilter(plaintext, cb => subs.unsub())
            } catch {
              console.debug('Unable to decrypt message! Probably not for us!')
            }
          })
        } catch (err) {
          console.error(`Error: ${err}`)
        }
      },
      messageFilter(text, cb = () => { }) {
        if (!isJson(text)) return
        let json = JSON.parse(text)
        if (json.id != this.activeOrder) return

        if (json.payment_options) {
          if (json.payment_options.length == 0 && json.message) {
            this.loading = false
            this.qrCodeDialog.data.message = json.message
            return cb()
          }
          let payment_request = json.payment_options.find(o => o.type == 'ln')
            .link
          if (!payment_request) return
          this.loading = false
          this.qrCodeDialog.data.payment_request = payment_request
          this.qrCodeDialog.dismissMsg = this.$q.notify({
            timeout: 0,
            message: 'Waiting for payment...'
          })
        } else if (json.paid) {
          this.closeQrCodeDialog()
          this.$q.notify({
            type: 'positive',
            message: 'Sats received, thanks!',
            icon: 'thumb_up'
          })
          this.activeOrder = null
          return cb()
        } else {
          return
        }
      }
    },
    created() {
      this.checkLogIn()
      let storedCart = this.$q.localStorage.getItem(
        `diagonAlley.carts.${this.stall.id}`
      )
      if (storedCart) {
        this.cart.total = storedCart.total
        this.cart.size = storedCart.size
        this.cart.products = new Map(Object.entries(storedCart.products))

        this.cartMenu = Array.from(this.cart.products, item => {
          return { id: item[0], ...item[1] }
        })
      }
      setTimeout(() => {
        if (window.nostr) {
          this.hasNip07 = true
        }
      }, 1000)
    }
  })
}
