<script setup lang="ts">
import { px2vw } from '@/utils'
import { dialog } from '.'

type OkAsyncFunc = (hide: any) => Promise<any>
type OkFunc = (hide: any) => any
type Func = () => void

// js参数
export type MjDialogOptions = {
  title?: string
  content?: string
  ok?: OkAsyncFunc | OkFunc | Func
  cancel?: Func
  open?: Func
  closed?: Func
  confirmClose?: boolean | (() => boolean)
  hideClose?: boolean
  hideCancel?: boolean
  hideFooter?: boolean
  cancelText?: string
  okText?: string
  width?: any
  maskClose?: boolean
  js_destroy?: Func
}
// 组件属性
export type MjDialogProps = {
  modelValue: boolean
} & MjDialogOptions
// 属性
const props = withDefaults(defineProps<MjDialogProps>(), {
  maskClose: true,
})
// 事件
const emits = defineEmits(['update:modelValue'])
// 背景
const OSS_URL = import.meta.env.VITE_OSS_URL
const headBg = `url(${OSS_URL}/urm/dia_head_bg.svg) 100%/100% no-repeat`
// 宽度
const width = computed(() => px2vw(props.width || 750))

const js_props = ref({} as MjDialogOptions)
// 组件模式
const mode_cmp = 0
// js模式
const mode_js = 1
const mode = ref(mode_cmp)

// 是否可见
const js_visible = ref(false)
function _setVisible(val: boolean, close?: any) {
  if (visible.value === val) return

  if (!val) {
    close && close()
  }

  if (mode.value === mode_js) {
    js_visible.value = val
    if (!val) {
      props.js_destroy && props.js_destroy()
    }
  } else {
    emits('update:modelValue', val)
  }
}

const visible = computed({
  get() {
    return mode.value === mode_js ? js_visible.value : props.modelValue
  },
  set(newVal) {
    _setVisible(newVal)
  },
})

// 需要动态修改的属性
const loading = ref(false)

const options = computed(() => {
  return (mode.value === mode_cmp ? props : js_props.value) as MjDialogOptions
})

const closable = computed(() => {
  if (!options.value.maskClose) return false
  if (options.value.confirmClose) return false
  return !(options.value.hideCancel && options.value.hideClose) && !loading.value
})

async function _ok() {
  // 默认的ok行为
  if (!options.value.ok) {
    _setVisible(false)
    return
  }

  // 如果外部传了ok函数
  try {
    loading.value = true
    const ret: any = await options.value.ok(() => _setVisible(false))
    if (ret !== true) {
      // 不是直接返回true，说明是需要关闭的
      _setVisible(false)
    }
  } finally {
    loading.value = false
  }
}

function _cancel() {
  const end = () => {
    options.value.cancel && options.value.cancel()
    js_props.value = {} as MjDialogOptions
  }

  // 确认关闭
  const close = options.value.confirmClose
  let confirm = false
  if (close) {
    if (typeof close === 'function') {
      if (close()) {
        confirm = true
      }
    } else {
      confirm = true
    }
  }

  if (confirm) {
    dialog.show({
      content: '确定要关闭么？',
      ok: () => {
        _setVisible(false, end)
      },
    })
  } else {
    _setVisible(false, end)
  }
}

// 暴露方法
defineExpose({
  show: (data: MjDialogOptions) => {
    mode.value = mode_js
    // 默认值
    if (data.maskClose === undefined) {
      data.maskClose = true
    }
    js_props.value = data
    _setVisible(true)
  },
  hide: () => {
    _cancel()
  },
  isShowing: () => visible.value,
})
</script>

<template>
  <el-dialog
    v-model="visible"
    class="mj-dialog"
    :title="options.title"
    :show-close="false"
    :close-on-click-modal="closable"
    :close-on-press-escape="closable"
    destroy-on-close
    align-center
    v-bind="$attrs"
    :style="{
      width,
    }"
    @closed="options.closed"
    @open="options.open"
  >
    <template #header>
      <div
        class="header"
        :style="{
          background: headBg,
        }"
      >
        <span class="title">{{ options.title || '提示' }}</span>
        <Icon class="left-icon" name="dia_logo" size="104" />
        <Icon
          v-if="!options.hideClose && !loading"
          class="right-icon"
          name="close_dia"
          size="48"
          style="cursor: pointer"
          @click="_cancel"
        />
      </div>
    </template>
    <div class="body">
      <div
        :class="{
          content: true,
          full: options.hideFooter,
        }"
      >
        <div v-if="options.content" class="tips">
          <span v-html="options.content" />
        </div>
        <slot v-else></slot>
      </div>
      <div v-if="$slots.footer || !options.hideFooter" class="footer">
        <slot v-if="$slots.footer" name="footer"></slot>
        <template v-else-if="!options.hideFooter">
          <mj-button v-if="!options.hideCancel" :loading="loading" type="warn" @click="_cancel">{{
            options.cancelText || '取消'
          }}</mj-button>
          <mj-button :loading="loading" type="success" @click="_ok">{{
            options.okText || '确定'
          }}</mj-button>
        </template>
      </div>
    </div>
  </el-dialog>
</template>
<style lang="scss">
.el-overlay-dialog {
  overflow: hidden;
}

.mj-dialog {
  min-height: 25vh;
  margin: 0;
  padding: 0;
  background: #373737;
  border-radius: 3.33vh !important;
  z-index: 100000000000;

  .el-dialog__header {
    height: 7.33vh;
    padding: 0 !important;
    position: relative;
  }

  .el-dialog__body {
    height: 100%;
    border-radius: 3.33vh;
    background: linear-gradient(162deg, #fdfdf9 12.23%, #dfebf7 90.14%);
    padding: 2.67vh !important;
  }
}
</style>

<style lang="scss" scoped>
.mj-dialog {
  .header {
    width: 100%;
    height: 7.33vh;
    position: absolute;
    top: 0;
    display: flex;
    align-items: center;
    justify-content: center;

    .title {
      font-family: $font-special;
      font-size: 4vh;
      color: #fff;
      letter-spacing: $space-2;
    }

    .left-icon {
      position: absolute;
      top: -1.67vh;
      left: -20px;
    }
    .right-icon {
      position: absolute;
      top: -0.5vh;
      right: -6px;
    }
  }

  .body {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    .content {
      flex: 1;
      min-height: 15vh;
      width: 100%;

      .tips {
        width: 100%;
        min-height: 15vh;
        display: flex;
        align-items: center;
        justify-content: center;
        font-family: $font-text;
        font-size: $font-size-7;
        color: $font-tag-color;
      }
      &.full {
        min-height: 15vh;
      }
    }
    .footer {
      display: flex;
      justify-content: center;
      height: 6.67vh;
      margin-top: 1.67vh;
      .mj-button {
        margin-right: $space-4;
        &:last-child {
          margin-right: 0;
        }
      }
    }
  }
}
</style>
