<template>
  <van-popup ref="popup" position="bottom" v-model:show="show" style="background: transparent;"
    @click-overlay="handleClose">
    <!-- 弹窗主体 -->
    <div class="relative w-full bg-white rounded-[12px] overflow-hidden">
      <!-- 头部区域 -->
      <div class="flex items-start justify-between p-[12px] border-b border-[#d9d9d9] bg-white">
        <div class="flex-1 flex flex-col gap-[4px]">
          <span class="text-[18px] font-semibold text-[#333] leading-[1.4]">{{ t("common.calendar.title") }}</span>
          <span v-if="props.rangeRequirePrice" class="text-[14px] text-[#8c8c8c] leading-[1.4]">{{
            t("common.calendar.stayDateHint") }}</span>
        </div>
        <div class="flex items-center justify-center w-[32px] h-[32px] " @click="handleClose">
          <van-icon name="cross" size="20" color="#8c8c8c"></van-icon>
        </div>
      </div>

      <!-- 周标题行 - 固定显示 -->
      <div class="flex p-[16px_12px_8px] bg-white border-b border-[#d9d9d9] border-solid">
        <span class="flex-1 text-center text-[14px] text-[#8c8c8c] font-medium leading-[1.4]" v-for="day in weekDays"
          :key="day">
          {{ day }}
        </span>
      </div>

      <!-- 日历主体区域 -->
      <div
        class="pt-2 px-3 pb-3 max-h-[calc(80vh-140px)] overflow-y-auto [-webkit-overflow-scrolling:touch] scrollbar-none [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden">
        <!-- 全年月份显示区域 -->
        <div class="flex flex-col gap-[32px]">
          <div class="flex flex-col" v-for="monthData in yearMonthsGrid" :key="monthData.key">
            <span class="text-[18px] font-medium text-[#262626] text-center mb-4 mt-2 leading-[1.4]">{{
              monthData.title }}</span>
            <div class="grid grid-cols-7 gap-[4px]">
              <div v-for="(dateInfo, index) in monthData.grid" :key="index" :class="getDateCellClass(dateInfo)"
                @click="handleDateClick(dateInfo)">
                <template v-if="dateInfo">
                  <span v-if="dateInfo.label"
                    class="text-[10px] leading-[12px] px-1 rounded-[2px] whitespace-nowrap font-medium text-center"
                    :class="getDateLabelClass(dateInfo)">
                    {{ dateInfo.label }}
                  </span>
                  <span class="text-[16px] font-medium leading-[18px] flex items-center justify-center"
                    :class="getDateNumberClass(dateInfo)">{{ dateInfo.day }}</span>
                  <span v-if="formatPrice(dateInfo.price)" class="text-[12px] leading-[14px] font-normal text-center"
                    :class="getDatePriceClass(dateInfo)">{{ formatPrice(dateInfo.price) }}</span>
                </template>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </van-popup>
</template>

<script setup>
import {
  ref,
  reactive,
  computed,
  watch,
  onBeforeUnmount,
} from "vue";
import { useI18n } from "vue-i18n";

// 定义组件名称
defineOptions({
  name: "Calendar",
});

const { t } = useI18n();

// van-popup组件引用
const popup = ref(null);
const show = ref(false);

// 定义Props
const props = defineProps({
  // 弹窗显示控制
  visible: {
    type: Boolean,
    default: false,
  },

  // 价格数据数组
  // 格式: [{ date: '2024-05-17', price: 449, stock: 3 }, ...]
  priceData: {
    type: [Object, Array],
    default: () => ({}),
  },

  // 默认选中日期
  defaultValue: {
    type: [String, Array, Object],
    default: "",
  },

  // 选择模式
  mode: {
    type: String,
    default: "single",
    validator: (value) => ["single", "range"].includes(value),
  },

  // 范围选择时是否必须有价格（作为价格区间选择器）
  rangeRequirePrice: {
    type: Boolean,
    default: false,
  },

  // 最小可选日期
  minDate: {
    type: String,
    default: () => new Date().toISOString().split("T")[0],
  },

  // 最大可选日期
  maxDate: {
    type: String,
    default: "",
  },

  // 禁用日期数组
  disabledDates: {
    type: Array,
    default: () => [],
  },

  // 自定义标签
  customLabels: {
    type: Object,
    default: () => ({}),
  },
});

// 定义Emits
const emit = defineEmits([
  "close",
  "select",
  "range-select",
  "date-click",
  "month-change",
]);

// 响应式数据
const weekDays = computed(() => [
  t("common.calendar.weekdays.monday"),
  t("common.calendar.weekdays.tuesday"),
  t("common.calendar.weekdays.wednesday"),
  t("common.calendar.weekdays.thursday"),
  t("common.calendar.weekdays.friday"),
  t("common.calendar.weekdays.saturday"),
  t("common.calendar.weekdays.sunday"),
]);
const selectedDates = ref([]);
const currentYear = ref(new Date().getFullYear());
const isRangeSelecting = ref(false);
const rangeStart = ref(null);
const rangeEnd = ref(null);
const clickTimer = ref(null);

// 计算属性
// 生成从当前月份到明年同月份的日历数据
const yearMonthsGrid = computed(() => {
  const months = [];
  const now = new Date();
  const currentYear = now.getFullYear();
  const startMonth = now.getMonth() + 1; // 从当前月份开始（getMonth()返回0-11，需要+1）
  const totalMonths = 13; // 显示13个月（当前月份到明年同月份）

  for (let i = 0; i < totalMonths; i++) {
    const month = ((startMonth - 1 + i) % 12) + 1;
    const year = currentYear + Math.floor((startMonth - 1 + i) / 12);

    months.push({
      key: `${year}-${month}`,
      title: t("common.calendar.monthTitle", { year, month }),
      year: year,
      month: month,
      grid: generateCalendarGrid(year, month),
    });
  }

  return months;
});

// 获取月份天数
const getDaysInMonth = (year, month) => {
  return new Date(year, month, 0).getDate();
};

// 获取月份第一天是星期几 (0=周日, 1=周一...)
const getFirstDayOfMonth = (year, month) => {
  const day = new Date(year, month - 1, 1).getDay();
  return day === 0 ? 6 : day - 1; // 转换为周一开始 (0=周一, 6=周日)
};

// 获取指定日期的价格项（兼容对象或者数组）
const getPriceItem = (dateStr) => {
  if (!props.priceData) return null;

  // 对象映射格式：{ '2024-05-17': 449 }
  if (!Array.isArray(props.priceData) && typeof props.priceData === "object") {
    if (Object.prototype.hasOwnProperty.call(props.priceData, dateStr)) {
      const val = props.priceData[dateStr];
      // 可能只是数字价格，也可能是对象
      if (val !== null && typeof val === "object") {
        return { date: dateStr, price: val.price, stock: val.stock };
      }
      return { date: dateStr, price: val };
    }
    return null;
  }

  // 数组格式：[{date, price, stock}, ...]
  if (Array.isArray(props.priceData)) {
    const item = props.priceData.find((it) => it.date === dateStr);
    return item || null;
  }

  return null;
};

// 获取价格值便捷函数
const getPriceForDate = (dateStr) => {
  const item = getPriceItem(dateStr);
  return item ? item.price : null;
};

// 生成日历网格数据
const generateCalendarGrid = (year, month) => {
  const daysInMonth = getDaysInMonth(year, month);
  const firstDay = getFirstDayOfMonth(year, month);
  const grid = [];

  // 填充空白格子
  for (let i = 0; i < firstDay; i++) {
    grid.push(null);
  }

  // 填充日期
  for (let day = 1; day <= daysInMonth; day++) {
    const dateStr = `${year}-${String(month).padStart(2, "0")}-${String(
      day,
    ).padStart(2, "0")}`;
    const priceItem = getPriceItem(dateStr);
    grid.push({
      date: dateStr,
      day: day,
      price: priceItem ? priceItem.price : null,
      stock: priceItem ? priceItem.stock : undefined,
      disabled: isDateDisabled(dateStr),
      selected: isDateSelected(dateStr),
      inRange: isDateInRange(dateStr),
      label: getDateLabel(dateStr),
    });
  }

  return grid;
};

// 判断日期是否禁用
const isDateDisabled = (dateStr) => {
  const date = new Date(dateStr);
  const minDate = new Date(props.minDate);
  const maxDate = props.maxDate ? new Date(props.maxDate) : null;

  // 过去或超出范围
  if (date < minDate) return true;
  if (maxDate && date > maxDate) return true;
  if (props.disabledDates.includes(dateStr)) return true;

  // 注意：不在此处基于价格全局禁用日期，
  // 允许未定价的日期被点击作为离店日（结束日），
  // 价格校验在范围完成时对夜晚（不含离店日）进行。
  return false;
};

// 判断日期是否选中
const isDateSelected = (dateStr) => {
  if (props.mode === "single") {
    return selectedDates.value.includes(dateStr);
  } else {
    return dateStr === rangeStart.value || dateStr === rangeEnd.value;
  }
};

// 判断日期是否在选择范围内
const isDateInRange = (dateStr) => {
  if (props.mode !== "range" || !rangeStart.value || !rangeEnd.value) {
    return false;
  }

  const date = new Date(dateStr);
  const start = new Date(rangeStart.value);
  const end = new Date(rangeEnd.value);

  return date > start && date < end;
};

// 获取日期标签
const getDateLabel = (dateStr) => {
  // 优先使用自定义标签
  if (props.customLabels[dateStr]) {
    return props.customLabels[dateStr];
  }

  // 为范围选择模式自动生成住/离标签
  if (props.mode === "range") {
    if (dateStr === rangeStart.value && dateStr === rangeEnd.value) {
      // 当入住和离店是同一天时，显示"住/离"
      return t("common.calendar.labels.stayAndLeave");
    }
    if (dateStr === rangeStart.value) {
      return t("common.calendar.labels.checkIn");
    }
    if (dateStr === rangeEnd.value) {
      return t("common.calendar.labels.checkOut");
    }
  }

  return "";
};

// 获取日期格子样式类
const getDateCellClass = (dateInfo) => {
  if (!dateInfo) return "w-[40px] h-[40px] bg-transparent cursor-default";

  const base =
    "relative w-[40px] h-[40px] flex flex-col items-center justify-center gap-[2px] p-[2px] rounded-[6px] transition-all duration-200 ease-in-out cursor-pointer border active:scale-[0.95]";

  if (dateInfo.disabled) {
    return `${base} border-transparent bg-[#f5f5f5] text-[#bfbfbf] cursor-not-allowed active:scale-100`;
  }

  if (dateInfo.selected) {
    return `${base} border-[#1989fa] bg-[#1989fa]`;
  }

  if (dateInfo.inRange) {
    return `${base} border-[#e6f4ff] bg-[#e6f4ff]`;
  }

  return `${base} border-transparent bg-white hover:bg-[#f5f5f5]`;
};

const formatPrice = (price) => {
  if (price === null || price === undefined || price === "-") return "";
  return `¥${price}`;
};

const getDateNumberClass = (dateInfo) => {
  if (dateInfo.disabled) return "text-[#bfbfbf]";
  if (dateInfo.selected) return "text-white";
  if (dateInfo.inRange) return "text-[#1890ff]";

  const noPrice = dateInfo.price === null || dateInfo.price === undefined || dateInfo.price === "-";
  if (noPrice) return "text-[#262626] opacity-90";

  return "text-[#262626]";
};

const getDatePriceClass = (dateInfo) => {
  const noPrice = dateInfo.price === null || dateInfo.price === undefined || dateInfo.price === "-";
  if (dateInfo.disabled) return "text-[#bfbfbf]";
  if (dateInfo.selected) return "text-white";
  if (dateInfo.inRange) return "text-[#1890ff]";
  if (noPrice) return "text-[#bfbfbf] italic";
  return "text-[#8c8c8c]";
};

const getDateLabelClass = (dateInfo) => {
  if (dateInfo.selected) return "text-white";
  return "text-[#1890ff]";
};

// 处理日期点击
const handleDateClick = (dateInfo) => {
  if (!dateInfo) return;
  if (dateInfo.disabled) {
    showToast(t("common.calendar.errors.disabledDate"));
    // 仍然触发点击事件，供上层参考
    emit("date-click", {
      date: dateInfo.date,
      price: dateInfo.price,
      disabled: dateInfo.disabled,
      selected: dateInfo.selected,
    });
    return;
  }

  // 防抖处理
  if (clickTimer.value) {
    clearTimeout(clickTimer.value);
  }

  clickTimer.value = setTimeout(() => {
    if (props.mode === "single") {
      handleSingleSelect(dateInfo);
    } else if (props.mode === "range") {
      handleRangeSelection(dateInfo);
    }

    // 触发点击事件
    emit("date-click", {
      date: dateInfo.date,
      price: dateInfo.price,
      disabled: dateInfo.disabled,
      selected: dateInfo.selected,
    });
  }, 100);
};

// 处理单选
const handleSingleSelect = (dateInfo) => {
  selectedDates.value = [dateInfo.date];
  emit("select", {
    date: dateInfo.date,
    price: dateInfo.price,
    mode: "single",
  });
};

// 处理范围选择
const handleRangeSelection = (dateInfo) => {
  // 如果当前没有开始日期或已经完成一次选择，则此次点击作为开始日期
  if (!rangeStart.value || (rangeStart.value && rangeEnd.value)) {
    // 开始新的范围选择：当作为价格区间选择器时，开始日必须有价格且有库存
    if (props.rangeRequirePrice) {
      const hasPrice =
        dateInfo.price !== null &&
        dateInfo.price !== undefined &&
        dateInfo.price !== "-";
      if (!hasPrice) {
        showToast(t("common.calendar.errors.dateUnavailable"));
        return;
      }
      if (dateInfo.stock !== undefined && Number(dateInfo.stock) <= 0) {
        showToast(t("common.calendar.errors.stockUnavailable"));
        return;
      }
    }

    rangeStart.value = dateInfo.date;
    rangeEnd.value = null;
    isRangeSelecting.value = true;
    return;
  }

  // 否则为结束日期（完成选择）
  if (rangeStart.value === dateInfo.date) {
    showToast(t("common.calendar.errors.sameDate"));
    return;
  }

  rangeEnd.value = dateInfo.date;
  isRangeSelecting.value = false;

  // 确保开始日期不大于结束日期
  if (new Date(rangeStart.value) > new Date(rangeEnd.value)) {
    [rangeStart.value, rangeEnd.value] = [rangeEnd.value, rangeStart.value];
  }

  // 检查日期跨度是否超过28天
  const daysBetween = calculateDaysBetween(rangeStart.value, rangeEnd.value);
  if (daysBetween > 28) {
    showToast(t("common.calendar.errors.maxRange"));
    rangeStart.value = null;
    rangeEnd.value = null;
    isRangeSelecting.value = false;
    return;
  }

  // 如果作为价格区间选择器，验证夜晚（不包含离店日）是否都有价格/库存
  if (props.rangeRequirePrice) {
    const nights = generateNightsRange(rangeStart.value, rangeEnd.value);
    const missing = nights.find(
      (d) => d.price === null || d.price === undefined || d.price === "-",
    );
    if (missing) {
      showToast(t("common.calendar.errors.missingPrice"));
      rangeStart.value = null;
      rangeEnd.value = null;
      return;
    }

    const badStock = nights.find((d) => {
      const item = getPriceItem(d.date);
      return item && item.stock !== undefined && Number(item.stock) <= 0;
    });
    if (badStock) {
      showToast(t("common.calendar.errors.rangeStockUnavailable"));
      rangeStart.value = null;
      rangeEnd.value = null;
      return;
    }
  }

  const dateRange = generateDateRange(rangeStart.value, rangeEnd.value);

  emit("range-select", {
    startDate: rangeStart.value,
    startPrice: getPriceForDate(rangeStart.value),
    endDate: rangeEnd.value,
    endPrice: getPriceForDate(rangeEnd.value),
    totalDays: daysBetween,
    dateRange: dateRange,
  });
};

// 生成日期范围内所有日期的数组
const generateDateRange = (startDate, endDate) => {
  const dateRange = [];
  const start = new Date(startDate);
  const end = new Date(endDate);

  // 如果是同一天，只返回一个日期
  if (startDate === endDate) {
    return [
      {
        date: startDate,
        price: getPriceForDate(startDate),
      },
    ];
  }

  // 生成范围内所有日期
  const current = new Date(start);
  while (current <= end) {
    const dateStr = current.toISOString().split("T")[0];
    dateRange.push({
      date: dateStr,
      price: getPriceForDate(dateStr),
    });
    current.setDate(current.getDate() + 1);
  }

  return dateRange;
};

// 生成以入住日期为开始、离店日期为结束（离店日不计入夜）的夜晚数组
const generateNightsRange = (startDate, endDate) => {
  const nights = [];
  const start = new Date(startDate);
  const end = new Date(endDate);

  // 若相同日期，视为单晚（保留原有兼容行为）
  if (startDate === endDate) {
    return [
      {
        date: startDate,
        price: getPriceForDate(startDate),
      },
    ];
  }

  const current = new Date(start);
  while (current < end) {
    const dateStr = current.toISOString().split("T")[0];
    nights.push({ date: dateStr, price: getPriceForDate(dateStr) });
    current.setDate(current.getDate() + 1);
  }

  return nights;
};

// 计算两个日期之间的天数
const calculateDaysBetween = (startDate, endDate) => {
  const start = new Date(startDate);
  const end = new Date(endDate);
  const diffTime = Math.abs(end - start);
  const days = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
  // 如果是同一天，返回1天而不是0天
  return days === 0 ? 1 : days;
};

const syncDefaultValue = (value) => {
  selectedDates.value = [];
  rangeStart.value = null;
  rangeEnd.value = null;

  if (!value) return;

  if (Array.isArray(value)) {
    rangeStart.value = value[0] || null;
    rangeEnd.value = value[1] || null;
    return;
  }

  if (typeof value === "object") {
    rangeStart.value = value.startDate || null;
    rangeEnd.value = value.endDate || null;
    return;
  }

  if (props.mode === "range") {
    rangeStart.value = value;
    return;
  }

  selectedDates.value = [value];
};

watch(
  () => props.defaultValue,
  (newValue) => {
    syncDefaultValue(newValue);
  },
  { immediate: true, deep: true },
);

onBeforeUnmount(() => {
  if (clickTimer.value) {
    clearTimeout(clickTimer.value);
  }
});

const open = () => show.value = true;
const close = () => show.value = false;
const handleClose = () => {
  close();
  emit("close");
};

defineExpose({ open, close });
</script>
