<template>
  <transition name="mystic-date-picker">
    <div v-if="isOpen" class="mystic-date-picker-overlay">
      <!-- Backdrop -->
      <div class="mystic-date-picker-backdrop" @click="handleClose"></div>

      <!-- Modal Content -->
      <div class="mystic-date-picker-modal">
        <!-- Header -->
        <div class="mystic-date-picker-header">
          <div class="mystic-date-picker-close" @click="handleClose">
            <CloseIcon :size="22" class="mystic-date-picker-icon" />
          </div>
          <span class="mystic-date-picker-title">{{ title }}</span>
          <div class="mystic-date-picker-confirm" @click="handleConfirm">
            <CheckIcon :size="22" class="mystic-date-picker-icon" />
          </div>
        </div>

        <!-- Picker View -->
        <div class="mystic-date-picker-view">
          <div class="mystic-date-picker-indicator"></div>

          <!-- Year Column -->
          <div class="mystic-date-picker-column" @scroll="handleScroll($event, 0)">
            <div class="mystic-date-picker-padding"></div>
            <div v-for="(y, idx) in years" :key="y" :ref="el => setColumnRef(el, 0, idx)"
              class="mystic-date-picker-item" :class="{ active: pickerValue[0] === idx }" @click="selectItem(0, idx)">
              <span>{{ y }}年</span>
            </div>
            <div class="mystic-date-picker-padding"></div>
          </div>

          <!-- Month Column -->
          <div class="mystic-date-picker-column" @scroll="handleScroll($event, 1)">
            <div class="mystic-date-picker-padding"></div>
            <div v-for="(m, idx) in months" :key="idx" :ref="el => setColumnRef(el, 1, idx)"
              class="mystic-date-picker-item" :class="{ active: pickerValue[1] === idx }" @click="selectItem(1, idx)">
              <span>{{ m }}</span>
            </div>
            <div class="mystic-date-picker-padding"></div>
          </div>

          <!-- Day Column -->
          <div class="mystic-date-picker-column" @scroll="handleScroll($event, 2)">
            <div class="mystic-date-picker-padding"></div>
            <div v-for="(d, idx) in days" :key="d.val" :ref="el => setColumnRef(el, 2, idx)"
              class="mystic-date-picker-item" :class="{ active: pickerValue[2] === idx }" @click="selectItem(2, idx)">
              <span>{{ d.name }}</span>
            </div>
            <div class="mystic-date-picker-padding"></div>
          </div>

          <!-- Time Column -->
          <div class="mystic-date-picker-column" @scroll="handleScroll($event, 3)">
            <div class="mystic-date-picker-padding"></div>
            <div v-for="(s, idx) in shichenOptions" :key="s.id" :ref="el => setColumnRef(el, 3, idx)"
              class="mystic-date-picker-item mystic-date-picker-item-time" :class="{ active: pickerValue[3] === idx }"
              @click="selectItem(3, idx)">
              <span class="mystic-date-picker-time-name">{{ s.name }}</span>
              <span class="mystic-date-picker-time-detail">{{ s.time }}</span>
            </div>
            <div class="mystic-date-picker-padding"></div>
          </div>
        </div>

        <!-- Footer Tip -->
        <div class="mystic-date-picker-footer">
          <span class="mystic-date-picker-tip">{{ footerTip || '滑动列表选择 · 系统自动换算干支' }}</span>
        </div>
      </div>
    </div>
  </transition>
</template>

<script setup lang="ts">
import { ref, computed, watch, nextTick } from 'vue';
import CloseIcon from './icons/CloseIcon.vue';
import CheckIcon from './icons/CheckIcon.vue';

interface Props {
  isOpen: boolean;
  title?: string;
  defaultValue?: string;
  /** 年份列下界（公历，含）。与 maxYear 同时用于自定义区间（如择吉期望范围可选至未来多年） */
  minYear?: number;
  /** 年份列上界（公历，含） */
  maxYear?: number;
  /** 底部提示，便于与其它场景日期选择区分 */
  footerTip?: string;
  /** 为 true 时公历日期不可晚于「今天」（用于择吉期望开始日等） */
  capAtToday?: boolean;
}

const props = withDefaults(defineProps<Props>(), {
  title: '请择良辰',
  defaultValue: '',
  minYear: undefined,
  maxYear: undefined,
  footerTip: '',
  capAtToday: false,
});

const emit = defineEmits<{
  close: [];
  confirm: [val: string, apiVal: string];
}>();

// 时辰对照表
const SHI_CHEN = [
  { id: 'zi', name: '子时', time: '23:00-00:59', hour: '00:00:00' },
  { id: 'chou', name: '丑时', time: '01:00-02:59', hour: '02:00:00' },
  { id: 'yin', name: '寅时', time: '03:00-04:59', hour: '04:00:00' },
  { id: 'mao', name: '卯时', time: '05:00-06:59', hour: '06:00:00' },
  { id: 'chen', name: '辰时', time: '07:00-08:59', hour: '08:00:00' },
  { id: 'si', name: '巳时', time: '09:00-10:59', hour: '10:00:00' },
  { id: 'wu', name: '午时', time: '11:00-12:59', hour: '12:00:00' },
  { id: 'wei', name: '未时', time: '13:00-14:59', hour: '14:00:00' },
  { id: 'shen', name: '申时', time: '15:00-16:59', hour: '16:00:00' },
  { id: 'you', name: '酉时', time: '17:00-18:59', hour: '18:00:00' },
  { id: 'xu', name: '戌时', time: '19:00-20:59', hour: '20:00:00' },
  { id: 'hai', name: '亥时', time: '21:00-22:59', hour: '22:00:00' },
];

const CH_NUM = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十'];
const MONTHS = ['正月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '冬月', '腊月'];

/**
 * 年份列（降序）：默认从当年起共 86 年（生辰等场景，不可超过当年）；
 * 若传入 minYear/maxYear 则按该区间生成（用于择吉期望日期等可选未来多年）。
 */
const years = computed(() => {
  const nowY = new Date().getFullYear();
  const useCustom = props.minYear !== undefined || props.maxYear !== undefined;
  if (!useCustom) {
    const maxY = nowY;
    const minY = maxY - 85;
    return Array.from({ length: 86 }, (_, i) => maxY - i);
  }
  const maxY = props.maxYear ?? nowY;
  const minY = props.minYear ?? maxY - 85;
  const hi = Math.max(minY, maxY);
  const lo = Math.min(minY, maxY);
  return Array.from({ length: hi - lo + 1 }, (_, i) => hi - i);
});
const months = MONTHS;
const shichenOptions = SHI_CHEN;

const pickerValue = ref([0, 0, 0, 0]);
const columnRefs = ref<Array<Array<HTMLElement | null>>>([[], [], [], []]);
const ITEM_HEIGHT = 50;

const setColumnRef = (el: any, columnIdx: number, itemIdx: number) => {
  if (el) {
    if (!columnRefs.value[columnIdx]) {
      columnRefs.value[columnIdx] = [];
    }
    columnRefs.value[columnIdx][itemIdx] = el;
  }
};

const isLeapYear = (year: number): boolean => {
  return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0);
};

const getDaysInMonth = (year: number, month: number): number => {
  const daysMap = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
  if (month === 1 && isLeapYear(year)) {
    return 29;
  }
  return daysMap[month];
};

const getDayName = (d: number): string => {
  if (d <= 10) return `初${CH_NUM[d]}`;
  if (d === 20) return '二十';
  if (d === 30) return '三十';
  if (d < 20) return `十${CH_NUM[d - 10]}`;
  if (d < 30) return `廿${CH_NUM[d - 20]}`;
  return `三十${CH_NUM[d - 30]}`;
};

const days = computed(() => {
  const [yearIdx, monthIdx] = pickerValue.value;
  const year = years.value[yearIdx] || 2000;
  const daysCount = getDaysInMonth(year, monthIdx);

  return Array.from({ length: daysCount }, (_, i) => ({
    val: i + 1,
    name: getDayName(i + 1)
  }));
});

const scrollToIndex = (columnIdx: number, index: number, smooth = true) => {
  const column = document.querySelectorAll('.mystic-date-picker-column')[columnIdx] as HTMLElement;
  if (column) {
    const scrollTop = index * ITEM_HEIGHT;
    column.scrollTo({
      top: scrollTop,
      behavior: smooth ? 'smooth' : 'auto'
    });
  }
};

const selectItem = (columnIdx: number, index: number) => {
  let newValue = [...pickerValue.value];
  newValue[columnIdx] = index;

  // 检查日期是否超出当月天数
  if (columnIdx === 0 || columnIdx === 1) {
    const [yearIdx, monthIdx] = newValue;
    const year = years.value[yearIdx] || 2000;
    const maxDays = getDaysInMonth(year, monthIdx);
    if (newValue[2] >= maxDays) {
      newValue[2] = maxDays - 1;
    }
  }

  newValue = clampPickerValueToTodayMax(newValue, years.value);
  pickerValue.value = newValue;

  nextTick(() => {
    pickerValue.value.forEach((val, idx) => {
      scrollToIndex(idx, val, false);
    });
  });
};

let scrollTimer: number | null = null;

const handleScroll = (e: Event, columnIdx: number) => {
  if (scrollTimer) {
    clearTimeout(scrollTimer);
  }

  scrollTimer = window.setTimeout(() => {
    const target = e.target as HTMLElement;
    const scrollTop = target.scrollTop;
    const index = Math.round(scrollTop / ITEM_HEIGHT);

    selectItem(columnIdx, index);
  }, 150);
};

const parseDefaultValue = (val: string, yearList: number[]) => {
  if (!val) return null;

  const yearMatch = val.match(/(\d+)年/);
  const monthMatch = val.match(/年(.+?)(?:初|十|廿|三十)/);
  const shichenMatch = val.match(/(子|丑|寅|卯|辰|巳|午|未|申|酉|戌|亥)时/);

  if (!yearMatch) return null;

  const year = parseInt(yearMatch[1]);
  const yearIdx = yearList.findIndex(y => y === year);

  let monthIdx = 0;
  if (monthMatch) {
    monthIdx = MONTHS.findIndex(m => m === monthMatch[1]);
    if (monthIdx < 0) monthIdx = 0;
  }

  let dayIdx = 0;
  const dayPart = val.replace(/\d+年/, '').replace(/.*月/, '').replace(/(子|丑|寅|卯|辰|巳|午|未|申|酉|戌|亥)时/, '');
  if (dayPart) {
    for (let i = 1; i <= 31; i++) {
      if (getDayName(i) === dayPart) {
        dayIdx = i - 1;
        break;
      }
    }
  }

  let shichenIdx = 0;
  if (shichenMatch) {
    shichenIdx = SHI_CHEN.findIndex(s => s.name.startsWith(shichenMatch[1]));
    if (shichenIdx < 0) shichenIdx = 0;
  }

  return {
    yearIdx: yearIdx >= 0 ? yearIdx : 0,
    monthIdx,
    dayIdx,
    shichenIdx
  };
};

const clampPickerDay = (parts: number[], yearList: number[]): number[] => {
  if (!yearList.length) return [0, 0, 0, 0];
  const yearIdx = Math.min(Math.max(0, parts[0]), yearList.length - 1);
  const monthIdx = Math.min(Math.max(0, parts[1]), 11);
  const y = yearList[yearIdx] ?? new Date().getFullYear();
  const maxD = getDaysInMonth(y, monthIdx);
  const dayIdx = Math.min(Math.max(0, parts[2]), maxD - 1);
  const shichenIdx = Math.min(Math.max(0, parts[3]), SHI_CHEN.length - 1);
  return [yearIdx, monthIdx, dayIdx, shichenIdx];
};

const getTodayCalendar = () => {
  const n = new Date();
  return { y: n.getFullYear(), m: n.getMonth(), d: n.getDate() };
};

/** capAtToday：将公历日期限制在「今天」及之前 */
const clampPickerValueToTodayMax = (parts: number[], yearList: number[]): number[] => {
  let next = clampPickerDay(parts, yearList);
  if (!props.capAtToday || !yearList.length) return next;

  const t = getTodayCalendar();
  let [yi, mi, di, si] = next;
  const sy = yearList[yi];

  if (sy > t.y) {
    const ti = yearList.findIndex((yr) => yr === t.y);
    if (ti >= 0) next = clampPickerDay([ti, t.m, t.d - 1, si], yearList);
    return next;
  }
  if (sy < t.y) return next;

  if (mi > t.m) {
    next = clampPickerDay([yi, t.m, t.d - 1, si], yearList);
    return next;
  }
  if (mi < t.m) return next;

  if (di > t.d - 1) {
    next = clampPickerDay([yi, mi, t.d - 1, si], yearList);
  }
  return next;
};

watch(() => props.isOpen, (newVal) => {
  if (newVal) {
    const ylist = years.value;
    const parsed = parseDefaultValue(props.defaultValue, ylist);
    if (parsed) {
      const yi = Math.min(Math.max(0, parsed.yearIdx), Math.max(0, ylist.length - 1));
      pickerValue.value = clampPickerValueToTodayMax(
        [yi, parsed.monthIdx, parsed.dayIdx, parsed.shichenIdx],
        ylist
      );
    } else {
      const now = new Date();
      const currentYear = now.getFullYear();
      const yearIdx = ylist.findIndex(y => y === currentYear);
      const monthIdx = now.getMonth();
      const dayIdx = now.getDate() - 1;
      const y = yearIdx >= 0 ? ylist[yearIdx] : ylist[0];
      const pickY = yearIdx >= 0 ? yearIdx : 0;

      pickerValue.value = clampPickerValueToTodayMax(
        [
          pickY,
          monthIdx,
          Math.min(dayIdx, getDaysInMonth(y, monthIdx) - 1),
          0,
        ],
        ylist
      );
    }

    nextTick(() => {
      pickerValue.value.forEach((val, idx) => {
        scrollToIndex(idx, val, false);
      });
    });
  }
});

const handleClose = () => {
  emit('close');
};

const handleConfirm = () => {
  const ylist = years.value;
  pickerValue.value = clampPickerValueToTodayMax(pickerValue.value, ylist);
  const [yearIdx, monthIdx, dayIdx, shichenIdx] = pickerValue.value;
  const selectedYear = years.value[yearIdx] ?? years.value[0];
  const selectedMonth = MONTHS[monthIdx];
  const selectedDay = days.value[dayIdx]?.name || getDayName(dayIdx + 1);
  const selectedShichen = shichenOptions[shichenIdx].name;

  const displayStr = `${selectedYear}年${selectedMonth}${selectedDay}${selectedShichen}`;

  const month = String(monthIdx + 1).padStart(2, '0');
  const day = String(dayIdx + 1).padStart(2, '0');
  const hour = shichenOptions[shichenIdx].hour;
  const apiStr = `${selectedYear}-${month}-${day} ${hour}`;

  emit('confirm', displayStr, apiStr);
  handleClose();
};
</script>

<style scoped>
.mystic-date-picker-overlay {
  position: fixed;
  inset: 0;
  z-index: 999;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}

.mystic-date-picker-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(26, 26, 26, 0.6);
  backdrop-filter: blur(4px);
}

.mystic-date-picker-modal {
  position: relative;
  width: 100%;
  background: #fcfaf5;
  border-top-left-radius: 16px;
  border-top-right-radius: 16px;
  overflow: hidden;
  box-shadow: 0 -8px 32px rgba(0, 0, 0, 0.25);
  border-top: 4px solid #8b2323;
}

.mystic-date-picker-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 20px;
  border-bottom: 1px solid #eaddcf;
  background: #f9f7f2;
}

.mystic-date-picker-close,
.mystic-date-picker-confirm {
  padding: 8px;
  color: #5a5a5a;
  cursor: pointer;
  transition: opacity 0.3s;
  display: flex;
  align-items: center;
  justify-content: center;
}

.mystic-date-picker-close:active,
.mystic-date-picker-confirm:active {
  opacity: 0.6;
}

.mystic-date-picker-confirm {
  color: #8b2323;
}

.mystic-date-picker-icon {
  display: block;
}

.mystic-date-picker-title {
  font-size: 18px;
  font-weight: bold;
  color: #2c2c2c;
  letter-spacing: 0.3em;
  font-family: SimSun, "Songti SC", serif;
}

.mystic-date-picker-view {
  height: 300px;
  width: 100%;
  display: flex;
  position: relative;
  overflow: hidden;
}

.mystic-date-picker-indicator {
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  height: 50px;
  transform: translateY(-50%);
  border-top: 1px solid #dcd3c9;
  border-bottom: 1px solid #dcd3c9;
  background: rgba(139, 35, 35, 0.02);
  pointer-events: none;
  z-index: 1;
}

.mystic-date-picker-column {
  flex: 1;
  height: 100%;
  overflow-y: auto;
  scroll-snap-type: y mandatory;
  -webkit-overflow-scrolling: touch;
}

.mystic-date-picker-column::-webkit-scrollbar {
  display: none;
}

.mystic-date-picker-padding {
  height: 125px;
  flex-shrink: 0;
}

.mystic-date-picker-item {
  height: 50px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  color: #8a8a8a;
  font-family: SimSun, "Songti SC", serif;
  cursor: pointer;
  transition: all 0.3s;
  scroll-snap-align: center;
  flex-shrink: 0;
}

.mystic-date-picker-item.active {
  color: #2c2c2c;
  font-weight: bold;
  font-size: 16px;
}

.mystic-date-picker-item-time {
  gap: 2px;
}

.mystic-date-picker-time-name {
  font-weight: bold;
  font-size: 14px;
}

.mystic-date-picker-item.active .mystic-date-picker-time-name {
  font-size: 16px;
}

.mystic-date-picker-time-detail {
  font-size: 10px;
  opacity: 0.6;
  color: #8a8a8a;
}

.mystic-date-picker-footer {
  background: #f9f7f2;
  padding: 12px;
  text-align: center;
  border-top: 1px solid #eaddcf;
}

.mystic-date-picker-tip {
  font-size: 11px;
  color: #8a8a8a;
  letter-spacing: 0.1em;
}

/* Transition */
.mystic-date-picker-enter-active,
.mystic-date-picker-leave-active {
  transition: opacity 0.3s;
}

.mystic-date-picker-enter-active .mystic-date-picker-modal,
.mystic-date-picker-leave-active .mystic-date-picker-modal {
  transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.mystic-date-picker-enter-from,
.mystic-date-picker-leave-to {
  opacity: 0;
}

.mystic-date-picker-enter-from .mystic-date-picker-modal,
.mystic-date-picker-leave-to .mystic-date-picker-modal {
  transform: translateY(100%);
}
</style>
