<template>
  <div
    class="bg-white py-2 px-2"
    @touchstart="touchStart"
    @touchend="touchEnd"
  >
    <!-- 头部 -->
    <div class="flex">
      <div class="flex-shrink-0 w-11 text-sm flex items-center py-1.5" @click="switchShow">
        <div class="">{{ month }}月</div>
        <app-icon
          :icon-name="open ? 'calendar-open' : 'calendar-close'"
          class-name="h-3 w-3"
        />
      </div>
      <!-- 头部周几 -->
      <div
        v-for="(day, index) in days"
        :key="index"
        class="flex-1 text-sm text-text-secondary text-center py-1.5 opacity-70"
      >
        {{ day }}
      </div>
    </div>
    <!-- 天展示 -->
    <div class="flex text-sm">
      <div class="w-11 flex-shrink-0"/>
      <div class="flex-1 col-span-7 grid grid-cols-7" :class="open ? 'min-h-10' : 'h-10'">
        <div
          v-for="(day, index) in daysShow"
          :key="index"
          class="flex items-center justify-center my-0.5 h-9 relative"
          :class="getDateClass(day)"
          @click="selectDay(day)"
        >
          <span :class="day.year === selectedYear && day.month === selectedMonth && day.date === date ? 'opacity-100' : 'opacity-70'">{{ day.date }}</span>
          <div
            v-if="showDot(day)"
            class="dot h-1 w-1 rounded-full bg-tag-green absolute bottom-0 left-1/2 transform -translate-x-1/2"
          />
        </div>
      </div>
    </div>
  </div>
</template>
<script lang="ts">
import Vue, { PropType } from "vue"

interface Day {
  type: string,
  day: number,
  month: number,
  year: number,
  date: number,
}

type RangeDays = [Date, Date]

export default Vue.extend({
  name: "Calendar",
  components: {
    // 'main-page': () => import('@/layout/main-page.vue'),
    'app-icon': () => import('@/components/common/Icon.vue')
  },
  props: {
    defaultDate: Date as PropType<Date>,
    selectedDays: {
      type: Array as PropType<Date[]>,
      default() {
        return []
      }
    },
    rangeDays: {
      type: Array as PropType<RangeDays[]>,
      default() {
        return []
      }
    },
    select: [Date, null] as PropType<Date>
  },
  data() {
    const daysInMonth: Array<Day> = []
    const daysShow: Array<Day> = []
    return {
      daysInMonth,
      daysShow,
      month: 0,
      year: 0,
      date: 0,
      day: 0,
      selectedYear: 0,
      selectedMonth: 0,
      days: ['日', '一', '二', '三', '四', '五', '六'],
      startX: 0,
      open: false,
      rowIndex: 0, // 缩略状态下展示的天数行
    }
  },
  computed: {
    maxRowIndex(): number {
      return Math.floor(this.daysInMonth.length / 7)
    }
  },
  created() {
    this.init()
  },
  methods: {
    init() {
      // 获取年月日
      const currentDate = this.select || this.defaultDate || new Date()
      this.selectedMonth = this.month = currentDate.getMonth() + 1
      this.selectedYear = this.year = currentDate.getFullYear()
      this.date = currentDate.getDate()
      this.day = currentDate.getDay()
      // 获取月份天数展示
      this.daysInMonth = this.getDaysInMonth(this.year, this.month)
      const {days, index} = this.getDaysShowInShort(this.date, this.daysInMonth)
      this.daysShow = this.open ? this.daysInMonth : days
      this.rowIndex = index
    },
    // 根据日期获取年月日
    getYearMonthDay(val: Date) {
      const year = val.getFullYear()
      const month = val.getMonth() + 1
      const date = val.getDate()
      const day = val.getDay()
      return { year, month, date, day}
    },
    // 切换显示模式
    switchShow() {
      this.open = !this.open
      const check = this.daysInMonth.find(day => this.getTime(day.year, day.month, day.date) === this.getTime(this.selectedYear, this.selectedMonth, this.date))
      let day = 1
      if (typeof check === 'undefined') {
        this.rowIndex = 0
      } else {
        day = this.date
        this.rowIndex = this.getRowIndex(this.date, this.daysInMonth)
      }
      this.daysShow = this.open ? this.daysInMonth : this.getDaysShowInShort(day, this.daysInMonth).days
    },
    // 获取天数展示的行index
    getRowIndex(day: number, daysArr: Array<Day>) {
       const index = daysArr.findIndex(item => item.date === day && item.type === 'current')
       return Math.floor( index / 7 )
    },
    // 缩略情况下显示的天数
    getDaysShowInShort(day: number, daysArr: Array<Day>) {
      const index = this.getRowIndex(day, daysArr)
      return { days: daysArr.slice( index * 7, index * 7 + 7 ), index}
    },
    // 触摸开始
    touchStart(e: TouchEvent) {
      this.startX = e.touches[0].clientX
    },
    // 重新获取月份天数
    getNewMonthDays(type: string) {
      let newYear = 0
      let newMonth = 0
      if (type === 'pre') {
        const { year, month } = this.getPreMonth(this.year, this.month)
        newYear = year
        newMonth = month
      } else {
        const { year, month } = this.getNextMonth(this.year, this.month)
        newYear = year
        newMonth = month
      }
      this.year = newYear
      this.month = newMonth
      this.daysInMonth = this.getDaysInMonth(this.year, this.month)
    },
    // 左右滑动 默认选中设置
    setDefaultSelect() {
      let day: Day
      if (this.open) {
        day = this.daysShow.find(item => item.date === 1 && item.type === 'current') as Day
      } else {
        day = this.daysShow.find(item => item.day === this.day) as Day
      }
      this.$emit('update:select', new Date(day.year, day.month - 1, day.date))
      this.selectedYear = day.year
      this.selectedMonth = day.month
      this.date = day.date
      this.day = day.day
    },
    // 触摸结束
    touchEnd(e: TouchEvent) {
      const end = e.changedTouches[0].clientX
      if (end - this.startX > 40) {
        // 左滑
        if (this.open) {
          // 展开状态
          this.getNewMonthDays('pre')
          this.daysShow = this.daysInMonth
        } else {
          // 缩略状态
          if (this.rowIndex === 0) {
            this.getNewMonthDays('pre')
            this.rowIndex = this.maxRowIndex - 1
          } else {
            this.rowIndex--
          }
          this.daysShow = this.getShowDays(this.rowIndex, this.daysInMonth)
        }
        this.setDefaultSelect()
      }
      if (this.startX - end > 40) {
        // 右滑
        if (this.open) {
          this.getNewMonthDays('next')
          this.daysShow = this.daysInMonth
        } else {
          if (this.rowIndex === this.maxRowIndex - 1) {
            // 切换到下一个月
            this.getNewMonthDays('next')
            this.rowIndex = 0
          } else {
            this.rowIndex++
          }
          this.daysShow = this.getShowDays(this.rowIndex, this.daysInMonth)
        }
        this.setDefaultSelect()
      }
    },
    // 当前有会议的展示圆点
    showDot(day: Day) {
      const date = this.getTime(day.year, day.month, day.date)
      const checkIfNotTripDate = this.checkIfInRangeDays(day, this.rangeDays)
      const index = this.selectedDays.findIndex(day => {
        const { year, month, date: newDate } = this.getYearMonthDay(day)
        return this.getTime(year, month, newDate) === date
      })
      return index > -1 && date !== this.getTime(this.year, this.month, this.date) && !checkIfNotTripDate
    },
    // 查询当前日期是否在日期区间内
    checkIfInRangeDays(targetDay: Day, rangeDays: Array<RangeDays>) {
      const target = this.getTime(targetDay.year, targetDay.month, targetDay.date)
      const index = rangeDays.findIndex(dayArr => {
        const {year: startYear, month: startMonth, date: startDate} = this.getYearMonthDay(dayArr[0])
        const {year: endYear, month: endMonth, date: endDate} = this.getYearMonthDay(dayArr[1])
        return target >= this.getTime(startYear, startMonth, startDate) && target <= this.getTime(endYear, endMonth, endDate)
      })
      return index > -1
    },
    // 会议日期区间显示下划线
    showRangeDateLine(day: Day) {
      return this.checkIfInRangeDays(day, this.rangeDays)
    },
    // 日期样式列表
    getDateClass(day: Day) {
      if (day.type === 'current') {
        if (this.getTime(day.year, day.month, day.date) === this.getTime(this.selectedYear, this.selectedMonth, this.date)) {
          return 'rounded-full bg-color-primary text-white shadow-schedule-selected'
        } else if (this.showRangeDateLine(day)) {
          return 'text-text-secondary border-b border-schedule-line'
        } else {
          return 'text-text-secondary'
        }
      } else {
        return 'text-text-extreme-light'
      }
    },
    // 点击选择日期
    selectDay(day: Day) {
      this.date = day.date
      this.day = day.day
      this.selectedYear = day.year
      this.selectedMonth = day.month
      this.$emit('update:select', new Date(day.year, day.month - 1, day.date))
      switch (day.type) {
        case 'pre': {
          this.getNewMonthDays('pre')
          if (this.open) {
            this.daysShow = this.daysInMonth
          } else {
            this.rowIndex = this.maxRowIndex - 1
            this.daysShow = this.getShowDays(this.rowIndex, this.daysInMonth)
          }
          break
        }
        case 'next': {
          this.getNewMonthDays('next')
          if (this.open) {
            this.daysShow = this.daysInMonth
          } else {
            this.rowIndex = 0
            this.daysShow = this.getShowDays(this.rowIndex, this.daysInMonth)
          }
          break
        }
        default: {
          this.rowIndex = this.getRowIndex(day.date, this.daysInMonth)
        }
      }
    },
    // 获取下一个月
    getNextMonth(year: number, month: number) {
      let newYear = year
      let newMonth = month
      if (newMonth === 12) {
        newMonth = 1
        newYear++
      } else {
        newMonth++
      }
      return { year: newYear, month: newMonth }
    },
    // 获取前一个月
    getPreMonth(year: number, month: number) {
      let newYear = year
      let newMonth = month
      if (newMonth === 1) {
        newMonth = 12
        newYear--
      } else {
        newMonth--
      }
      return { year: newYear, month: newMonth }
    },
    // 获取月份中的天数
    getDaysInMonth(year: number, month: number) {
      const newMonth = month - 1
      const result: Array<Day> = []
      // 一年中每个月的天数
      const daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
      // 闰二月
      if ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0) {
        daysInMonth[1] = 29
      }
      // 当月第一天日期 周几 0-6
      let firstDay = new Date(year, newMonth, 1).getDay()
      // 获取当月一号前几天显示
      for (let i = 0; i < firstDay; i++) {
        result.push({
          type: 'pre',
          day: i,
          year,
          month: newMonth,
          date: daysInMonth[newMonth - 1 < 0 ? 0 : newMonth - 1] - firstDay + 1 + i,
        })
      }
      // 当月日期天数
      for (let i = 0; i < daysInMonth[newMonth]; i++) {
        result.push({
          type: 'current',
          date: i + 1,
          year,
          month: newMonth + 1,
          day: firstDay
        })
        if (firstDay >= 6) {
          firstDay = 0
        } else {
          firstDay++
        }
        // firstDay = firstDay > 6 ? 0 : firstDay++
      }
      // 获取当月最后一天之后显示天数
      for (let i = 0; i < 6 - new Date(year, newMonth + 1, 0).getDay(); i++) {
        result.push({
          type: 'next',
          date: i + 1,
          year,
          month: newMonth + 2,
          day: firstDay
        })
        if (firstDay >= 6) {
          firstDay = 0
        } else {
          firstDay++
        }
      }
      return result
    },
    // new Date().getTime()
    getTime(year: number, month: number, day: number) {
      return new Date(year, month - 1, day).getTime()
    },
    // 获取展示的天数
    getShowDays(index: number, daysArr: Array<Day>) {
      return daysArr.slice(index * 7, index * 7 + 7)
    }
  }
})
</script>

<style lang="scss" scoped>
</style>