<template>
  <n-drawer
    to="#main"
    :show="show"
    :on-update:show="close"
    width="2.8rem"
    :mask-closable="false"
  >
    <n-drawer-content title="筛选" closable>
      <div class="content">
        <div class="tabs">
          <div :class="{ on: curTab === 'tag' }" @click="setTab('tag')">
            标签筛选
          </div>
          <div :class="{ on: curTab === 'geo' }" @click="setTab('geo')">
            地理筛选
          </div>
        </div>
        <n-collapse
          v-show="curTab === 'tag'"
          id="tag-filter"
          :default-expanded-names="['1', '2']"
        >
          <template #arrow>
            <n-icon size=".08rem">
              <CaretForward />
            </n-icon>
          </template>
          <n-collapse-item title="党组织" name="1">
            <div class="list">
              <div
                v-for="item in organization"
                :key="item.key"
                :title="`${item.name}（${item.count}个）`"
              >
                <n-checkbox v-model:checked="item.checked" size="small">{{
                  `${item.name}（${item.count}个）`
                }}</n-checkbox>
                <div
                  v-show="item.checked"
                  class="export"
                  @click.prevent="
                    handleExport('organization', item.key, item.name)
                  "
                >
                  导出详表
                  <n-icon size=".1rem">
                    <svg-icon :data="exportIcon" original />
                  </n-icon>
                </div>
              </div>
            </div>
          </n-collapse-item>
          <n-collapse-item title="党员" name="2">
            <div class="member-filter">
              <div>
                <p>党龄筛选</p>
                <n-input-number
                  v-model:value="partyAge"
                  class="input"
                  :min="0"
                  :max="100"
                  size="small"
                  :show-button="false"
                >
                  <template #suffix>年</template>
                </n-input-number>
                <n-space :justify="ageTips ? 'space-between' : 'end'">
                  <span v-if="ageTips" class="num-tips">
                    已筛选出{{ ageTips }}位党员
                  </span>
                  <n-space>
                    <n-button size="tiny" @click="resetMember('age')">
                      重置
                    </n-button>
                    <n-button
                      size="tiny"
                      type="primary"
                      @click="searchMember('age')"
                    >
                      筛选
                    </n-button>
                  </n-space>
                </n-space>
              </div>
              <div>
                <p>入党日期筛选</p>
                <n-space justify="space-between" align="center">
                  <n-date-picker
                    v-model:value="partyStart"
                    class="input"
                    type="date"
                    clearable
                    size="small"
                    :is-date-disabled="disableDateStart"
                  />
                  -
                  <n-date-picker
                    v-model:value="partyEnd"
                    class="input"
                    type="date"
                    clearable
                    size="small"
                    :is-date-disabled="disableDateEnd"
                  />
                </n-space>
                <n-space :justify="dateTips ? 'space-between' : 'end'">
                  <span v-if="dateTips" class="num-tips">
                    已筛选出{{ dateTips }}位党员
                  </span>
                  <n-space>
                    <n-button size="tiny" @click="resetMember('date')">
                      重置
                    </n-button>
                    <n-button
                      size="tiny"
                      type="primary"
                      @click="searchMember('date')"
                    >
                      筛选
                    </n-button>
                  </n-space>
                </n-space>
              </div>
            </div>
            <div class="list">
              <div
                v-for="item in member"
                :key="item.key"
                :title="`${item.name}（${item.count}位）`"
              >
                <n-checkbox v-model:checked="item.checked" size="small">{{
                  `${item.name}（${item.count}位）`
                }}</n-checkbox>
                <div
                  v-show="item.checked"
                  class="export"
                  @click.prevent="handleExport('member', item.key, item.name)"
                >
                  导出详表
                  <n-icon size=".1rem">
                    <svg-icon :data="exportIcon" original />
                  </n-icon>
                </div>
              </div>
            </div>
          </n-collapse-item>
        </n-collapse>
        <div v-show="curTab === 'geo'" id="geo-filter">
          <p class="nav">
            <span v-if="curPath.length > 1" class="pre" @click="toPreStep">
              <n-icon size=".08rem">
                <ArrowBack />
              </n-icon>
              上一页 |
            </span>
            <template v-if="curPath.length > 0">
              <span v-for="(n, i) in curPath" :key="n">
                <span v-if="i !== 0">/</span>
                <b v-if="i === curPath.length - 1">{{ n }}</b>
                <template v-else>{{ n }}</template>
              </span>
            </template>
            <b v-else>社区</b>
          </p>
          <n-tabs v-model:value="curGeo" type="line" size="small">
            <n-tab-pane name="社区" tab="社区" class="geo-list">
              <div
                v-for="(item, i) in areas"
                :key="i"
                :class="{ on: curArea === item }"
                @click="setArea(item)"
              >
                <p>
                  <n-icon class="dot" size=".08rem">
                    <svg-icon :data="dot" />
                  </n-icon>
                  {{ item }}
                </p>
                <span class="next" @click.stop="areaNext(item)">
                  下一级
                  <n-icon class="icon" size=".1rem" color="#dd505E">
                    <ArrowForward />
                  </n-icon>
                </span>
              </div>
            </n-tab-pane>
            <n-tab-pane name="居委" tab="居委" class="geo-list">
              <div
                v-for="(item, i) in committees"
                :key="i"
                :class="{ on: curCommittee === item }"
                @click="setCommittee(item)"
              >
                <p>
                  <n-icon class="dot" size=".08rem">
                    <svg-icon :data="dot" />
                  </n-icon>
                  {{ item }}
                </p>
                <span class="next" @click.stop="committeeNext(item)">
                  下一级
                  <n-icon class="icon" size=".1rem" color="#dd505E">
                    <ArrowForward />
                  </n-icon>
                </span>
              </div>
            </n-tab-pane>
            <n-tab-pane name="小区" tab="小区" class="geo-list">
              <div
                v-for="(item, i) in communities"
                :key="i"
                :class="{ on: curCommunity === item }"
                @click="setCommunity(item)"
              >
                <p>
                  <n-icon class="dot" size=".08rem">
                    <svg-icon :data="dot" />
                  </n-icon>
                  {{ item }}
                </p>
                <span class="next" @click.stop="communityNext(item)">
                  下一级
                  <n-icon class="icon" size=".1rem" color="#dd505E">
                    <ArrowForward />
                  </n-icon>
                </span>
              </div>
            </n-tab-pane>
          </n-tabs>
        </div>
      </div>
    </n-drawer-content>
  </n-drawer>
  <BuildingDrawer
    :list="buildingList"
    :path="curPath"
    :reset-info="checkPathThenFetchInfo"
    :close="close"
    @building="setBuildingBoundary"
  />
</template>

<script lang="ts" setup>
import store from '@/store'
import { computed, ref, watch } from 'vue'
import {
  useFetchOrg,
  useFetchMember,
  useFetchTag,
  useFetchArea,
  useFetchCommittee,
  useFetchCommunity,
  useFetchBuilding,
} from '@/hooks/useFetch'
import useExportXlsx from '@/hooks/useExportXlsx'
import BuildingDrawer from './building-drawer.vue'
import dayjs from '@/util/dayjs'
import { CaretForward, ArrowBack, ArrowForward } from '@vicons/ionicons5'
import exportIcon from '@images/export.svg'
import dot from '@images/dot.svg'
import { useMessage } from 'naive-ui'

const message = useMessage()
const emit = defineEmits(['boundary', 'close'])

const show = computed(() => store.state.showFilterDrawer)
const close = () => {
  store.dispatch('getBasicInfo')
  store.commit('SET_FILTER_DRAWER', false)
  store.commit('SET_SHOW_TAG', true)
  store.commit('SET_CUR_TAG', '')
  emit('close')
}
watch(
  () => show.value,
  (val) => {
    if (!val) {
      reset()
    }
  },
)

const curTab = ref('tag')
const setTab = (val: string) => {
  if (val === 'geo') {
    store.commit('SET_SHOW_TAG', true)
  } else {
    store.commit('SET_SHOW_TAG', false)
  }
  curTab.value = val
}

type Tags = { key: string; name: string; count: number; checked: boolean }[]
const fetchTags = async (type: string): Promise<Tags> => {
  const res = await useFetchTag({
    keys: '标签名称',
    q: `paths @ "所属模块" && string == "${type}"`,
  })
  return Promise.all(
    res.map(async (item: any) => {
      const key = item['标签名称'].replace(type, '').replace('获得', '')
      return {
        name: item['标签名称'],
        key,
        count:
          (await getDetail(type === '党组织' ? 'organization' : 'member', key))
            ?.length || 0,
        checked: false,
      }
    }),
  )
}
const organization = ref<Tags>([])
const getOrgTags = async () => {
  organization.value = await fetchTags('党组织')
}

const member = ref<Tags>([])
const getMemberTags = async () => {
  member.value = await fetchTags('党员')
}
const partyAge = ref<number | null>(null)
const partyStart = ref<number | null>(null)
const partyEnd = ref<number | null>(null)
const disableDateStart = (ts: number) => {
  const cur = dayjs(ts)
  const start = dayjs('1900-01-01')
  let end = dayjs()
  if (partyEnd.value) {
    end = dayjs(partyEnd.value)
  }
  return !cur.isAfter(start) || !cur.isBefore(end)
}
const disableDateEnd = (ts: number) => {
  const cur = dayjs(ts)
  let start = dayjs('1900-01-01')
  const end = dayjs()
  if (partyStart.value) {
    start = dayjs(partyStart.value)
  }
  return !cur.isAfter(start) || !cur.isBefore(end)
}

function reset() {
  organization.value = organization.value.map((item) => ({
    ...item,
    checked: false,
  }))
  member.value = member.value.map((item) => ({ ...item, checked: false }))
  curArea.value = null
  curCommittee.value = null
  curCommunity.value = null
  curTab.value = 'tag'
  curGeo.value = '社区'
}

const areas = ref([])
const committees = ref([])
const communities = ref([])
const getAreas = async () => {
  areas.value = (
    await useFetchArea({
      a: 'id,count',
      keys: '所属社区',
    })
  )
    .map((item: any) => item['所属社区'])
    .filter((item: string) => !!item)
}
const getCommittees = async (name?: string) => {
  const query = name ? `paths @ "所属社区" && string == "${name}"` : undefined
  committees.value = (
    await useFetchCommittee({
      keys: '所属居委',
      q: query,
    })
  )
    .map((item: any) => item['所属居委'])
    .filter((item: string) => !!item)
}
const getCommunities = async (name?: string) => {
  const query = name ? `paths @ "所属居委" && string == "${name}"` : undefined
  communities.value = (
    await useFetchCommunity({
      keys: '居住区名称',
      q: query,
    })
  )
    .map((item: any) => item['居住区名称'])
    .filter((item: string) => !!item)
}

watch(
  () => store.state.auth.code,
  (code) => {
    if (!code) return
    getOrgTags()
    getMemberTags()
    getAreas()
    getCommittees()
    getCommunities()
  },
  { immediate: true },
)

const getDetail = async (type: string, name: string) => {
  let res = []
  switch (type) {
    case 'organization':
      res = await useFetchOrg({
        q: `paths @ "标签" && string @ "${name}",paths @ "党组织编号" && string @ "${store.state.auth.code}"`,
      })
      break
    case 'member':
      if (name === '光荣在党50年') {
        const year = dayjs().subtract(51, 'year').format('YYYY')
        res = await useFetchMember({
          q: `paths @ "加入中共党组织日期" && string @ "${year}",paths @ "党组织编号" && string @ "${store.state.auth.code}"`,
        })
      } else {
        res = await useFetchMember({
          q: `paths @ "标签" && string @ "${name}",paths @ "党组织编号" && string @ "${store.state.auth.code}"`,
        })
      }
      break
    default:
      break
  }
  return res
}

const handleExport = async (type: string, key: string, name: string) => {
  let data = (await getDetail(type, key))?.map((item: any) => item.extra)
  if (type === 'member') {
    data = data.map((item: any) => ({
      姓名: item['姓名'] || '无',
      性别: item['性别'] || '无',
      学历: item['学历'] || '无',
      民族: item['民族'] || '无',
      人户情况: item['人户情况'] || '无',
      党员类型: item['党员类型'] || '无',
      党员身份: item['党员身份'] || '无',
      出生日期: item['出生日期'] || '无',
      所属社区: item['所属社区'] || '无',
      所属居委: item['所属居委'] || '无',
      所属小区: item['所属小区'] || '无',
      所属楼宇: item['所属楼宇'] || '无',
      所属房间: item['所属房间'] || '无',
      身份证号码: item['身份证号码'] || '无',
      党组织编号: item['党组织编号'] || '无',
      所属党组织名称: item['所属党组织名称'] || '无',
      加入中共党组织日期: item['加入中共党组织日期'] || '无',
      是否居住在花木街道: item['是否居住在花木街道'] ? '是' : '否',
    }))
  }
  if (!data || data.length === 0) {
    message.error('暂无数据')
  }
  useExportXlsx(data, name)
}

function resetMember(type) {
  switch (type) {
    case 'age':
      partyAge.value = null
      ageTips.value = ''
      break
    case 'date':
      partyStart.value = null
      partyEnd.value = null
      dateTips.value = ''
      break
    default:
      break
  }
  store.commit('SET_MAP_POINTS')
}
const ageTips = ref('')
const dateTips = ref('')
async function searchMember(type) {
  member.value.forEach((item) => (item.checked = false))
  organization.value.forEach((item) => (item.checked = false))
  const query: string[] = [
    `paths @ "党组织编号" && string @ "${store.state.auth.code}"`,
  ]
  switch (type) {
    case 'age':
      partyStart.value = null
      partyEnd.value = null
      if (partyAge.value) {
        const year = dayjs()
          .subtract(+partyAge.value + 1, 'year')
          .format('YYYY')
        query.push(`paths @ "加入中共党组织日期" && string @ "${year}"`)
      }
      break
    case 'date':
      partyAge.value = null
      if (partyStart.value) {
        query.push(
          `paths @ "加入中共党组织日期" && string >= "${dayjs(
            partyStart.value,
          ).format('YYYY-MM-DD')}"`,
        )
      }
      if (partyEnd.value) {
        query.push(
          `paths @ "加入中共党组织日期" && string <= "${dayjs(
            partyEnd.value,
          ).format('YYYY-MM-DD')}"`,
        )
      }
      break
    default:
      break
  }
  const memData = await useFetchMember({
    q: query.join(','),
  })
  if (type === 'age') {
    ageTips.value =
      (
        await useFetchMember({
          q: query.join(','),
          a: 'id,count',
        })
      )?.[0]?.__aggregate__ + ''
    dateTips.value = ''
  } else if (type === 'date') {
    dateTips.value =
      (
        await useFetchMember({
          q: query.join(','),
          a: 'id,count',
        })
      )?.[0]?.__aggregate__ + ''
    ageTips.value = ''
  }
  const pointData: any[] = []
  memData.forEach(({ extra }) => {
    pointData.push({
      上海2000纬度:
        extra['上海2000纬度'] ||
        extra['居住地上海2000纬度'] ||
        extra['党组织上海2000纬度'],
      上海2000经度:
        extra['上海2000经度'] ||
        extra['居住地上海2000经度'] ||
        extra['党组织上海2000经度'],
      ...extra,
    })
  })
  store.commit('SET_MAP_POINTS', pointData)
}
watch(
  [() => organization.value, () => member.value],
  async ([organization, member]) => {
    const pointData: any[] = []
    const orgKeys = organization.filter((e) => e.checked).map((e) => e.key)
    const memKeys = member.filter((e) => e.checked).map((e) => e.key)
    if ((memKeys && memKeys.length > 0) || (orgKeys && orgKeys.length > 0)) {
      resetMember('age')
      resetMember('date')
    }
    const orgData = await Promise.all(
      orgKeys.map((key) => getDetail('organization', key)),
    )
    const memData = await Promise.all(
      memKeys.map((key) => getDetail('member', key)),
    )
    const total = [...orgData, ...memData]
    total.forEach((item: any[]) => {
      if (!item || item.length === 0) return
      pointData.push(
        ...item.map(({ extra }) => ({
          上海2000纬度:
            extra['上海2000纬度'] ||
            extra['居住地上海2000纬度'] ||
            extra['党组织上海2000纬度'],
          上海2000经度:
            extra['上海2000经度'] ||
            extra['居住地上海2000经度'] ||
            extra['党组织上海2000经度'],
          ...extra,
        })),
      )
    })
    store.commit('SET_MAP_POINTS', pointData)
  },
  { deep: true },
)

const curGeo = ref('社区')
const curArea = ref<string | null>(null)
const curCommittee = ref<string | null>(null)
const curCommunity = ref<string | null>(null)
const setArea = (name: string, causedByNext?: boolean) => {
  if (curArea.value === name && !causedByNext) {
    curArea.value = null
  } else {
    curArea.value = name
  }
}
const setCommittee = (name: string, causedByNext?: boolean) => {
  if (curCommittee.value === name && !causedByNext) {
    curCommittee.value = null
  } else {
    curCommittee.value = name
  }
}
const setCommunity = (name: string, causedByNext?: boolean) => {
  if (curCommunity.value === name && !causedByNext) {
    curCommunity.value = null
  } else {
    curCommunity.value = name
  }
}

const areaNext = async (name: string) => {
  await getCommittees(name)
  setArea(name, true)
  curGeo.value = '居委'
}
const committeeNext = async (name: string) => {
  await getCommunities(name)
  setCommittee(name, true)
  curGeo.value = '小区'
}

const buildingList = ref([])
const getBuildings = async (name: string) => {
  buildingList.value =
    (
      await useFetchBuilding({
        q: `paths @ "楼宇名称" && string @ "${name}"`,
      })
    )?.map((item: any) => item.extra) || []
  store.commit('SET_MAP_POINTS', buildingList.value)
}
const communityNext = async (name: string) => {
  await getBuildings(name)
  setCommunity(name, true)
  store.commit('SET_BUILDING_DRAWER', true)
  store.commit('SET_SHOW_TAG', false)
}
const toPreStep = () => {
  if (curGeo.value === '小区') {
    curCommunity.value = null
    curGeo.value = '居委'
    return
  }
  if (curGeo.value === '居委') {
    curCommittee.value = null
    curGeo.value = '社区'
    return
  }
}

watch(
  () => curGeo.value,
  (cur) => {
    if (cur === '社区') {
      curCommittee.value = null
      curCommunity.value = null
    }
    if (cur === '居委') {
      if (curArea.value) {
        getCommittees(curArea.value)
      } else {
        getCommittees()
      }
      curCommunity.value = null
    } else if (cur === '小区') {
      if (curCommittee.value) {
        getCommunities(curCommittee.value)
      } else {
        curArea.value = null
        getCommunities()
      }
    }
  },
)

const curPath = computed(() => {
  if (curGeo.value === '社区') return [curArea.value || '社区']
  if (curGeo.value === '居委' && !curArea.value)
    return [curCommittee.value || '居委']
  if (curGeo.value === '小区' && !curCommittee.value)
    return [curCommunity.value || '小区']

  const result: string[] = []
  curArea.value && result.push(curArea.value)
  curCommittee.value
    ? result.push(curCommittee.value)
    : curGeo.value === '居委' && result.push('居委')
  curCommunity.value
    ? result.push(curCommunity.value)
    : curGeo.value === '小区' && result.push('小区')
  return result
})

const checkPathThenFetchInfo = () => {
  const area = curArea.value
  const committee = curCommittee.value
  const community = curCommunity.value
  const query: string[] = []
  area && query.push(`paths @ "所属社区" && string == "${area}"`)
  committee && query.push(`paths @ "所属居委" && string == "${committee}"`)
  community && query.push(`paths @ "所属小区" && string == "${community}"`)
  store.dispatch('getBasicInfo', query.length > 0 ? query.join(',') : undefined)
}

function setBuildingBoundary(building: string) {
  if (!building) return
  emit('boundary', { type: 'building', name: building })
}
watch(
  [() => curArea.value, () => curCommittee.value, () => curCommunity.value],
  async ([area, committee, community]) => {
    checkPathThenFetchInfo()
    const { curTag } = store.state
    let query = ''
    if (curTag) {
      query = `,paths @ "类别" && string == "${curTag}"`
    }
    let points: any[] = []
    if (community) {
      emit('boundary', { type: 'community', name: community })
    } else if (committee) {
      points =
        (
          await useFetchOrg({
            q: `paths @ "所属居委" && string == "${committee}"` + query,
          })
        )?.map((item: any) => item.extra) || []
      emit('boundary', { type: 'committee', name: committee })
    } else if (area) {
      points =
        (
          await useFetchOrg({
            q: `paths @ "所属社区" && string == "${area}"` + query,
          })
        )?.map((item: any) => item.extra) || []
      emit('boundary', { type: 'area', name: area })
    }
    if (!store.state.showBuildingDrawer) {
      store.commit('SET_MAP_POINTS', points)
    }
  },
)
watch(
  () => store.state.curTag,
  async (tag) => {
    let query = ''
    if (tag) {
      query = `,paths @ "类别" && string == "${tag}"`
    }
    const area = curArea.value
    const committee = curCommittee.value
    let points: any[] = []
    if (committee) {
      points =
        (
          await useFetchOrg({
            q: `paths @ "所属居委" && string == "${committee}"` + query,
          })
        )?.map((item: any) => item.extra) || []
    } else if (area) {
      points =
        (
          await useFetchOrg({
            q: `paths @ "所属社区" && string == "${area}"` + query,
          })
        )?.map((item: any) => item.extra) || []
    }
    store.commit('SET_MAP_POINTS', points)
  },
)
</script>

<style lang="stylus" scoped>
@import '../../components/MyComponent/main.styl'
.content
  .tabs
    margin .05rem
    $flex-align()
    border-radius .03rem
    border .01rem solid $light-gray
    padding .02rem
    >div
      flex 1
      border-radius inherit
      color $gray
      text-align center
      cursor pointer
      &:hover
      &.on
        background $light-red
        color $red
  .list
    padding .05rem .1rem
    background #f7f7f7
    >div
      border-bottom .01rem solid $light-gray
      padding .08rem 0
      $flex-align()
      justify-content space-between
      .export
        color $red
        cursor pointer
        font-size .08rem
.member-filter
  background #f7f7f7
  padding .05rem .1rem
  >div
    border-bottom .01rem solid $light-gray
    padding .1rem 0
  p
    font-family $font-ping-medium
  .input
    margin .05rem 0
  .num-tips
    color $font
#geo-filter
  .nav
    padding .03rem .1rem
    color #a7afb7
    .pre
      cursor pointer
      &:hover
        color $red
    b
      color #000

  .geo-list
    background #f7f7f7
    >div
      $flex-align()
      justify-content space-between
      border-bottom .01rem solid $light-gray
      padding .06rem 0
      color $font
      cursor pointer
      >p
        flex 1
        $text-overflow()
      &.on
      &:hover
        color $red
        .dot
          color $red
      .dot
        margin 0 .08rem
      .next
        color $red
        cursor pointer
        font-size .09rem
        &:hover
          font-family $font-ping-medium
</style>
<style lang="stylus">
@import '../../components/MyComponent/main.styl'
.n-drawer-mask
  display none
.n-drawer.n-drawer--right-placement
  top .42rem
  .n-drawer-header
    font-family $font-ping-medium
    font-size .14rem
  .n-drawer-body-content-wrapper
    padding 0
    overflow-x hidden !important
    overflow-y auto !important
  .n-drawer-body
    overflow-y auto
#tag-filter
  .n-collapse-item__header
    padding .05rem
    border-top .01rem solid $light-gray
  .n-collapse-item__content-inner
    padding-top 0
  .n-collapse-item
    border-top none
  .n-checkbox
    width 75%
  .n-checkbox__label
    width 90%
    font-size .09rem
    $text-overflow()
    &:hover
      color #ec7281
  .n-checkbox--checked
    .n-checkbox__label
      color $red
  .n-input-number
    width 100%
    .n-input-wrapper
      padding-right 0
    .n-input__suffix
      background #f3f4f7
      border-left .01rem solid $light-gray
      padding 0 .1rem
  .n-date-picker
    width 1.14rem
    .n-input
      background #fff

#geo-filter
  .n-tabs
    .n-tabs-wrapper
      padding .03rem .1rem
    .n-tabs-tab
      color #a7afb7
      font-size .1rem
      padding 0
      &:hover
      &.n-tabs-tab--active
        color $red
    .n-tab-pane
      padding .05rem .1rem
      box-sizing border-box
</style>
