<template>
  <el-dialog
    draggable
    append-to-body
    v-model="showModal"
    :title="t('languageSetting')"
    width="720px"
    align-center
  >
    <div>
      <el-input v-model="search" placeholder="输入key/内容搜索" class="mb-10px" />
    </div>
    <div
      class="flex items-center justify-between border-b border-b-solid border-border pb-12px border-1px"
    >
      <div class="w-280px flex items-center gap-12px">
        <span class="text-12px shrink-0">当前语言:</span>
        <el-select v-model="currentLanguage" :options="languagesMenu" />
      </div>
      <div class="flex items-center gap-8px">
        <el-button type="text" @click="handleCollapseAll">
          <el-icon class="cursor-pointer">
            <ArrowRight />
          </el-icon>
          <span>一键折叠</span>
        </el-button>
        <el-button type="text" @click="handleExpandAll">
          <el-icon class="cursor-pointer">
            <ArrowDown />
          </el-icon>
          <span>一键展开</span>
        </el-button>
        <el-button type="text" @click="handleAdd">
          <el-icon class="cursor-pointer">
            <Plus />
          </el-icon>
          <span>添加</span>
        </el-button>
      </div>
    </div>
    <el-scrollbar ref="scrollbarRef" height="calc(100vh - 300px)" class="config">
      <el-form label-position="top">
        <div v-for="item in getData" :key="item.id">
          <el-collapse v-model="activeNames">
            <el-collapse-item :name="item.id">
              <template #title>
                <div class="collapse-title">
                  <el-icon class="arrow" :class="{ active: activeNames.includes(item.id) }">
                    <ArrowRight />
                  </el-icon>

                  <span class="title-text">{{ item.key }}</span>

                  <el-icon @click.stop="handleRemoveGroup(item)">
                    <Delete />
                  </el-icon>
                </div>
              </template>
              <el-card class="m-10px">
                <el-input
                  v-model="item.key"
                  spellcheck="false"
                  class="mt-10px mb-10px"
                  :placeholder="t('languageKey')"
                  @focus="rememberLanguageKey(item)"
                  @input="sanitizeLanguageKey(item)"
                  @blur="handleLanguageKeyBlur(item)"
                />
                <div v-for="(languageItem, index) in item.values" :key="index" class="mb-10px">
                  <div class="flex flex-wrap gap-5px items-center">
                    <el-select
                      v-model="languageItem.language"
                      style="flex: 1"
                      @change="handleLanguageChange(item.values, languageItem)"
                    >
                      <el-option
                        v-for="menu in getLanguageOptions(item.values, languageItem)"
                        :key="menu.value"
                        :value="menu.value"
                        :label="menu.label"
                        :disabled="menu.disabled"
                      />
                    </el-select>
                    <el-input
                      v-model="languageItem.value"
                      spellcheck="false"
                      style="flex: 1"
                      :placeholder="t('content')"
                    />
                    <el-select v-model="languageItem.font" style="flex: 1" :placeholder="t('font')">
                      <template #label="{ label }">
                        <div :style="{ fontFamily: `'${label}'` }">{{ label }}</div>
                      </template>
                      <el-option
                        v-for="item in fontOptions"
                        :key="item.value"
                        :value="item.value"
                        :label="item.label"
                      >
                        <div :style="{ fontFamily: `'${item.label}'` }">
                          {{ item.label }}
                        </div>
                      </el-option>
                    </el-select>
                    <input-number
                      v-model="languageItem.fontSize"
                      spellcheck="false"
                      style="width: 80px"
                      :placeholder="t('fontSize')"
                    />
                    <el-icon
                      class="cursor-pointer"
                      @click.stop="handleRemoveItem(item.values, languageItem)"
                    >
                      <Delete />
                    </el-icon>
                  </div>
                </div>
                <el-tooltip :content="t('addLanguage')">
                  <el-icon class="cursor-pointer" @click="handleAddLanguageValue(item.values)">
                    <Plus />
                  </el-icon>
                </el-tooltip>
              </el-card>
            </el-collapse-item>
          </el-collapse>
        </div>
      </el-form>
      <el-empty v-if="!getData.length" :image-size="80">
        <template #description>
          <div>暂时数据</div>
        </template>
      </el-empty>
    </el-scrollbar>
  </el-dialog>
</template>

<script setup lang="ts">
import { computed, nextTick, ref } from 'vue'
import type { Language, LanguageItem } from '@/types/language'
import type { ScrollbarInstance } from 'element-plus'
import { ArrowRight, Plus, Delete, ArrowDown } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { languagesMenu } from '@/constants'
import { v4 } from 'uuid'
import { useProjectStore } from '@/store/modules/project'
import { useI18n } from 'vue-i18n'

const { t } = useI18n()
const showModal = ref(false)
const activeNames = ref<string[]>([])
const previousLanguageKeys = ref<Record<string, string>>({})
const projectStore = useProjectStore()
const search = ref('')
const scrollbarRef = ref<ScrollbarInstance>()

// 字体选项
const fontOptions = computed(() => {
  const list = (projectStore.project?.resources.fonts || []).map((font) => {
    return {
      label: font.fileName,
      value: font.id
    }
  })
  return [{ label: 'montserratMedium', value: 'montserratMedium' }, ...list]
})

const data = computed<Language[]>({
  get() {
    return projectStore.project?.languages || []
  },
  set(val) {
    if (projectStore.project) {
      projectStore.project.languages = val
    }
  }
})

const getData = computed(() => {
  if (!search.value) return data.value

  return data.value.filter(
    (item) =>
      item.key.includes(search.value) || item.values.some((v) => v.value.includes(search.value))
  )
})

const currentLanguage = computed({
  get() {
    return projectStore.project?.currentLanguage || ''
  },
  set(val) {
    if (projectStore.project) {
      projectStore.project.currentLanguage = val
    }
  }
})

const handleCollapseAll = () => {
  activeNames.value = []
}

const handleExpandAll = () => {
  activeNames.value = getData.value.map((item) => item.id)
}

const ensureProject = () => {
  if (projectStore.project) return true

  ElMessage.warning(t('createProjectFirst'))
  return false
}

const sanitizeLanguageKey = (language: Language) => {
  const normalized = language.key.replace(/[^A-Za-z0-9_]/g, '').replace(/^[^A-Za-z_]+/, '')

  if (normalized !== language.key) {
    language.key = normalized
  }
}

const isDuplicateLanguageKey = (currentId: string, key: string) => {
  return data.value.some((item) => item.id !== currentId && item.key === key)
}

const rememberLanguageKey = (language: Language) => {
  previousLanguageKeys.value[language.id] = language.key
}

const handleLanguageKeyBlur = (language: Language) => {
  const previousKey = previousLanguageKeys.value[language.id] ?? ''

  if (!language.key) {
    language.key = previousKey
    if (previousKey) ElMessage.warning(t('languageKeyEmpty'))
    return
  }

  if (isDuplicateLanguageKey(language.id, language.key)) {
    language.key = previousKey
    ElMessage.warning(t('languageKeyDuplicate'))
    return
  }

  previousLanguageKeys.value[language.id] = language.key
}

const handleAddLanguageValue = (values: LanguageItem[]) => {
  if (!ensureProject()) return

  values.push({
    language: '',
    value: '',
    font: 'montserratMedium',
    fontSize: 14
  })
}

const handleRemoveItem = (languages: LanguageItem[], languageItem: LanguageItem) => {
  const index = languages.findIndex((item) => item === languageItem)
  if (index !== -1) {
    languages.splice(index, 1)
  }
}

const getLanguageOptions = (languages: LanguageItem[], current: LanguageItem) => {
  const used = new Set(
    languages
      .filter((item) => item !== current)
      .map((item) => item.language)
      .filter(Boolean)
  )

  return languagesMenu.map((menu) => ({
    ...menu,
    disabled: used.has(menu.value)
  }))
}

const handleLanguageChange = (languages: LanguageItem[], current: LanguageItem) => {
  if (!current.language) return

  const duplicated = languages.some(
    (item) => item !== current && item.language && item.language === current.language
  )

  if (!duplicated) return

  current.language = ''
  ElMessage.warning(t('languageDuplicate'))
}

const handleRemoveGroup = (language: Language) =>
  ElMessageBox.confirm(t('deleteConfirm'), t('tip'), {
    confirmButtonText: t('confirm'),
    cancelButtonText: t('cancel'),
    type: 'warning'
  }).then(() => {
    const index = data.value.findIndex((item) => item.id === language.id)
    if (index !== -1) {
      data.value.splice(index, 1)
    }
  })

const handleAdd = async () => {
  if (!ensureProject()) return

  const first = data.value?.[0]?.values.map((item) => ({
    ...item,
    value: ''
  }))

  const id = v4()
  let keyIndex = data.value.length + 1
  let nextKey = `lang_key_${keyIndex}`
  while (isDuplicateLanguageKey(id, nextKey)) {
    keyIndex += 1
    nextKey = `lang_key_${keyIndex}`
  }

  data.value.push({
    id,
    key: nextKey,
    values: first?.length
      ? first
      : [
          {
            language: '',
            value: '',
            font: 'montserratMedium',
            fontSize: 14
          }
        ]
  })
  previousLanguageKeys.value[id] = nextKey
  activeNames.value.push(id)

  // 滚动到新增的语言项
  await nextTick()
  const h = scrollbarRef.value?.wrapRef?.scrollHeight
  if (h) {
    scrollbarRef.value?.setScrollTop(h)
  }
}

defineExpose({
  open: () => {
    if (!ensureProject()) return

    previousLanguageKeys.value = Object.fromEntries(data.value.map((item) => [item.id, item.key]))
    showModal.value = true
  }
})
</script>

<style lang="less" scoped>
:deep(.el-form-item) {
  margin-bottom: 5px;
}

:deep(.el-collapse-item__header) {
  padding-right: 0;
}

:deep(.el-collapse-item__arrow) {
  display: none;
}

.collapse-title {
  display: flex;
  align-items: center;
  width: 100%;
  box-sizing: border-box;
  padding: 0 12px;
}

.arrow {
  margin-right: 8px;
  transition: transform 0.2s;
}

.arrow.active {
  transform: rotate(90deg);
}

.title-text {
  flex: 1;
  font-weight: 500;
}

::v-deep(.el-collapse-item__content) {
  padding-bottom: 0;
}
</style>
