import MessageBox from '@/components/common/MessageBox/index.vue'
import type { MessageBoxProps } from '@/components/common/MessageBox/types'
import type { FormInstance } from 'element-plus'
import { render, effect, stop } from 'vue'

interface ConfirmProps extends MessageBoxProps {
  useLoading?: boolean // 是否用到loading
}
interface PromptProps extends MessageBoxProps {
  inputPattern?: RegExp // 输入框的正则
  inputErrorMessage?: string // 输入框的错误信息
}
let hasBindEvent = false

// 记录每次鼠标点击的位置 x y
const mousePosition = ref({ x: 0, y: 0 })

let shouldUpdateMousePosition = true
const handler = (e: MouseEvent) => {
  if (!shouldUpdateMousePosition) return
  mousePosition.value = { x: e.clientX, y: e.clientY }
}
if (!hasBindEvent) {
  window.addEventListener('click', handler, {
    capture: true,
  })
  hasBindEvent = true
}

export const useMessageBox = () => {
  const confirm = (props: Omit<ConfirmProps, 'mousePosition'>) => {
    return new Promise((resolve, reject) => {
      shouldUpdateMousePosition = false

      const visible = ref(false)
      const loading = ref(false)
      const onConfirm = () => {
        if (props.useLoading) {
          // 设置loading
          loading.value = true
          // 关闭全给用户
          resolve({
            close: () => {
              visible.value = false
            },
            setLoading: (value: boolean) => {
              loading.value = value
            },
          })
        } else {
          resolve(true)
        }
      }
      const onCancel = () => {
        reject(false)
      }
      const onClose = () => {
        reject(false)
      }

      const effectRunner = effect(() => {
        render(
          <MessageBox
            v-model={visible.value}
            {...props}
            mousePosition={mousePosition.value}
            loading={loading.value}
            onConfirm={onConfirm}
            onCancel={onCancel}
            onClose={onClose}
            onAfterLeave={() => {
              stop(effectRunner)
              render(null, document.body)
              shouldUpdateMousePosition = true
            }}
          />,
          document.body,
        )
      })

      visible.value = true
    })
  }

  const prompt = <T extends string | number = string>(
    props: Omit<PromptProps, 'mousePosition'>,
  ): Promise<T> => {
    return new Promise((resolve, reject) => {
      shouldUpdateMousePosition = false
      const visible = ref(false)
      const loading = ref(false)
      const rules = {
        inputValue: [
          {
            required: true,
            message: '内容不能为空',
            trigger: 'blur',
          },
          {
            pattern: props.inputPattern,
            message: props.inputErrorMessage ?? '请输入正确的内容',
            trigger: 'blur',
          },
        ],
      }

      const validate = async () => {
        await formRef.value?.validate()
        return form.value.inputValue
      }
      const formRef = ref<FormInstance | null>(null)
      const form = ref<{ inputValue: T }>({ inputValue: '' as T })

      const messageFC = () => (
        <div>
          <el-form ref={formRef} rules={rules} model={form.value}>
            <el-form-item prop="inputValue">
              <el-input v-model={form.value.inputValue} />
            </el-form-item>
          </el-form>
        </div>
      )

      const onConfirm = (val: T) => {
        resolve(val)
      }
      const onCancel = () => {
        reject(false)
      }
      const onClose = () => {
        reject(false)
      }

      const effectRunner = effect(() => {
        render(
          <MessageBox
            {...props}
            v-model={visible.value}
            validate={validate}
            message={messageFC}
            loading={loading.value}
            mousePosition={mousePosition.value}
            onConfirm={(res: string | number | undefined) => onConfirm(res as T)}
            onCancel={onCancel}
            onClose={onClose}
            onAfterLeave={() => {
              stop(effectRunner)
              render(null, document.body)
              shouldUpdateMousePosition = true
            }}
          />,
          document.body,
        )
      })

      visible.value = true
    })
  }

  return { confirm, prompt }
}
