<script setup lang="ts">
import { EventEnum } from "@/constant/enums";

const { t } = useI18n();
import dayjs from "dayjs";

const storeBusinessHours = ref('');
const onlySelectDay = ref(true);

import { parseDeliveryScheduleTimes, isDeliveryScheduleDay } from '@/utils/deliverySchedule';

const allowedWeekdays = ref<number[]>([]);
const isAllowedDay = (date: Date): boolean => {
  return isDeliveryScheduleDay(date, allowedWeekdays.value);
};

interface BusinessHours {
  days: string[];
  startTime: string;
  endTime: string;
}

const parseBusinessHours = (businessHoursStr: string): BusinessHours[] => {
  if (!businessHoursStr) return [];

  const businessHours: BusinessHours[] = [];
  const segments = businessHoursStr.split(";");

  segments.forEach((segment) => {
    const trimmedSegment = segment.trim();
    if (!trimmedSegment) return;

    const parts = trimmedSegment.split(" ");
    if (parts.length !== 2) return;

    const dayStr = parts[0].trim().toUpperCase();
    const timeStr = parts[1];

    const timeRange = timeStr.split("-");
    if (timeRange.length !== 2) return;

    const startTime = timeRange[0].trim();
    const endTime = timeRange[1].trim();

    const days = dayStr
      .split("/")
      .map((day) => day.trim())
      .filter((day) => day);

    businessHours.push({
      days,
      startTime,
      endTime,
    });
  });

  return businessHours;
};

const getBusinessHoursForDate = (date: Date): BusinessHours | null => {
  if (!storeBusinessHours.value) return null;

  const businessHours = parseBusinessHours(storeBusinessHours.value);

  const dayNames = [
    "SUNDAY",
    "MONDAY",
    "TUESDAY",
    "WEDNESDAY",
    "THURSDAY",
    "FRIDAY",
    "SATURDAY",
  ];
  const dayName = dayNames[date.getDay()];

  return businessHours.find((hours) => hours.days.includes(dayName)) || null;
};

const isDateOpen = (date: Date): boolean => {
  if (!storeBusinessHours.value) return true;
  return getBusinessHoursForDate(date) !== null;
};

const isDateSelectable = (date: Date): boolean => {
  if (!isAllowedDay(date)) {
    return false;
  }

  if (onlySelectDay.value) {
    if (!storeBusinessHours.value) return true;
    return isDateOpen(date);
  }

  if (!storeBusinessHours.value) return true;
  if (!isDateOpen(date)) return false;
  return hasAvailableTimeSlots(date);
};

const dateOptions = computed(() => {
  const dates: Date[] = [];
  const today = new Date();

  for (let i = 0; i < 7; i++) {
    const date = new Date(today);
    date.setDate(today.getDate() + i);
    dates.push(date);
  }

  return dates;
});

const thisWeekDates = computed(() => dateOptions.value.slice(0, 5));
const nextWeekDates = computed(() => dateOptions.value.slice(5, 7));

const selectedDate = ref<Date>();

const isTimeInBusinessHours = (
  hour: number,
  minute: number,
  businessHours: BusinessHours
): boolean => {
  const timeStr = `${hour.toString().padStart(2, "0")}:${minute
    .toString()
    .padStart(2, "0")}`;
  return timeStr >= businessHours.startTime && timeStr <= businessHours.endTime;
};

const hasAvailableTimeSlots = (date: Date): boolean => {
  const now = new Date();
  const currentHour = now.getHours();
  const currentMinute = now.getMinutes();

  const businessHours = getBusinessHoursForDate(date);

  if (!businessHours) {
    return false;
  }

  const [startHour, startMinute] = businessHours.startTime
    .split(":")
    .map(Number);
  const [endHour, endMinute] = businessHours.endTime.split(":").map(Number);

  for (let hour = startHour; hour <= endHour; hour++) {
    for (let minute = 0; minute < 60; minute += 30) {
      if (!isTimeInBusinessHours(hour, minute, businessHours)) {
        continue;
      }

      let nextHour = hour;
      let nextMinute = minute + 30;
      if (nextMinute >= 60) {
        nextHour++;
        nextMinute = 0;
      }

      if (!isTimeInBusinessHours(nextHour, nextMinute, businessHours)) {
        if (
          nextHour > endHour ||
          (nextHour === endHour && nextMinute > endMinute)
        ) {
          nextHour = endHour;
          nextMinute = endMinute;
        }
      }

      if (hour === nextHour && minute === nextMinute) {
        continue;
      }

      if (date.toDateString() === now.toDateString()) {
        if (
          hour < currentHour ||
          (hour === currentHour && minute <= currentMinute)
        ) {
          continue;
        }
      }

      return true;
    }
  }

  return false;
};

const userPickedDate = ref(false);

/** 从今天起查找最近可配送日（配送日 + 营业时间） */
const findNearestDeliverableDate = (maxDays = 30): Date | null => {
  const today = new Date();
  today.setHours(0, 0, 0, 0);
  for (let i = 0; i <= maxDays; i++) {
    const d = new Date(today);
    d.setDate(today.getDate() + i);
    if (isDateSelectable(d)) {
      return d;
    }
  }
  return null;
};

const initializeSelectedDate = (resetUserPick = false) => {
  if (resetUserPick) {
    userPickedDate.value = false;
  }
  if (userPickedDate.value) {
    return;
  }

  const nearest = findNearestDeliverableDate(30);
  if (nearest) {
    selectedDate.value = nearest;
    selectedTimeSlot.value = "";
    return;
  }

  selectedDate.value = dateOptions.value[0] ?? new Date();
  selectedTimeSlot.value = "";
};

watch(
  () => [...allowedWeekdays.value],
  () => {
    initializeSelectedDate();
  }
);

watch(storeBusinessHours, () => {
  initializeSelectedDate();
});
const selectedTimeSlot = ref<string>("");

const formatWeekdayCircle = (date: Date) => dayjs(date).format("dddd");

const formatCircleSubLine = (date: Date) => {
  if (!isDateSelectable(date)) {
    return t("pages.address.reservationTime.notAvailable");
  }
  return dayjs(date).format("MM/DD");
};

const timeSlots = computed(() => {
  const slots: string[] = [];
  const now = new Date();
  const currentHour = now.getHours();
  const currentMinute = now.getMinutes();

  if (!selectedDate.value) {
    return slots;
  }

  const businessHours = getBusinessHoursForDate(selectedDate.value);

  if (!businessHours) {
    for (let hour = 0; hour < 24; hour++) {
      for (let minute = 0; minute < 60; minute += 30) {
        if (selectedDate.value.toDateString() === now.toDateString()) {
          if (
            hour < currentHour ||
            (hour === currentHour && minute <= currentMinute)
          ) {
            continue;
          }
        }

        const startHour = hour.toString().padStart(2, "0");
        const startMinute = minute.toString().padStart(2, "0");
        const endHour =
          minute === 30
            ? (hour + 1).toString().padStart(2, "0")
            : hour.toString().padStart(2, "0");
        const endMinute = minute === 30 ? "00" : "30";

        const timeSlot = `${startHour}:${startMinute} - ${endHour}:${endMinute}`;
        slots.push(timeSlot);
      }
    }
    return slots;
  }

  const [startHour, startMinute] = businessHours.startTime
    .split(":")
    .map(Number);
  const [endHour, endMinute] = businessHours.endTime.split(":").map(Number);

  for (let hour = startHour; hour <= endHour; hour++) {
    for (let minute = 0; minute < 60; minute += 30) {
      if (!isTimeInBusinessHours(hour, minute, businessHours)) {
        continue;
      }

      let nextHour = hour;
      let nextMinute = minute + 30;
      if (nextMinute >= 60) {
        nextHour++;
        nextMinute = 0;
      }

      if (!isTimeInBusinessHours(nextHour, nextMinute, businessHours)) {
        if (
          nextHour > endHour ||
          (nextHour === endHour && nextMinute > endMinute)
        ) {
          nextHour = endHour;
          nextMinute = endMinute;
        }
      }

      if (hour === nextHour && minute === nextMinute) {
        continue;
      }

      if (selectedDate.value.toDateString() === now.toDateString()) {
        if (
          hour < currentHour ||
          (hour === currentHour && minute <= currentMinute)
        ) {
          continue;
        }
      }

      const startHourStr = hour.toString().padStart(2, "0");
      const startMinuteStr = minute.toString().padStart(2, "0");
      const endHourStr = nextHour.toString().padStart(2, "0");
      const endMinuteStr = nextMinute.toString().padStart(2, "0");

      const timeSlot = `${startHourStr}:${startMinuteStr} - ${endHourStr}:${endMinuteStr}`;
      slots.push(timeSlot);
    }
  }

  return slots;
});

watch(timeSlots, (newSlots) => {
  if (onlySelectDay.value) return;
  if (selectedDate.value && newSlots.length === 0) {
    const nextBusinessDate = findNextBusinessDate(selectedDate.value);
    if (nextBusinessDate) {
      selectedDate.value = nextBusinessDate;
      selectedTimeSlot.value = ""; // 清空已选择的时间段
      uni.showToast({
        title: t('pages.address.reservationTime.noAvailableTime'),
        icon: "none",
        duration: 2000,
      });
    }
  }
});

const findNextBusinessDate = (currentDate: Date): Date | null => {
  const maxDays = 30;
  for (let i = 1; i <= maxDays; i++) {
    const nextDate = new Date(currentDate);
    nextDate.setDate(currentDate.getDate() + i);

    const isInRange = dateOptions.value.some((date) =>
      dayjs(date).isSame(dayjs(nextDate), "day")
    );

    if (
      isInRange &&
      isAllowedDay(nextDate) &&
      isDateOpen(nextDate) &&
      hasAvailableTimeSlots(nextDate)
    ) {
      return nextDate;
    }
  }
  return null;
};

const selectDate = (date: Date) => {
  if (!isDateSelectable(date)) {
    uni.showToast({
      title: t('pages.address.reservationTime.dateNotSelectable'),
      icon: "none",
    });
    return;
  }

  userPickedDate.value = true;
  selectedDate.value = date;
  selectedTimeSlot.value = "";
};

const selectTimeSlot = (timeSlot: string) => {
  selectedTimeSlot.value = timeSlot;
};

const isDateSelected = (date: Date) =>
  !!selectedDate.value && dayjs(selectedDate.value).isSame(dayjs(date), "day");

const submitReservation = () => {
  const dateVal = selectedDate.value;
  if (!dateVal) {
    return;
  }

  if (!onlySelectDay.value) {
    if (!selectedTimeSlot.value) {
      uni.showToast({
        title: t('pages.address.reservationTime.selectTimeSlot'),
        icon: "none",
      });
      return;
    }
  }

  const selectedDateDayjs = dayjs(dateVal);
  let startTime: dayjs.Dayjs;
  let endTime: dayjs.Dayjs;

  if (onlySelectDay.value) {
    const bh = getBusinessHoursForDate(dateVal);
    if (bh) {
      const [startHour, startMinute] = bh.startTime.split(':').map(Number);
      const [endHour, endMinute] = bh.endTime.split(':').map(Number);
      startTime = selectedDateDayjs
        .hour(startHour)
        .minute(startMinute)
        .second(0)
        .millisecond(0);
      endTime = selectedDateDayjs
        .hour(endHour)
        .minute(endMinute)
        .second(0)
        .millisecond(0);
    } else {
      startTime = selectedDateDayjs.startOf('day');
      endTime = selectedDateDayjs.endOf('day');
    }
  } else {
    const [startTimeStr, endTimeStr] = selectedTimeSlot.value.split(' - ');
    const [startHour, startMinute] = startTimeStr.split(':').map(Number);
    const [endHour, endMinute] = endTimeStr.split(':').map(Number);
    startTime = selectedDateDayjs
      .hour(startHour)
      .minute(startMinute)
      .second(0)
      .millisecond(0);
    endTime = selectedDateDayjs
      .hour(endHour)
      .minute(endMinute)
      .second(0)
      .millisecond(0);
  }

  console.log("预约信息:", {
    date: dateVal,
    timeSlot: onlySelectDay.value ? '' : selectedTimeSlot.value,
    startTime: startTime.valueOf(),
    endTime: endTime.valueOf(),
  });

  uni.$emit(EventEnum.CHOOSE_APPOINTMENT_TIME, {
    merchantId: storeId.value,
    date: dateVal,
    timeSlot: onlySelectDay.value ? '' : selectedTimeSlot.value,
    startTime: startTime.valueOf(),
    endTime: endTime.valueOf(),
  });

  uni.showToast({
    title: t('pages.address.reservationTime.reservationSuccess'),
    icon: "none",
  });

  uni.navigateBack();
};

const storeId = ref(null);

onLoad((options: any) => {
  if (options.merchantId) {
    storeId.value = options.merchantId;
  } else if (options.storeId) {
    storeId.value = options.storeId;
  }
  if (options.deliveryScheduleTimes) {
    allowedWeekdays.value = parseDeliveryScheduleTimes(
      decodeURIComponent(options.deliveryScheduleTimes)
    );
  }
  if (options.storeBusinessHours) {
    storeBusinessHours.value = decodeURIComponent(options.storeBusinessHours);
    onlySelectDay.value = true;
  }
  nextTick(() => {
    initializeSelectedDate(true);
  });
});
</script>

<template>
  <view class="reservation-time-page min-h-screen pb-180rpx">
    <navbar
      :title="t('pages.address.reservationTime.pageTitle')"
      circle-back
      custom-class="reservation-time-navbar"
    />
    <view class="reservation-time-body px-40rpx pt-40rpx">
      <view class="date-section">
        <text class="section-label">{{ t("pages.address.reservationTime.thisWeek") }}</text>
        <view class="date-row">
          <view
            v-for="(item, index) in thisWeekDates"
            :key="index"
            class="date-circle"
            :class="{
              'date-circle--selected': isDateSelected(item),
              'date-circle--disabled': !isDateSelectable(item),
            }"
            @click="selectDate(item)"
          >
            <text class="date-circle__weekday">{{ formatWeekdayCircle(item) }}</text>
            <text class="date-circle__sub">{{ formatCircleSubLine(item) }}</text>
          </view>
        </view>
      </view>
      <view v-if="nextWeekDates.length" class="date-section date-section--next">
        <text class="section-label">{{ t("pages.address.reservationTime.nextWeek") }}</text>
        <view class="date-row">
          <view
            v-for="(item, index) in nextWeekDates"
            :key="index"
            class="date-circle"
            :class="{
              'date-circle--selected': isDateSelected(item),
              'date-circle--disabled': !isDateSelectable(item),
            }"
            @click="selectDate(item)"
          >
            <text class="date-circle__weekday">{{ formatWeekdayCircle(item) }}</text>
            <text class="date-circle__sub">{{ formatCircleSubLine(item) }}</text>
          </view>
        </view>
      </view>
    </view>
    <view v-if="!onlySelectDay" class="pb-138rpx mx-40rpx bg-white rounded-24rpx overflow-hidden mt-24rpx">
      <view
        v-for="(timeSlot, index) in timeSlots"
        :key="index"
        class="h-108rpx flex-center-sb px-30rpx"
        :class="[
          index === 0 ? '' : 'border-top',
          timeSlots.length - 1 === index ? 'border-bottom' : '',
        ]"
        @click="selectTimeSlot(timeSlot)"
      >
        <text class="text-32rpx font-regular">{{ timeSlot }}</text>
        <image
          :src="
            selectedTimeSlot === timeSlot
              ? '/static/images/chef/133.png'
              : '/static/images/chef/134.png'
          "
          class="w-48rpx h-48rpx shrink-0"
          mode="aspectFit"
        />
      </view>
    </view>

    <fixed-bottom-large-btn
      class="z-100"
      fixed
      :text="`${t('common.submit')}`"
      @click="submitReservation"
    />
  </view>
</template>

<style scoped lang="scss">
.reservation-time-body {
  box-sizing: border-box;
}

.date-section {
  margin-bottom: 48rpx;

  &--next {
    margin-bottom: 0;
  }
}

.section-label {
  display: block;
  font-size: 32rpx;
  line-height: 44rpx;
  color: #111;
  font-weight: 500;
  margin-bottom: 24rpx;
}

.date-row {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  gap: 20rpx;
  justify-content: flex-start;
}

.date-circle {
  width: 118rpx;
  height: 118rpx;
  border-radius: 50%;
  background-color: #fff;
  box-shadow: 0 8rpx 20rpx rgba(0, 0, 0, 0.06);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  box-sizing: border-box;
}

.date-circle__weekday {
  font-size: 26rpx;
  line-height: 32rpx;
  color: #111;
  font-weight: 500;
}

.date-circle__sub {
  font-size: 22rpx;
  line-height: 28rpx;
  margin-top: 6rpx;
  color: #111;
  opacity: 0.88;
}

.date-circle--selected {
  background-color: #111;
  box-shadow: none;

  .date-circle__weekday,
  .date-circle__sub {
    color: #fff;
    opacity: 1;
  }
}

.date-circle--disabled {
  opacity: 0.45;
}

.date-circle--disabled.date-circle--selected {
  opacity: 1;
}
</style>

<style lang="scss">
page {
  background-color: #f7f7f9;
}

.reservation-time-page :deep(.reservation-time-navbar.wd-navbar) {
  background-color: #f7f7f9 !important;
}
</style>
