import { Component, Util, $ } from '@apigo.cc/state'

export const UI = {}

Component.register('Modal', container => {
	container.modal = new bootstrap.Modal(container)
	container.addEventListener('bind', e => {
		e.detail ? container.modal.show() : container.modal.hide()
	})
	container.addEventListener('hide.bs.modal', () => {
		document.activeElement?.blur()
		container.dispatchEvent(new CustomEvent('change', { bubbles: false, detail: false }))
	})
	Util.copyFunction(container, container.modal, 'show', 'hide')
}, Util.makeDom(/*html*/`
<div class="modal fade" data-bs-backdrop="static">
  <div class="modal-dialog modal-dialog-centered">
    <div $class="modal-content border-\${this.state?.type || 'primary'} border-2 shadow-lg">
      <div slot-id="header" class="modal-header py-2 px-3 bg-light">
        <h6 $class="modal-title fw-bold text-\${this.state?.type || 'primary'}" $text="this.state?.title"></h6>
        <button type="button" class="btn btn-link ms-2 bi bi-x-lg link-reset p-0" style="color:inherit; text-decoration:none" data-bs-dismiss="modal"></button>
      </div>
      <div slot-id="body" class="modal-body p-3"></div>
      <div slot-id="footer" class="modal-footer py-2 px-3 bg-light"></div>
    </div>
  </div>
</div>
`))

Component.register('Dialog', Component.getSetupFunction('Modal'), Util.makeDom(/*html*/`
<div class="modal fade" data-bs-backdrop="static">
  <div class="modal-dialog modal-dialog-centered">
    <div $class="modal-content border-\${this.state?.type || 'primary'} border-2 shadow-lg">
      <div $if="this.state?.title" $class="modal-header py-2 px-3 bg-light fw-bold text-\${this.state?.type || 'primary'}" $text="this.state?.title"></div>
      <div slot-id="body" class="modal-body p-4"><div $html="this.state?.message"></div></div>
      <div class="modal-footer py-2 px-3 bg-light">
        <button $each="this.state?.buttons || ['{#Close#}']" type="button" $class="btn btn-sm px-3 btn-\${index === (this.state?.buttons || []).length - 1 ? (this.state?.type && this.state?.type !== 'body' ? this.state?.type : 'primary') : 'outline-secondary border'}" $onclick="this.result=index+1;this.hide()" $text="\${item}"></button>
      </div>
    </div>
  </div>
</div>
`))

let _dialogCount = 0
UI.showDialog = function ({ title = '', message = '', buttons = ['{#Close#}'], type = 'body' }) {
	const d = document.body.appendChild(document.createElement('Dialog'))
	d.style.zIndex = 2000 + ++_dialogCount
	Promise.resolve().then(() => {
		Object.assign(d.state, { message, title, type, buttons })
		d.show()
	})
	return new Promise((resolve) => {
		d.addEventListener('change', e => {
			_dialogCount--
			resolve(d.result || 0)
			d.remove()
		})
	})
}

UI.alert = function (message, options = {}) {
	return UI.showDialog({ message, ...options })
}
UI.confirm = function (message, options = {}) {
	return new Promise((resolve) => UI.showDialog({ message, buttons: ['{#Cancel#}', '{#Confirm#}'], ...options }).then(index => resolve(index >= 2)).catch(() => resolve(false)))
}

Component.register('Toast', container => {
	container.toast = new bootstrap.Toast(container, { autohide: container.state.delay > 0 })
	Util.copyFunction(container, container.toast, 'show', 'hide')
	container.addEventListener('show.bs.toast', () => {
		if (container.state.delay > 0) {
			let timer
			const startTimer = () => {
				container.state.left = container.state.delay / 1000
				timer = setInterval(() => {
					if (!container.isConnected || --container.state.left <= 0) clearInterval(timer)
				}, 1000)
			}
			startTimer()
			container.addEventListener('mouseenter', () => { clearInterval(timer); container.state.left = undefined })
			container.addEventListener('mouseleave', startTimer)
		}
	})
}, Util.makeDom(/*html*/`
<div class="toast align-items-center border-0 m-1">
  <div $class="toast-body rounded p-3 text-bg-\${this.state?.type}">
    <div class="d-flex align-items-center">
      <div class="flex-grow-1">
        <span style="white-space:pre-wrap" class="fs-6" $text="this.state?.message"></span>
        <span $if="this.state?.left !== undefined" class="small text-dim ms-2" $text="\${this.state?.left}s"></span>
      </div>
      <button type="button" class="btn btn-link ms-3 bi bi-x-lg link-reset" style="color:inherit" data-bs-dismiss="toast"></button>
    </div>
    <div class="d-flex justify-content-end gap-3">
      <button $each="this.state?.buttons || ['{#Close#}']" type="button" $class="btn btn-sm btn-\${this.state?.type} mt-2" data-bs-dismiss="toast" $onclick="this.result=index+1" $text="item"></button>
    </div>
  </div>
</div>
`), Util.makeDom(/*html*/`<div toast-container="default" class="position-fixed bottom-0 end-0 overflow-auto" style="z-index:3000;max-height:80%"></div>`))

UI.toast = function (message, options = {}) {
	const delay = options.delay ?? 5000
	const t = document.createElement('Toast')
	t.state = { delay, left: delay ? delay / 1000 : undefined, type: options.type || 'primary', message, buttons: options.buttons || [] }
	$(`[toast-container="${options.container || 'default'}"]`).appendChild(t)
	Promise.resolve().then(() => t.show())
}

UI.toastConfirm = function (message, options = {}) {
	return new Promise((resolve) => UI.toast(message, { buttons: ['{#Confirm#}'], ...options }).then(index => resolve(index === 1)).catch(() => resolve(false)))
}
