<template>
  <view class="inline-calendar" :style="calendarStyle">
    <view class="calendar-header" v-if="showMonthNav">
      <view class="nav-btn" @click="prevMonth">
        <text class="nav-icon">‹</text>
      </view>
      <text class="month-title">{{ currentYear }}年{{ currentMonth }}月</text>
      <view class="nav-btn" @click="nextMonth">
        <text class="nav-icon">›</text>
      </view>
    </view>

    <view class="weekday-header">
      <view class="weekday-cell" v-for="(day, i) in weekdayLabels" :key="'wd-' + i">
        <text class="weekday-text" :class="{ 'is-weekend': i === 5 || i === 6 }">{{ day }}</text>
      </view>
    </view>

    <view class="days-grid">
      <view
        class="day-row"
        v-for="(week, wi) in weeks"
        :key="wi"
      >
        <view
          class="day-item"
          :class="getDayClass(date)"
          :style="getDayStyle(date)"
          v-for="(date, di) in week"
          :key="di"
          @click="onDateClick(date)"
        >
          <text class="day-number">{{ date.getDate() }}</text>
          <view
            class="mark-dot"
            v-if="isMarked(date) && markType === 'dot'"
          ></view>
        </view>
      </view>
    </view>
  </view>
</template>

<script>
import themeMixin from '@/mixins/themeMixin.js'
import { THEME_CHANGE_EVENT } from '@/utils/theme'

// 周一到周日的完整中文名（展示在日历数字上方）
const WEEKDAY_LABELS = ['一', '二', '三', '四', '五', '六', '日']

export default {
  name: 'InlineCalendar',
  mixins: [themeMixin],
  props: {
    value: {
      type: String,
      default: ''
    },
    markDates: {
      type: Array,
      default: () => []
    },
    markType: {
      type: String,
      default: 'dot'
    },
    rangeSelect: {
      type: Boolean,
      default: false
    },
    startDate: {
      type: String,
      default: ''
    },
    endDate: {
      type: String,
      default: ''
    },
    showMonthNav: {
      type: Boolean,
      default: true
    },
    minDate: {
      type: String,
      default: ''
    },
    maxDate: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      currentDate: new Date(),
      innerStartDate: '',
      innerEndDate: ''
    }
  },
  computed: {
    calendarStyle() {
      return {
        backgroundColor: this.themeConfig.cardBgColor,
        borderRadius: '20rpx'
      }
    },
    weekdayLabels() {
      return WEEKDAY_LABELS
    },
    currentYear() {
      return this.currentDate.getFullYear()
    },
    currentMonth() {
      return this.currentDate.getMonth() + 1
    },
    todayStr() {
      return this.formatDate(new Date())
    },
    weeks() {
      const year = this.currentDate.getFullYear()
      const month = this.currentDate.getMonth()
      const firstDay = new Date(year, month, 1)
      const dayOfWeek = firstDay.getDay()
      const daysSinceMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1
      const gridStart = new Date(year, month, 1 - daysSinceMonday)

      const result = []
      for (let w = 0; w < 6; w++) {
        const week = []
        for (let d = 0; d < 7; d++) {
          const date = new Date(gridStart)
          date.setDate(gridStart.getDate() + w * 7 + d)
          week.push(date)
        }
        result.push(week)
      }
      return result
    },
    effectiveStart() {
      return this.rangeSelect ? (this.startDate || this.innerStartDate) : ''
    },
    effectiveEnd() {
      return this.rangeSelect ? (this.endDate || this.innerEndDate) : ''
    }
  },
  watch: {
    value: {
      immediate: true,
      handler(val) {
        if (val) {
          const d = this.parseDate(val)
          if (d) {
            this.currentDate = new Date(d.getFullYear(), d.getMonth(), 1)
          }
        }
      }
    },
    startDate(val) {
      if (val) this.innerStartDate = val
    },
    endDate(val) {
      if (val) this.innerEndDate = val
    }
  },
  created() {
    this.syncThemeConfig()
    this.watchThemeChange()
    if (this.value) {
      const d = this.parseDate(this.value)
      if (d) {
        this.currentDate = new Date(d.getFullYear(), d.getMonth(), 1)
      }
    }
    if (this.startDate) this.innerStartDate = this.startDate
    if (this.endDate) this.innerEndDate = this.endDate
  },
  beforeUnmount() {
    if (this.themeChangeHandler) {
      uni.$off(THEME_CHANGE_EVENT, this.themeChangeHandler)
    }
  },
  methods: {
    formatDate(date) {
      const y = date.getFullYear()
      const m = String(date.getMonth() + 1).padStart(2, '0')
      const d = String(date.getDate()).padStart(2, '0')
      return `${y}-${m}-${d}`
    },
    parseDate(str) {
      if (!str) return null
      const parts = str.split('-')
      if (parts.length !== 3) return null
      return new Date(parseInt(parts[0]), parseInt(parts[1]) - 1, parseInt(parts[2]))
    },
    isSameDay(d1, d2) {
      return d1.getFullYear() === d2.getFullYear() &&
             d1.getMonth() === d2.getMonth() &&
             d1.getDate() === d2.getDate()
    },
    isToday(date) {
      return this.isSameDay(date, new Date())
    },
    isCurrentMonth(date) {
      return date.getFullYear() === this.currentYear &&
             date.getMonth() === this.currentMonth - 1
    },
    isMarked(date) {
      const str = this.formatDate(date)
      return this.markDates.indexOf(str) !== -1
    },
    isDisabled(date) {
      const str = this.formatDate(date)
      if (this.minDate && str < this.minDate) return true
      if (this.maxDate && str > this.maxDate) return true
      return false
    },
    getDayClass(date) {
      const str = this.formatDate(date)
      const classes = {}
      if (!this.isCurrentMonth(date)) classes['day-item--other-month'] = true
      if (this.isToday(date)) classes['day-item--today'] = true
      if (this.isDisabled(date)) classes['day-item--disabled'] = true

      if (this.rangeSelect) {
        if (this.effectiveStart && this.effectiveEnd) {
          if (str === this.effectiveStart || str === this.effectiveEnd) {
            classes['day-item--selected'] = true
          } else if (str > this.effectiveStart && str < this.effectiveEnd) {
            classes['day-item--in-range'] = true
          }
        } else if (this.effectiveStart && str === this.effectiveStart) {
          classes['day-item--selected'] = true
        }
      } else {
        if (this.value && str === this.value) {
          classes['day-item--selected'] = true
        }
      }

      if (this.isMarked(date) && this.markType === 'bg') {
        classes['day-item--mark-bg'] = true
      }

      return classes
    },
    getDayStyle(date) {
      const styles = {}
      if (this.isToday(date)) {
        styles.borderColor = this.themeConfig.primaryColor
      }
      if (this.isMarked(date) && this.markType === 'bg') {
        styles.backgroundColor = this.themeConfig.primaryColor + '26'
      }
      if (!this.isCurrentMonth(date)) {
        styles.color = this.themeConfig.textDisabled
      }
      return styles
    },
    onDateClick(date) {
      if (this.isDisabled(date)) return
      const str = this.formatDate(date)

      if (this.rangeSelect) {
        if (!this.innerStartDate || (this.innerStartDate && this.innerEndDate)) {
          this.innerStartDate = str
          this.innerEndDate = ''
        } else {
          if (str <= this.innerStartDate) {
            this.innerEndDate = this.innerStartDate
            this.innerStartDate = str
          } else {
            this.innerEndDate = str
          }
          this.$emit('rangeChange', {
            start: this.innerStartDate,
            end: this.innerEndDate
          })
        }
        return
      }

      this.$emit('change', str)
      this.$emit('input', str)
    },
    prevMonth() {
      let y = this.currentYear
      let m = this.currentMonth - 2
      if (m < 0) {
        m = 11
        y--
      }
      this.currentDate = new Date(y, m, 1)
    },
    nextMonth() {
      let y = this.currentYear
      let m = this.currentMonth
      if (m > 11) {
        m = 0
        y++
      }
      this.currentDate = new Date(y, m, 1)
    }
  }
}
</script>

<style lang="scss" scoped>
.inline-calendar {
  padding: 24rpx;
  user-select: none;

  .calendar-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 24rpx;
  }

  .nav-btn {
    width: 60rpx;
    height: 60rpx;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 14rpx;
    transition: background-color 0.2s;
  }

  .nav-btn:active {
    background-color: rgba(0, 0, 0, 0.05);
  }

  .nav-icon {
    font-size: 40rpx;
    color: v-bind('themeConfig.textSecondary');
    font-weight: 300;
  }

  .month-title {
    font-size: 32rpx;
    font-weight: 600;
    color: v-bind('themeConfig.textPrimary');
  }

  .weekday-header {
    display: flex;
    gap: 8rpx;
    margin: 0 auto 16rpx;
    width: 552rpx; /* 与 .day-row 7*72 + 6*8 保持一致 */
  }

  .weekday-cell {
    width: 72rpx;
    flex-shrink: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 36rpx;
    border-radius: 8rpx;
	background-color: v-bind('themeConfig.bgColor');
  }

  .weekday-text {
    font-size: 24rpx;
    font-weight: 600;
    color: v-bind('themeConfig.textSecondary');
    letter-spacing: 1rpx;
  }

  .weekday-text.is-weekend {
    color: v-bind('themeConfig.primaryColor');
  }

  .days-grid {
    display: table;
    flex-direction: column;
    gap: 8rpx;
	margin: 0 auto;
  }

  .day-row {
    display: flex;
    gap: 8rpx;
  }

  .day-item {
    width: 72rpx;
    height: 72rpx;
    border-radius: 10rpx;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    position: relative;
    background-color: transparent;
    transition: all 0.2s ease;
    flex-shrink: 0;
  }

  .day-number {
    font-size: 28rpx;
    color: v-bind('themeConfig.textPrimary');
    line-height: 1;
  }

  .day-item--other-month {
    opacity: 0.25;
  }

  .day-item--other-month .day-number {
    color: v-bind('themeConfig.textDisabled');
  }

  .day-item--today {
    border: 2rpx solid transparent;
    box-sizing: border-box;
  }

  .day-item--today .day-number {
    font-weight: 600;
  }

  .day-item--selected {
    background: v-bind('themeConfig.gradientSoft');
  }

  .day-item--selected .day-number {
    color: #fff;
    font-weight: 600;
  }

  .day-item--in-range {
    background-color: v-bind('themeConfig.primaryColor + "1A"');
    border-radius: 0;
  }

  .day-item--in-range .day-number {
    color: v-bind('themeConfig.primaryColor');
  }

  .day-item--disabled {
    opacity: 0.3;
    pointer-events: none;
  }

  .day-item--mark-bg {
    background-color: v-bind('themeConfig.primaryColor + "26"');
  }

  .mark-dot {
    position: absolute;
    bottom: 8rpx;
    width: 8rpx;
    height: 8rpx;
    border-radius: 50%;
    background-color: v-bind('themeConfig.primaryColor');
  }

  .day-item--selected .mark-dot {
    background-color: #fff;
  }

  .day-item--in-range .mark-dot {
    background-color: v-bind('themeConfig.primaryColor');
  }
}
</style>