import { createApp, h, type App, type Component, type VNode } from 'vue'
import BasePopupBox from './PopupBox.vue'

export interface PopupBoxOptions {
  title?: string
  content?: string | VNode | Component
  theme?: 'dark' | 'light'
  width?: string | number
  closable?: boolean
  closeOnBackdrop?: boolean
  closeOnEscape?: boolean
  showFooter?: boolean
  hideCancel?: boolean
  cancelText?: string
  confirmText?: string
  onClose?: () => void
  onCancel?: () => void
  onConfirm?: () => void
}

export interface PopupBoxHandle {
  close: () => void
}

export type PopupBoxResult = 'confirm' | 'cancel' | 'close'

function renderContent(content: PopupBoxOptions['content']) {
  if (content == null) return undefined
  if (typeof content === 'string') return content
  if (typeof content === 'object' && 'type' in content) return content as VNode
  return h(content as Component)
}

export function open(options: PopupBoxOptions = {}): PopupBoxHandle {
  if (typeof document === 'undefined') {
    return { close: () => undefined }
  }

  const container = document.createElement('div')
  document.body.appendChild(container)

  let app: App | null = null
  let settled = false

  function cleanup() {
    if (app) {
      app.unmount()
      app = null
    }
    container.parentNode?.removeChild(container)
  }

  function settle(kind: PopupBoxResult) {
    if (settled) return
    settled = true

    if (kind === 'close') options.onClose?.()
    if (kind === 'cancel') options.onCancel?.()
    if (kind === 'confirm') options.onConfirm?.()

    cleanup()
  }

  app = createApp({
    render: () =>
      h(
        BasePopupBox,
        {
          visible: true,
          title: options.title,
          theme: options.theme ?? 'dark',
          width: options.width,
          closable: options.closable ?? true,
          closeOnBackdrop: options.closeOnBackdrop ?? false,
          closeOnEscape: options.closeOnEscape ?? true,
          showFooter: options.showFooter ?? true,
          hideCancel: options.hideCancel ?? false,
          cancelText: options.cancelText,
          confirmText: options.confirmText,
          onClose: () => settle('close'),
          onCancel: () => settle('cancel'),
          onConfirm: () => settle('confirm'),
        },
        { default: () => renderContent(options.content) },
      ),
  })

  app.mount(container)

  return {
    close: () => settle('close'),
  }
}

export function alert(
  options: Omit<PopupBoxOptions, 'cancelText' | 'onCancel'> = {},
): Promise<PopupBoxResult> {
  return new Promise((resolve) => {
    open({
      ...options,
      showFooter: options.showFooter ?? true,
      onConfirm: () => {
        options.onConfirm?.()
        resolve('confirm')
      },
      onClose: () => {
        options.onClose?.()
        resolve('close')
      },
      hideCancel: true,
    })
  })
}

export function confirm(options: PopupBoxOptions = {}): Promise<PopupBoxResult> {
  return new Promise((resolve) => {
    open({
      ...options,
      showFooter: options.showFooter ?? true,
      onConfirm: () => {
        options.onConfirm?.()
        resolve('confirm')
      },
      onCancel: () => {
        options.onCancel?.()
        resolve('cancel')
      },
      onClose: () => {
        options.onClose?.()
        resolve('close')
      },
    })
  })
}
