<script lang="ts" setup>
import type { ThingType } from './type';
import dayjs from 'dayjs';

const props = withDefaults(defineProps<Props>(), {
  yStep: 80,
  minuteStep: 80 / 60,
  value: dayjs().valueOf(),
  weekDates: () => [],
  groupedEvents: () => new Map(),
  timeLineWidth: 80,
});

const emit = defineEmits<Emits>();

defineComponent({ name: 'GantView' });

interface Props {
  value?: number // 选中的日期 时间戳
  yStep?: number
  timeLineWidth?: number
  minuteStep?: number
  weekDates?: { date: number, day: string, weekDay: string }[]
  groupedEvents?: Map<number, ThingType[]>
}

interface Emits {
  (e: 'clickThing', value: ThingType): void
}

// Y 轴为 00:00 - 24:00 的时间轴 , 时间步进为 1H , 用dayjs 转换为 00:00 格式
const Y_AXIS = Array.from({ length: 24 }, (_, i) => {
  return {
    label: dayjs().startOf('day').add(i, 'hour').format('HH'),
    top: i * props.yStep,
  };
});

/** ** 正确的格式一定为某一天的起始 */
const selectedDate = computed(() => {
  return dayjs(props.value).startOf('day').valueOf();
});

watch(selectedDate, () => {
  scrollToThing();
});

onMounted(() => {
  // nextTick(() => {
  //   scrollToThing();
  // });
});

function scrollToThing(): number {
  const _thing = props.groupedEvents.get(selectedDate.value);

  const currentTime = dayjs().startOf('minute');

  if (!_thing) {
    return currentTime.diff(currentTime.startOf('day'), 'minute') * props.minuteStep - props.yStep;
  }

  let closestEvent: ThingType | null = null;

  // 查找与当前时刻最接近的事件
  for (const event of _thing) {
    const eventTime = dayjs(event.startTime);
    if (
      !closestEvent
      || Math.abs(eventTime.diff(currentTime)) < Math.abs(dayjs(closestEvent.startTime).diff(currentTime))
    ) {
      closestEvent = event;
    }
  }

  // 如果没有找到与当前时刻最接近的事件，则查找当前时刻未来的第一个事件
  if (!closestEvent) {
    closestEvent = _thing.find(event => dayjs(event.startTime).isAfter(currentTime)) || null;
  }

  // 如果还没有找到，则查找列表中与当前时刻最相近的事件
  if (!closestEvent) {
    closestEvent = _thing.reduce((prev, curr) => {
      const prevDiff = Math.abs(dayjs(prev.startTime).diff(currentTime));
      const currDiff = Math.abs(dayjs(curr.startTime).diff(currentTime));
      return currDiff < prevDiff ? curr : prev;
    });
  }

  // 如果还没有找到，则使用列表中的第一个事件
  if (!closestEvent && _thing[0]) {
    closestEvent = _thing[0];
  }

  if (!closestEvent.toTop)
    closestEvent.toTop = 0;
  return closestEvent.toTop;
}

const scrollTop = computed(() => {
  const top = uni.upx2px(scrollToThing()) - props.yStep / 4;
  return top;
});
</script>

<template>
  <view class="relative flex-1 bg-tertiaryContainer">
    <scroll-view
      :scroll-anchoring="true"
      :scroll-with-animation="true"
      :scroll-top="scrollTop"
      :scroll-y="true"
      class="absolute left-0 top-0 w-full h-full "
    >
      <view class="flex flex-row">
        <!-- time line -->
        <view
          :style="{
            width: `${props.timeLineWidth}rpx`,
          }"
          class="flex flex-col"
        >
          <view
            v-for="(item, inex) in Y_AXIS"
            :key="inex"
            :style="{
              height: `${props.yStep}rpx`,
            }"
          >
            <text
              class="relative block text-20rpx translate-y-[-50%] text-onTertiaryContainer line-height-none text-center"
              :class="{
                'translate-y-0': inex === 0,
              }"
            >
              {{ item.label }}
            </text>
          </view>
        </view>

        <view class="relative flex flex-1 flex-col">
          <!-- 网格 -->
          <view
            class="absolute left-0 top-0 z-1 w-full h-full"
            :style="{
              'background-image': `linear-gradient(to right, #f7f7f7 1rpx,
                transparent 1rpx, transparent calc(100% / 7.5)),
                linear-gradient(to bottom, #f7f7f7 1rpx, transparent 1rpx, transparent ${props.yStep}rpx)`,
              'background-size': `calc(100%/7.5) ${props.yStep}rpx`,
            }"
          />
          <!-- 事件组 分为 7day -->
          <view
            class="z-2 flex flex-1 flex-row"
            :style="{
              width: `calc((100%/7.5)*7)`,
            }"
          >
            <!--
               :style="{
                  'background-color': item.date === selectedDate ? `rgb(var(--primary-100-color) / 0.2)` : 'transparent'
                }"
            -->
            <view
              v-for="(item, index) in props.weekDates"
              :key="index"
              class="relative flex flex-1 transition-background-color will-change-background-color"
            >
              <!-- 'background-color': addColorAlpha(itm.color, 0.06) -->
              <view
                v-for="itm in props.groupedEvents.get(item.date)"
                :key="itm.id"
                class="absolute w-full flex-shrink-0 cursor-pointer flex-self-stretch"
                :style="{
                  top: `${itm.toTop}rpx`,
                  height: `${itm.height}rpx`,
                  background: itm.color,
                  borderTop: `0rpx solid ${itm.color}`,
                }"
                @click="emit('clickThing', itm)"
              >
                <text
                  class="text-28 !text-white"
                  :style="{
                    color: itm.color,
                  }"
                >
                  {{ itm.name }}
                </text>
              </view>
            </view>
          </view>
        </view>
      </view>
    </scroll-view>
  </view>
</template>

<style lang="scss" scoped></style>
