<script lang="ts" setup>
import { computed, nextTick, onBeforeMount, onMounted, reactive, ref, shallowRef, unref, watch } from 'vue'
import { CustomFilterModalVue, FilterModalVue, NewFilterModalVue } from './comp/modals'
import Search from './comp/Search.vue'
import AdvanceFilter from './comp/AdvanceFilter.vue'
import { getViewportOffset } from '@/utils/domUtils'
import { useWindowSizeFn } from '@/hooks/event/useWindowSizeFn'
import { useConfig } from '@/store/modules/asideConfig'
import type { Filter } from '/#/home'
import type { AsideEntity } from '@/config/aside'
import { asideMap } from '@/config/aside'
import type { AsideConfig } from '/#/api'
import emitter from '@/utils/mitt'

const configStore = useConfig()

// 所有左侧模块的值
const asideValue: Record<keyof typeof asideMap, any> = reactive({})
// 左侧某个模块是否显示: 显示需同时满足系统配置和个人配置
const asideVisible: Partial<Record<keyof AsideConfig, boolean>> = reactive({})
// 当前显示的模块，按照数组顺序显示
const showItems = shallowRef<{ key: string, config: AsideEntity }[]>([])

Object.keys(asideMap).forEach((key) => {
  const entity = asideMap[key]
  const { defaultValue } = entity
  asideValue[key] = defaultValue
})

const filterModalRef = ref(null)
const newFilterModalRef = ref(null)
const customModalRef = ref(null)

function showModal(modalRef: any) {
  const modal = unref(modalRef)! as any
  modal.showModal()
}

onMounted(() => {
  nextTick(() => {
    computeSlideHeight()
  })
})

const collapse = ref(false)

function collapseHandler() {
  collapse.value = !collapse.value
}

const asideWidth = computed(() => {
  return collapse.value ? 0 : 308
})

const asideHeight = ref(500)
const asideStyle = computed(() => {
  return {
    width: `${asideWidth.value}px`,
    height: `${asideHeight.value}px`,
  }
})

const collapseIcon = computed(() => {
  return collapse.value ? 'expand-cir' : 'collapse-cir'
})

function computeSlideHeight() {
  const headEl = document.querySelector('.aside-header')!
  const { bottomIncludeBody } = getViewportOffset(headEl)
  const height = bottomIncludeBody
  asideHeight.value = height - 24
}

useWindowSizeFn(computeSlideHeight, 280)

onBeforeMount(async () => {
  configStore.fetchConfig()
  configStore.fetchCustomConfig()
})

configStore.$subscribe(() => {
  const config = configStore.getConfig
  const customConfig = configStore.getCustomConfig

  if (config == null || customConfig == null)
    return

  const showKeys = [...customConfig].filter(key => !asideMap[key].isDefaultFilter)
  const defaultKeys = Object.keys(asideMap).filter(key => asideMap[key].isDefaultFilter)
  showKeys.unshift(...defaultKeys)

  Object.keys(config).forEach((key) => {
    if (key.startsWith('iz') && asideMap[key] !== undefined)
      asideVisible[key] = (showKeys.includes(key) || asideMap[key].isDefaultFilter) && config[key] === 'Y'
  })

  const items = showKeys.reduce((acc, key) => {
    const { render } = asideMap[key]

    if (render !== false) {
      const str = key.toLowerCase()

      const o = {
        key: str,
        config: asideMap[str],
      }
      return [...acc, o]
    }
    else {
      return acc
    }
  }, [])

  showItems.value = items
})

const asideEnter = ref(false)

const showCollapse = computed(() => {
  return collapse.value ? true : asideEnter.value
})

const showSearch = ref(false)

function setShowSearch(value: boolean) {
  showSearch.value = value
}

// 滚动容器，让key对应模块处于可视区域
function scrollHandler(key: string) {
  const element = document.querySelector(`#${key}`)
  element?.scrollIntoView(true)
}

// 选择某个过滤配置，刷新图片墙
function filterHandler(filterList: Filter[]) {
  const filerMap: Record<string, any> = {}

  for (const filter of filterList) {
    const { key, value } = filter
    filerMap[key] = value
  }

  emitter.emit('filter', filerMap)
}

function editFilter(filter: any) {
  const modal = unref(newFilterModalRef)! as any
  modal.showModal()
  modal.edit(filter)
}

watch(asideValue, (newVal) => {
  configStore.setAsideValue(newVal)
})
</script>

<template>
  <div class="aside" :style="asideStyle" @mouseenter="asideEnter = true" @mouseleave="asideEnter = false">
    <div v-show="showCollapse" class="aside-collapse">
      <div class="aside-collapse-btn" @click="collapseHandler">
        <SvgIcon :name="collapseIcon" size="40" />
      </div>
    </div>
    <n-scrollbar trigger="none">
      <div class="aside-header">
        <!-- 搜索跳转模块 -->
        <Search v-show="showSearch" @select="scrollHandler" @close="setShowSearch(false)" />
        <!-- 高级筛选 -->
        <AdvanceFilter
          v-show="!showSearch" :type="0" @select="filterHandler" @update:search="setShowSearch(true)"
          @show-custom="showModal(customModalRef)" @show-filter="showModal(filterModalRef)"
        />
      </div>

      <component
        :is="item.config.component" v-for="(item, index) in showItems" :id="item.key" :key="index" v-model:value="asideValue[item.key]"
        :label="item.config.label"
      />

      <!-- 过滤列表 -->
      <FilterModalVue ref="filterModalRef" @edit-filter="editFilter" @show-new-filter="showModal(newFilterModalRef)" />
      <!-- 新增过滤 -->
      <NewFilterModalVue ref="newFilterModalRef" />
      <!-- 筛选 -->
      <CustomFilterModalVue ref="customModalRef" />
    </n-scrollbar>
  </div>
</template>

<style lang="less" scoped>
.aside {
  display: flex;
  position: relative;
  flex-direction: column;
  background: #FFF;
  border: 1px solid #efeff5;
  border-radius: 3px;
  box-sizing: border-box;

  &-header {
    padding: 10px;
    width: 100%;
    border-bottom: 1px solid #e8e8e8;
    margin-bottom: 15px;
  }

  &-divider {
    width: 100%;
    height: 1px;
    background-color: #e8e8e8;
  }

  &-collapse {
    width: 2px;
    height: 100%;
    background: #507afd;
    position: absolute;
    right: 0;
    top: 0;
    z-index: 18;
  }

  &-collapse-btn {
    position: absolute;
    cursor: pointer;
    width: 40px;
    height: 40px;
    top: calc(15%);
    right: -20px;
  }

  ::v-deep(.n-collapse .n-collapse-item.n-collapse-item--right-arrow-placement .n-collapse-item__header .n-collapse-item-arrow) {
    margin-left: 8px;
  }

  ::v-deep(.n-collapse .n-collapse-item .n-collapse-item__header .n-collapse-item__header-main) {
    font-weight: bold;
    justify-content: space-between;
  }

  ::v-deep(.n-collapse .n-collapse-item .n-collapse-item__header) {
    padding: 0px;
  }

  ::v-deep(.n-collapse .n-collapse-item:not(:first-child)) {
    border-top: 0px;
  }

  ::v-deep(.n-collapse .n-collapse-item .n-collapse-item__content-wrapper .n-collapse-item__content-inner) {
    padding-top: 10px;
  }

  ::v-deep(.n-scrollbar > .n-scrollbar-rail.n-scrollbar-rail--vertical > .n-scrollbar-rail__scrollbar, .n-scrollbar + .n-scrollbar-rail.n-scrollbar-rail--vertical > .n-scrollbar-rail__scrollbar) {
    width: 0px;
  }
}
</style>
