<template>
  <view class="calendar">
    <slot name="head" v-bind:currentDate="currentDate">
      <view class="header">
        <view class="btn btn-prev fu-iconfont2" @click="onSwitchPrevMonth()">&#59290;</view>
        <view class="current-date">{{ currentDate }}</view>
        <view class="btn btn-next fu-iconfont2" @click="onSwitchNextMonth()">&#59278;</view>
      </view>
    </slot>
    <view class="body">
      <view class="weeks">
        <view class="week-item" v-for="week in weeks" :key="week">{{ week }}</view>
      </view>
      <view class="day-list">
        <view class="day-item" v-for="(day, index) in dayList" :key="index" @click="handleClick(day)">
          <text v-if="day.checked" class="checked">{{ day.day }}</text>
          <text v-else-if="day.isToday" class="today">{{ day.day }}</text>
          <text v-else-if="day.type === 'current'" class="current-month-day">{{ day.day }}</text>
          <text v-else>{{ day.day }}</text>
        </view>
      </view>
    </view>
  </view>
</template>
<script>
export default {
  name: 'benben-sign-card',
  props: {
    signData: {
      type: Array,
      default() {
        return []
      },
    },
    keyName: {
      type: String,
      default: '',
    },
    currentMonth: {
      type: String,
      default: '',
    },
  },
  data() {
    return {
      setTimeoutFn: null,
      year: null,
      month: null,
      day: null,
      dayList: [],
      weeks: ['日', '一', '二', '三', '四', '五', '六'],
    }
  },
  computed: {
    checks() {
      if (this.keyName) {
        return this.signData.map((item) => item[this.keyName])
      } else {
        return this.signData
      }
    },
    currentDate() {
      const year = this.year
      const month = this.month < 10 ? '0' + this.month : this.month
      return `${year}-${month}`
    },
  },
  watch: {
    checks() {
      this.initDate()
    },
  },
  created() {
    const { year, month, day } = this.getCurrentDate()
    this.initDate(year, month, day)
  },
  methods: {
    // 初始化日期数据
    initDate(year = this.year, month = this.month, day = this.day) {
      // 获取日期列表
      const dayList = this.getDayList(year, month)
      // 更新年月日以及日期列表
      this.year = year
      this.month = month
      this.day = day
      this.dayList = dayList
    },
    // 处理点击事件
    handleClick(day) {
      // 构造数据
      const payload = {
        year: this.year,
        month: this.month,
        ...day,
      }
      // 根据日期类型，执行相应操作
      switch (day.type) {
        case 'prev':
          this.onSwitchPrevMonth(day)
          break
        case 'next':
          this.onSwitchNextMonth(day)
          break
        default:
          this.$emit('current-month-day', payload)
      }
    },
    // 切换到上一个月
    onSwitchPrevMonth(day) {
      // 获取上一个月的年月信息
      const { prevYear, prevMonth } = this.getPrevMonthInfo(this.year, this.month)
      // 构造数据
      const payload = {
        year: prevYear,
        month: prevMonth,
        oldYear: this.year,
        oldMonth: this.month,
        ...day,
      }
      // 初始化日期数据
      this.initDate(prevYear, prevMonth)
      // 触发事件
      this.$emit('update:current-month', this.currentDate)
      this.emitChange(payload)
    },
    // 切换到下一个月
    onSwitchNextMonth(day) {
      // 获取下一个月的年月信息
      const { nextYear, nextMonth } = this.getNextMonthInfo(this.year, this.month)
      // 构造数据
      const payload = {
        year: nextYear,
        month: nextMonth,
        oldYear: this.year,
        oldMonth: this.month,
        ...day,
      }
      // 初始化日期数据
      this.initDate(nextYear, nextMonth)
      // 修改current-month的值
      this.$emit('update:current-month', this.currentDate)
      // 触发事件
      this.emitChange(payload)
    },
    // 触发change
    emitChange(payload) {
      this.setTimeoutFn && clearTimeout(this.setTimeoutFn)
      this.setTimeoutFn = setTimeout(() => {
        this.$emit('change', payload)
      }, 300)
    },
    // 获取上一个月的年月信息
    getPrevMonthInfo(year, month) {
      let prevYear = year
      let prevMonth = month - 1
      if (prevMonth < 1) {
        prevMonth = 12
        prevYear -= 1
      }
      return {
        prevYear,
        prevMonth,
      }
    },
    // 获取下一个月的年月信息
    getNextMonthInfo(year, month) {
      let nextYear = year
      let nextMonth = month + 1
      if (nextMonth > 12) {
        nextMonth = 1
        nextYear += 1
      }
      return {
        nextYear,
        nextMonth,
      }
    },
    // 获取日期列表
    getDayList(year, month) {
      // 获取前一个月的日期列表
      const prevMonthDays = this.getPrevMonthDays(year, month)
      // 获取当前月的日期列表
      const currentMonthDays = this.getCurrentMonthDays(year, month)
      // 获取下一个月的日期列表
      const nextMonthDays = this.getNextMonthDays(year, month)
      // 合并日期列表
      return [...prevMonthDays, ...currentMonthDays, ...nextMonthDays]
    },
    // 获取当前日期
    getCurrentDate() {
      // const date = this.currentMonth ? new Date(this.currentMonth) : new Date()
      const date = new Date()
      const year = date.getFullYear() // 获取当前年份
      const month = date.getMonth() + 1 // 获取当前月份，注意需要加1，因为月份从0开始
      const day = date.getDate() // 获取当前日期
      return {
        year,
        month,
        day,
      }
    },
    // 获取下一个月天数
    getMonthLastDay(year, month) {
      // 根据传入的年份和月份获取下一个月的信息
      const { nextYear, nextMonth } = this.getNextMonthInfo(year, month)
      // 构建一个日期对象，设置为下一个月的第一天
      const date = new Date(`${nextYear}/${nextMonth}/1`)
      // 获取下一个月的第一天的时间戳
      const firstDayTimeStamp = date.getTime()
      const oneDayTimeStamp = 24 * 60 * 60 * 1000 // 一天的毫秒数
      // 上一个月最后一天的日期
      const prevMonthLastDay = new Date(firstDayTimeStamp - oneDayTimeStamp).getDate()
      return prevMonthLastDay
    },
    // 获取上一个月的日期列表
    getPrevMonthDays(year, month) {
      // 根据传入的年份和月份获取上一个月的信息
      const { prevYear, prevMonth } = this.getPrevMonthInfo(year, month)
      // 获取上一个月的最后一天
      const prevMonthLastDay = this.getMonthLastDay(prevYear, prevMonth)
      // 构建一个日期对象，设置为当前月的第一天
      const date = new Date(`${year}/${month}/1`)
      // 获取当前月的第一天是星期几
      const week = date.getDay()
      const days = []
      // 遍历上一个月的日期，并添加到日期列表中
      for (let i = 0; i < week; i++) {
        days.unshift({
          type: 'prev',
          checked: false,
          day: prevMonthLastDay - i, // 依次从上一个月最后一天向前推
        })
      }
      return days
    },
    // 获取当前月天数日期列表
    // 参数：year-年份，month-月份
    getCurrentMonthDays(year, month) {
      // 获取当前月的最后一天
      const currentMonthLastDay = this.getMonthLastDay(year, month)
      // 获取已选日期
      const checks = this.checks
      // 存储当月所有日期的数组
      const days = []
      // 获取当前日期
      const { year: currentYear, month: currentMonth, day: currentDay } = this.getCurrentDate()
      // 遍历当月所有日期
      for (let i = 1; i <= currentMonthLastDay; i++) {
        let checked = false
        let isToday = currentYear === year && currentMonth === month && currentDay === i
        // 判断当前日期是否被选中
        checks.forEach((date) => {
          const dateArr = date.split('-')
          if (year == dateArr[0] && month == dateArr[1] && i == dateArr[2]) {
            checked = true
          }
        })
        // 将日期对象添加到数组中
        days.push({
          type: 'current',
          checked,
          isToday,
          day: i,
        })
      }
      return days
    },
    // 获取下一个月天数
    // 参数：year-年份，month-月份
    getNextMonthDays(year, month) {
      // 获取当前月的最后一天
      const currentMonthLastDay = this.getMonthLastDay(year, month)
      // 获取下一个月的最后一天对应的日期
      const date = new Date(`${year}/${month}/${currentMonthLastDay}`)
      // 获取下一个月的第一天是星期几
      const week = date.getDay()
      // 存储下一个月从第一天开始的日期
      const days = []
      let day = 0
      // 遍历下一个月的日期
      for (let i = week + 1; i <= 6; i++) {
        day++
        // 将日期对象添加到数组中
        days.push({
          type: 'next',
          checked: false,
          day,
        })
      }
      return days
    },
  },
}
</script>
<style lang="scss" scoped>
.calendar {
  color: $uni-text-color;
  .header {
    padding: 0 24rpx;
    justify-content: center;
    display: flex;
    align-items: center;
    border-bottom: 2rpx solid #eee;
    .current-date {
      text-align: center;
      font-size: 34rpx;
      padding: 32rpx 0;
      color: #030303;
      margin: 0 24rpx;
    }
    .btn {
      line-height: 1;
      background: #fff;
      border: 1px solid #dcdfe6;
      color: #606266;
      text-align: center;
      box-sizing: border-box;
      font-weight: 500;
      padding: 12rpx 20rpx;
      font-size: 24rpx;
    }
  }
  .body {
    .weeks {
      display: flex;
      font-size: 30rpx;
      padding: 32rpx 0;
      .week-item {
        flex: 1;
        text-align: center;
      }
    }
    .day-list {
      display: flex;
      flex-wrap: wrap;
      .day-item {
        display: flex;
        justify-content: center;
        text-align: center;
        width: 14.285%;
        padding: 15rpx 0;
        font-size: 28rpx;
        color: #c8c8c8;
        line-height: 56rpx;
        .current-month-day {
          color: #171717;
        }
        .today {
          width: 56rpx;
          border-radius: 50%;
          background: var(--benbenbgColor2);
          color: #fff;
        }
        .checked {
          color: #171717;
          border-radius: 50%;
          position: relative;
          &::before {
            position: absolute;
            bottom: 0;
            left: 50%;
            transform: translateX(-50%);
            content: '';
            width: 10rpx;
            height: 10rpx;
            border-radius: 50%;
            background: var(--benbenbgColor7);
          }
        }
      }
    }
  }
}
</style>
