<script setup lang="ts" generic="TableType extends Record<string, any>">
import { ref, onMounted, PropType, Ref, watch } from 'vue'
import { CCCard, CCMDIcon, CCInput, CCSelect, CCButton } from '../../index'
import { dateFormat } from './utils/dateFormat'
type ColumnType = {
  name: keyof TableType
  label: string
  type: string
}
const props = defineProps({
  /**
   * テーブル一覧に表示させるオブジェクト
   * 複数のコレクションをjoinしている場合は、joinした後のデータを渡す
   * 検索対象でないものもまとめて渡す
   */
  allTableDetailObj: { type: Array as PropType<TableType[]>, default: [] },
  /**
   * テーブル一覧の見出しに表示させるオブジェクト
   */
  tableTitleObj: {
    type: Array as PropType<ColumnType[]>,
    default: () => [],
  },
})

const emit = defineEmits<{
  (e: 'searchData', value: { searchResults: TableType[]; flag: boolean }): void
  (e: 'allData', value: boolean): void
}>()

/** 詳細検索メニュー表示非常時のフラグ */
const isSearchMenu = ref(false)
/** tableTitleObjにcalendarのtypeプロパティがあるかのフラグ */
const isCalendarArea = ref(false)
/** tableTitleObjにselectのtypeプロパティがあるかのフラグ */
const isSelectArea = ref(false)
/** tableTitleObjにtextのtypeプロパティがあるかのフラグ */
const isTextArea = ref(false)
/** typeプロパティがcalendarのオブジェクトを格納する配列 */
const calendarArray = ref<ColumnType[]>([]) as Ref<ColumnType[]>
/** typeプロパティがselectのオブジェクトを格納する配列 */
const selectArray = ref<ColumnType[]>([]) as Ref<ColumnType[]>
/** カレンダーの開始日付を格納する配列 */
const calendarStart = ref<string[]>([])
/** カレンダーの終了日付を格納する配列 */
const calendarEnd = ref<string[]>([])
/** ドロップダウンで選択された値を格納する配列
 * ドロップダウンが複数あった場合は選択されている値がどんどん追加されていく
 */
const selectValueArray = ref<string[]>([])
/** ドロップダウンの選択肢を格納する配列 */
const selectDataArray = ref<string[][]>([])
/** インプットフォームの入力値を格納 */
const textValue = ref('')

onMounted(() => {
  // tableTitleObjのtypeプロパティによって各フラグを切り替え
  props.tableTitleObj.map(column => {
    if (column.type === 'calendar') isCalendarArea.value = true
    if (column.type === 'select') isSelectArea.value = true
    if (column.type === 'text') isTextArea.value = true
  })

  calendarArray.value = props.tableTitleObj.filter(column => column.type === 'calendar')
  selectArray.value = props.tableTitleObj.filter(column => column.type === 'select')

  // typeプロパティselectのオブジェクトからnameプロパティを抽出
  const tableName: (keyof TableType)[] = selectArray.value.map(column => column.name)

  // allTableDetailObjからselectの選択肢を抽出
  for (let i = 0; i < selectArray.value.length; i++) {
    const tableDataArray: TableType[keyof TableType][] = []
    props.allTableDetailObj.forEach(item => {
      const value = item[tableName[i]]
      if (value !== '-' && !tableDataArray.includes(value)) tableDataArray.push(value)
    })
    selectDataArray.value.push(tableDataArray)
  }

  // 詳細検索メニューの外側をクリックした時にメニューを閉じる
  document.addEventListener('click', e => {
    if (!(e.target as Element).closest('#menuArea') && isSearchMenu.value) {
      searchMenuClose()
    }
  })
})

/**
 * 詳細検索メニューを開く
 */
const searchMenuOpen = (event: MouseEvent) => {
  event.stopPropagation()
  isSearchMenu.value = true
}

/**
 * 詳細検索メニューを閉じる
 */
const searchMenuClose = () => {
  isSearchMenu.value = false
}

/**
 * カレンダーの値をクリアする
 * @param index インデックス
 */
const calendarClear = (index: number) => {
  calendarStart.value[index] = ''
  calendarEnd.value[index] = ''
}

/**
 * ドロップダウンの値をクリアする
 * @param index インデックス
 */
const selectClear = (index: number) => {
  selectValueArray.value[index] = ''
}

/**
 * インプットフォームの値をクリアする
 */
const textClear = () => {
  textValue.value = ''
}

/**
 * 各フォームで入力された全ての値をクリアする
 */
const allClear = () => {
  calendarStart.value = []
  calendarEnd.value = []
  selectValueArray.value = []
  textValue.value = ''
  emit('allData', false)
}

/**
 * 検索対象のデータをemitする
 */
const runSearch = () => {
  let searchResults: TableType[] = props.allTableDetailObj
  type SearchType<T extends Record<string, any>> = { label: keyof TableType; data: T }
  const searchCalendarArray: SearchType<{ start: string; end: string }>[] = []
  const searchSelectArray: SearchType<{ value: string }>[] = []
  // 大文字小文字、全角半角の区別をなくす
  const searchText = textValue.value.toLowerCase().replace(/[Ａ-Ｚａ-ｚ０-９]/g, s => {
    return String.fromCharCode(s.charCodeAt(0) - 0xfee0)
  })

  // typeプロパティがcalendarのオブジェクトを加工
  calendarArray.value.forEach((obj, index) => {
    const calendarObject = { start: calendarStart.value[index], end: calendarEnd.value[index] }
    searchCalendarArray.push({ label: obj.name, data: calendarObject })
  })

  // typeプロパティがselectのオブジェクトを加工
  selectArray.value.forEach((d, index) => {
    const selectObject = { value: selectValueArray.value[index] }
    searchSelectArray.push({ label: d.name, data: selectObject })
  })

  // カレンダーの日付で絞り込み
  searchResults = props.allTableDetailObj.filter((tableObj: TableType) => {
    return searchCalendarArray.every(calendarObj => {
      const startDate = calendarObj.data.start
        ? dateFormat(new Date(calendarObj.data.start.replace(/\/(\d)\//, '-0$1-')), 'YYYY-MM-DD')
        : null
      const endDate = calendarObj.data.end
        ? dateFormat(new Date(calendarObj.data.end.replace(/\/(\d)\//, '-0$1-')), 'YYYY-MM-DD')
        : null
      const targetDate = tableObj[calendarObj.label]
        ? dateFormat(
            new Date(tableObj[calendarObj.label].replace(/\/(\d)\//, '-0$1-')),
            'YYYY-MM-DD'
          )
        : ''
      if (startDate && endDate) {
        return startDate <= targetDate && targetDate <= endDate
      } else if (startDate) {
        return startDate <= targetDate
      } else if (endDate) {
        return targetDate <= endDate
      } else {
        return true
      }
    })
  })

  // ドロップダウンの値で絞り込み
  searchResults = searchResults.filter((tableObj: TableType) => {
    return searchSelectArray.every(selectObj => {
      if (selectObj.data.value) {
        return tableObj[selectObj.label] === selectObj.data.value
      } else {
        return true
      }
    })
  })

  // インプットフォームの値で絞り込み
  searchResults = searchResults.filter((tableObj: TableType) => {
    const objValues = Object.values(tableObj).map((value: TableType) =>
      String(value)
        .toLowerCase()
        .replace(/[Ａ-Ｚａ-ｚ０-９]/g, s => {
          return String.fromCharCode(s.charCodeAt(0) - 0xfee0)
        })
    )
    if (searchText) {
      return objValues.some((value: string) => value.includes(searchText))
    } else {
      return true
    }
  })

  emit('searchData', { searchResults, flag: true })
}
</script>

<template>
  <div class="_serch_container" @click="searchMenuOpen">
    <span class="_serch_text">search</span>
    <CCMDIcon name="manage_search" class="_search_icon" />
  </div>
  <transition name="slide">
    <div class="_back_ground" v-show="isSearchMenu">
      <CCCard id="menuArea" class="_menu_container">
        <CCMDIcon @click="searchMenuClose" name="arrow_forward" class="_arrow_icon" />
        <div class="_feature_container">
          <div v-if="isCalendarArea" class="_form_container">
            <div v-for="(calendar, index) in calendarArray" :key="index" class="_calendar_form">
              <div @click="calendarClear(index)" class="_clear_button">×&thinsp;クリア</div>
              <CCInput
                v-model="calendarStart[index]"
                :label="calendar.label"
                shadow
                date
                placeholder="開始する年月を選択"
              />
              <CCInput v-model="calendarEnd[index]" shadow date placeholder="終了する年月を選択" />
            </div>
          </div>
          <div
            v-if="isSelectArea"
            v-for="(select, index) in selectArray"
            :key="index"
            class="_form_container"
            style="width: 92%"
          >
            <div @click="selectClear(index)" class="_clear_button">×&thinsp;クリア</div>
            <CCSelect
              v-model="selectValueArray[index]"
              :options="selectDataArray[index]"
              :label="select.label"
              shadow
              placeholder="選択してください"
            />
          </div>
          <div v-if="isSelectArea" class="_form_container">
            <div @click="textClear()" class="_clear_button">×&thinsp;クリア</div>
            <CCInput
              v-model="textValue"
              label="フリーワード"
              shadow
              placeholder="フリーワードを入れてください"
            />
          </div>
          <div class="_button_container">
            <CCButton @click="allClear()" style="background: #333333" label="全ての条件をクリア" />
            <CCButton @click="runSearch()" style="background: #00bbc9" label="検索" />
          </div>
        </div>
      </CCCard>
    </div>
  </transition>
</template>

<style lang="sass" scoped>
._serch_container
  display: flex
  align-items: center
  gap: 15px
  position: absolute
  right: 100px
  top: 40px
  cursor: pointer
  transition: 0.3s
._serch_container:hover
  opacity: 0.7

._serch_text
  font-size: 20px

._search_icon
  font-size: 40px

._menu_container
  background: #D2D2D2
  width: 325px
  // max-height: 100vh
  min-height: 100%
  position: absolute
  top: 0
  right: 0
  z-index: 1

._feature_container
  width: 80%
  margin: 20px auto 0 auto
  display: flex
  flex-direction: column
  row-gap: 20px

._form_container
  display: flex
  flex-direction: column
  row-gap: 20px
  position: relative

._calendar_form
  display: flex
  flex-direction: column
  row-gap: 10px

._clear_button
  font-size: 12px
  font-weight: bold
  color: var(--pm-text-black)
  position: absolute
  right: 0
  z-index: 1
  cursor: pointer

._back_ground
  position: absolute
  top: 0
  right: 0
  width: 100%
  height: 100vh
  overflow-y: scroll

._button_container
  display: flex
  flex-direction: column
  row-gap: 20px
  margin-top: 60px
  margin-bottom: 80px

._arrow_icon
  font-size: 50px
  font-weight: bold
  color: #333333
  margin: 10px 0 0 10px
  cursor: pointer
  transition: 0.3s

::v-deep(._select_form_container)
  background-color: white

._arrow_icon:hover
  opacity: 0.7

.slide-enter-active, .slide-leave-active
  transition: transform 0.5s ease

.slide-enter-from, .slide-leave-to
  transform: translateX(100%)

.slide-enter-to, .slide-leave-from
  transform: translateX(0)
</style>
