<template>
  <view class="calendar-container">
    <!-- 展开/收起按钮，可以外部隐藏 -->
    <view class="calendar-header">
      <button size="mini" @click="toggleMode">
        {{ mode === 'month' ? '收起为周' : '展开为月' }}
      </button>
      <text>{{ displayTitle }}</text>
    </view>

    <view
      class="calendar-content"
      @touchstart="onTouchStart"
      @touchmove="onTouchMove"
      @touchend="onTouchEnd"
      :style="{ height: mode === 'month' ? '450rpx' : '120rpx', transition: 'height 0.3s' }"
    >
      <!-- 星期栏 -->
      <view class="calendar-week">
        <text v-for="(w, i) in weeks" :key="i">{{ w }}</text>
      </view>

      <!-- 日期 -->
      <view class="calendar-days">
        <view
          v-for="(item, i) in renderDays"
          :key="i"
          :class="{
            'calendar-day': true,
            'today': item.isToday,
            'selected': isSelected(item),
            'other-month': item.otherMonth
          }"
          @click="selectDate(item)"
        >
          {{ item.day || '' }}
        </view>
      </view>
    </view>
  </view>
</template>

<script>
export default {
  name: 'CustomCalendar',
  props: {
    initialMode: { type: String, default: 'month' }, // 'month' or 'week'
    initialDate: { type: String, default: '' },
    allowWeekSwitch: { type: Boolean, default: true } // 控制是否允许上下滑切换
  },
  data() {
    const today = new Date()
    return {
      mode: this.initialMode,
      selected: this.initialDate || this.formatDate(today),
      weeks: ['日', '一', '二', '三', '四', '五', '六'],
      renderDays: [],
      touchStartX: 0,
      touchStartY: 0,
      touchMoveX: 0,
      touchMoveY: 0,
      anchorDate: new Date() // 当前视图基准日期
    }
  },
  computed: {
    displayTitle() {
      return `${this.anchorDate.getFullYear()}年${this.anchorDate.getMonth() + 1}月`
    }
  },
  watch: {
    mode() {
      this.generateRenderDays()
    },
    selected() {
      this.generateRenderDays()
    }
  },
  mounted() {
    this.anchorDate = this.safeDate(this.selected)
    this.generateRenderDays()
  },
  methods: {
    // =================== 日期工具 ===================
    formatDate(date) {
      const y = date.getFullYear()
      const m = date.getMonth() + 1
      const d = date.getDate()
      return `${y}-${m < 10 ? '0' + m : m}-${d < 10 ? '0' + d : d}`
    },
    safeDate(date) {
      return new Date(date)
    },
    startOfMonth(date) {
      const d = this.safeDate(date)
      d.setDate(1)
      return d
    },
    startOfWeek(date) {
      const d = this.safeDate(date)
      const day = d.getDay()
      d.setDate(d.getDate() - day)
      return d
    },
    pad(num) {
      return num < 10 ? '0' + num : '' + num
    },

    // =================== 渲染日历 ===================
    generateRenderDays() {
      const days = []
      if (this.mode === 'month') {
        const year = this.anchorDate.getFullYear()
        const month = this.anchorDate.getMonth() + 1
        const firstDayWeek = new Date(year, month - 1, 1).getDay()
        const monthDays = new Date(year, month, 0).getDate()

        // 上月补位
        const lastMonth = month === 1 ? 12 : month - 1
        const lastMonthYear = month === 1 ? year - 1 : year
        const lastMonthDays = new Date(lastMonthYear, lastMonth, 0).getDate()
        for (let i = 0; i < firstDayWeek; i++) {
          days.push({
            day: lastMonthDays - firstDayWeek + 1 + i,
            date: this.formatDate(new Date(lastMonthYear, lastMonth - 1, lastMonthDays - firstDayWeek + 1 + i)),
            otherMonth: true,
            isToday: false
          })
        }

        // 本月
        const todayStr = this.formatDate(new Date())
        for (let i = 1; i <= monthDays; i++) {
          const dateStr = `${year}-${this.pad(month)}-${this.pad(i)}`
          days.push({
            day: i,
            date: dateStr,
            otherMonth: false,
            isToday: dateStr === todayStr
          })
        }

        // 下月补位
        while (days.length % 7 !== 0) {
          const nextDay = days.length - (firstDayWeek + monthDays) + 1
          days.push({
            day: nextDay,
            date: this.formatDate(new Date(month === 12 ? year + 1 : year, month % 12, nextDay)),
            otherMonth: true,
            isToday: false
          })
        }
      } else {
        // 周视图
        const base = this.safeDate(this.selected)
        const weekDay = base.getDay()
        for (let i = 0; i < 7; i++) {
          const d = new Date(base)
          d.setDate(base.getDate() - weekDay + i)
          days.push({
            day: d.getDate(),
            date: this.formatDate(d),
            otherMonth: d.getMonth() !== base.getMonth(),
            isToday: this.formatDate(d) === this.formatDate(new Date())
          })
        }
      }
      this.renderDays = days
    },

    // =================== 事件 ===================
    toggleMode() {
      if (!this.allowWeekSwitch) return
      this.mode = this.mode === 'month' ? 'week' : 'month'
      this.anchorDate = this.mode === 'month' ? this.startOfMonth(this.safeDate(this.selected)) : this.startOfWeek(this.safeDate(this.selected))
      this.generateRenderDays()
    },
    selectDate(item) {
      if (!item.day) return
      this.selected = item.date
      this.$emit('dateChange', item.date)
    },
    isSelected(item) {
      return item.date === this.selected && !item.otherMonth
    },

    // =================== 滑动 ===================
    onTouchStart(e) {
      const t = e.changedTouches[0]
      this.touchStartX = t.clientX
      this.touchStartY = t.clientY
    },
    onTouchMove(e) {
      const t = e.changedTouches[0]
      this.touchMoveX = t.clientX
      this.touchMoveY = t.clientY
    },
    onTouchEnd(e) {
      const t = e.changedTouches[0]
      const endX = t.clientX
      const endY = t.clientY
      const deltaX = endX - this.touchStartX
      const deltaY = endY - this.touchStartY
      const threshold = 40

      // 垂直滑动切换周/月
      if (Math.abs(deltaY) > Math.abs(deltaX) && Math.abs(deltaY) > threshold) {
        if (!this.allowWeekSwitch) return

        if (deltaY < 0 && this.mode !== 'week') {
          this.mode = 'week'
          this.anchorDate = this.startOfWeek(this.safeDate(this.selected))
          this.generateRenderDays()
        } else if (deltaY > 0 && this.mode !== 'month') {
          this.mode = 'month'
          this.anchorDate = this.startOfMonth(this.safeDate(this.selected))
          this.generateRenderDays()
        }
        return
      }

      // 水平滑动翻页
      if (Math.abs(deltaX) > threshold && Math.abs(deltaX) >= Math.abs(deltaY)) {
        if (deltaX < 0) this.slide(1)
        else this.slide(-1)
      }
    },
    slide(direction) {
      if (this.mode === 'month') {
        const y = this.anchorDate.getFullYear()
        let m = this.anchorDate.getMonth() + 1 + direction
        let year = y
        if (m > 12) { m = 1; year++ }
        if (m < 1) { m = 12; year-- }
        this.anchorDate = new Date(year, m - 1, 1)
      } else {
        const d = this.safeDate(this.selected)
        d.setDate(d.getDate() + direction * 7)
        this.selected = this.formatDate(d)
        this.anchorDate = this.startOfWeek(d)
      }
      this.generateRenderDays()
    }
  }
}
</script>

<style scoped>
.calendar-container {
  width: 100%;
  background: #fff;
  border-radius: 12rpx;
  box-shadow: 0 2rpx 16rpx #eee;
  padding: 12rpx;
}
.calendar-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8rpx;
}
.calendar-content {
  overflow: hidden;
}
.calendar-week {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  color: #999;
  font-size: 24rpx;
  padding: 8rpx 0;
  text-align: center;
}
.calendar-days {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  grid-auto-rows: 80rpx; /* 每个格子固定高度 */
}
.calendar-day {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 60rpx;   /* 固定宽度 */
  height: 60rpx;  /* 固定高度，和宽度一致 */
  margin: auto;   /* 居中对齐，避免被挤压 */
  font-size: 30rpx;
  border-radius: 50%;
  transition: background 0.2s;
}
.today {
  color: #007aff;
  font-weight: bold;
  border: 1rpx solid #007aff;
}
.selected {
  background: #007aff;
  color: #fff;
}
.other-month {
  color: #ccc;
}
</style>
