<template>
  <div class="flex scoring-panel" :class="[getClass('modal-panel', 'sticky'), { mini: !props.large && !props.modal }]">
    <toggle-dialog-render v-if="isMarkerPage">
      <svg-icon name="question"></svg-icon>
      <span class="m-l-mini" style="max-width: 200px"
        >{{ question.mainNumber }} - {{ question.subNumber }}{{ question.mainTitle }}</span
      >
      <!-- <template #callback>
        <div class="grid radius-base dialog-name">
          <div class="text-center">
            <p>{{ question.mainNumber }} - {{ question.subNumber }}</p>
            <p>{{ question.mainTitle }}</p>
          </div>
        </div>
      </template> -->
    </toggle-dialog-render>
    <div class="flex flex-1 flex-wrap score-list">
      <div
        v-for="scoreItem in scoreList"
        :key="scoreItem"
        class="score-span"
        :class="[
          getClass('m-b-mini'),
          { active: parseFloat(`${currentScore}`) === parseFloat(`${scoreItem}`), mini: !props.large && !props.modal },
        ]"
        @click="onSetScore(scoreItem)"
      >
        {{ scoreItem }}
      </div>
      <toggle-dialog-render>
        <div class="flex items-center score-result" :class="{ 'score-valid-fail': scoreValidFail }">
          <div class="flex-1 text-center">给分</div>
          <input
            ref="refInput1"
            class="flex-1 text-center score-input score-num"
            :value="currentScore"
            @focus="onInputFocus"
            @blur="onBlur"
            @keydown="onValidScoreDebounce"
            @input="scoreChange"
          />
        </div>
      </toggle-dialog-render>
    </div>
    <toggle-dialog-render dialog>
      <div class="grid radius-base dialog-score" :class="{ 'score-valid-fail': scoreValidFail }">
        <input
          ref="refInput2"
          class="score-input"
          :value="currentScore"
          @focus="onInputFocus"
          @blur="onBlur"
          @keydown="onValidScoreDebounce"
          @input="scoreChange"
        />
      </div>
    </toggle-dialog-render>
    <toggle-dialog-render>
      <!-- <svg-icon
        class="pointer toggle-icon"
        :class="{ visible: props.toggleModal }"
        name="toggle-panel"
        @click="onToggleClick"
      ></svg-icon> -->
      <div class="toggle-icon-box" :class="{ visible: props.toggleModal }" @click="onToggleClick">
        <img src="../../assets/images/tanchu.png" />
        <p>弹出</p>
      </div>
    </toggle-dialog-render>
  </div>
</template>

<script setup lang="ts" name="ScoringPanelItem">
import { watch, computed, ref, nextTick, withDefaults, defineComponent, useSlots } from 'vue'
import SvgIcon from '@/components/common/SvgIcon.vue'
import useVModel from '@/hooks/useVModel'
import { getNumbers } from '@/utils/common'
import { debounce } from 'lodash-es'
import { useRoute } from 'vue-router'

const route = useRoute()
const isMarkerPage = computed(() => {
  return route.path === '/marking/mark'
})

interface QuestionInfo {
  mainNumber: number
  mainTitle: string
  subNumber: number
  totalScore: number
  intervalScore: number
}

const props = withDefaults(
  defineProps<{
    /** 弹窗模式? */
    modal?: boolean
    /** 是否可以切换显示模式 */
    toggleModal?: boolean
    /** 分值 */
    score?: number | string | undefined
    /** active 当前正在评分 */
    active: boolean
    scoreValidFail: boolean | undefined
    question: QuestionInfo
    large?: boolean
  }>(),
  { modal: false, toggleModal: true, score: void 0, scoreValidFail: false, large: true }
)

const emit = defineEmits(['focused', 'blur', 'toggle-click', 'enter', 'update:score'])

const dialogMode = ref<boolean>(props.modal)

const currentScore = useVModel(props, 'score')

const scoreValidFail = useVModel(props, 'scoreValidFail')

const ToggleDialogRender = defineComponent({
  name: 'DialogHideNode',
  inheritAttrs: false,
  props: {
    dialog: {
      type: Boolean,
      default: false,
    },
  },
  render() {
    const slots = useSlots()
    const defaultSlot = slots?.default?.()
    const callBackSlot = slots?.callback?.()
    return (this.dialog ? dialogMode.value : !dialogMode.value) ? defaultSlot : callBackSlot
  },
})

const question = computed(() => {
  return props.question || ({} as QuestionInfo)
})

const scoreList = computed<number[]>(() => {
  const { totalScore, intervalScore } = question.value
  return getNumbers(totalScore || 0, intervalScore || 0)
})

const focused = ref<boolean>(false)

const refInput1 = ref<HTMLInputElement>()
const refInput2 = ref<HTMLInputElement>()

watch(
  () => props.active,
  () => {
    nextTick(() => {
      if (props.active) {
        inputFocus()
      } else {
        inputBlur()
      }
    })
  },
  { immediate: true }
)

const getClass = (val: string, callback?: string) => {
  return dialogMode.value ? val : callback || ''
}

const onSetScore = (v: number | string) => {
  onInputFocus()
  currentScore.value = v
}

const onInputFocus = () => {
  focused.value = true
  emit('focused')
}

const onBlur = (e: Event) => {
  focused.value = false
  const target = e.target as HTMLInputElement
  target.value && scoreStrictValidFail(target.value)
  emit('blur')
}

const inputFocus = () => {
  nextTick(() => {
    refInput1?.value?.focus()
    refInput2?.value?.focus()
  })
}

const inputBlur = () => {
  nextTick(() => {
    refInput1?.value?.blur()
    refInput2?.value?.blur()
  })
}

const KEY_WHITE_LIST1 = ['ArrowLeft', 'ArrowRight', 'Backspace', 'Delete', 'Enter']
const KEY_WHITE_LIST2 = ['\\.', '[0-9]', '[+-]']
const KEY_VALID_REG = new RegExp(
  KEY_WHITE_LIST1.map((k) => `\\b${k}\\b`)
    .concat(KEY_WHITE_LIST2)
    .join('|')
)

const validScore = (score: number | string) => {
  return scoreList.value.some((s) => `${s}`.startsWith(`${score}`))
}

const scoreStrictValidFail = (score: number | string) => {
  scoreValidFail.value = !scoreList.value.some((s) => `${s}` === `${score}`)
  return scoreValidFail.value
}

const deleteStringChart = (str: string, index: number) => {
  return str.substring(0, index) + str.substring(index + 1)
}

const joinStringChart = (str: string, index: number, chart: string) => {
  return str.substring(0, index) + chart + str.substring(index + 1)
}

const onValidScore = (e: any) => {
  const target = e.target as HTMLInputElement
  const oldScore = `${currentScore.value ?? ''}`
  const start = target.selectionStart || 0

  if (!KEY_VALID_REG.test(e.key)) {
    console.log('valid:', e.key)

    e.preventDefault()
    return
  }
  if (['ArrowLeft', 'ArrowRight'].includes(e.key)) {
    return
  }
  console.log('e.key:', e.key)

  if (e.key === '+' && Number(currentScore.value || 0) < scoreList.value[scoreList.value.length - 1]) {
    currentScore.value = Number(currentScore.value || 0) + 1 + ''
  }
  if (e.key === '-' && Number(currentScore.value || 0) > scoreList.value[0]) {
    currentScore.value = Number(currentScore.value || 0) - 1 + ''
  }
  if ('Enter' === e.key) {
    let targetInputValue = e.target?.value
    if (!targetInputValue) {
      return
    }
    if (oldScore && !scoreStrictValidFail(oldScore)) {
      nextTick(() => {
        emit('enter')
      })
    }
    e.preventDefault()
    return
  }

  if ('Backspace' === e.key) {
    if (!validScore(deleteStringChart(oldScore, start - 1))) {
      e.preventDefault()
    }
    return
  }
  if ('Delete' === e.key) {
    if (!validScore(deleteStringChart(oldScore, start))) {
      e.preventDefault()
    }
    return
  }
  if (!validScore(joinStringChart(oldScore, start, e.key))) {
    e.preventDefault()
  }
}
const onValidScoreDebounce = debounce(onValidScore, 50)

const scoreChange = (e: Event) => {
  const target = e.target as HTMLInputElement
  const oldScore = `${currentScore.value || ''}`
  if (validScore(target.value)) {
    onSetScore(target.value)
  } else {
    target.value = oldScore
  }
}

const onToggleClick = () => {
  emit('toggle-click')
}
</script>

<style scoped lang="scss">
.scoring-panel {
  // background-color: $MainLayoutHeaderBg;
  background-color: #fff;
  font-size: $MediumFont;
  margin-bottom: 6px;
  &.mini {
    padding: 12px 5px !important;
  }
  &.modal-panel {
    padding: 10px 0;
  }
  &.sticky {
    align-items: center;
    // padding: 12px 20px;
    padding: 5px 20px;
    height: 56px;
  }

  // .dialog-name {
  //   width: 98px;
  //   place-items: center;
  //   background: #f5f5f5;
  // }

  .score-list {
    font-size: $BaseFont;
    margin-bottom: -8px;
    // margin-left: 8px;
    .score-span {
      width: 46px;
      height: 32px;
      line-height: 32px;
      text-align: center;
      border-radius: 4px;
      border: 1px solid #e5e5e5;
      color: #666666;
      margin-left: 8px;
      margin-bottom: 8px;
      cursor: pointer;
      &.mini {
        width: 32px;
        font-size: 12px;
      }
      &.active,
      &:hover {
        background-color: $color--primary;
        color: $color--white;
      }
    }

    .score-result {
      background-color: $color--primary;
      color: $color--white;
      margin-left: 8px;
      border-radius: 6px;
      padding: 2px;
      height: 32px;
      line-height: 32px;
      min-width: 84px;
      margin-bottom: 8px;

      .score-num {
        width: 40px;
        height: 100%;
        line-height: 28px;
        background-color: $color--white;
        color: #e02020;
        border-radius: 0 6px 6px 0;
        outline: none;
      }
    }
  }

  .dialog-score {
    width: 80px;
    place-items: center;
    background: $color--primary;
    color: $color--white;
    font-size: 32px;
    outline: none;
    margin-left: 6px;
    overflow: hidden;
    .score-input {
      background: inherit;
      color: inherit;
      font-size: inherit;
      width: 100% !important;
      height: 100%;
    }
  }

  .score-input {
    border: none;
    outline: none;
    font-weight: bold;
    text-align: center;
  }

  .score-valid-fail {
    position: relative;
    // background-color: $DangerColor !important;
    border: 1px solid $DangerColor;
    box-shadow: 0 0 4px $DangerColor;
    &:before {
      content: '无效分值';
      position: absolute;
      width: 100%;
      height: 1em;
      line-height: 1;
      text-align: center;
      top: -1.2em;
      left: 50%;
      transform: translateX(-50%);
      font-size: 10px;
      color: $DangerColor;
    }
  }

  // .toggle-icon {
  //   align-self: flex-start;
  //   margin-top: 6px;
  //   margin-left: 6px;
  //   opacity: 0;
  //   &.visible {
  //     opacity: 1;
  //   }
  // }
  .toggle-icon-box {
    cursor: pointer;
    background-color: #0091ff;
    width: 70px;
    border-radius: 6px;
    text-align: center;
    color: #fff;
    opacity: 0;
    height: 100%;
    transition: all 0.3s;
    &:hover {
      background-color: rgba(0, 145, 255, 0.8);
    }
    &.visible {
      opacity: 1;
    }
    img {
      height: 20px;
      margin-top: 4px;
    }
    p {
      font-size: 12px;
    }
  }
}
</style>
