<script setup>
import { computed } from 'vue'
import { useCalendarStore } from '@/stores/CalendarStore'
import {
  getLocalizedWeekdayNames,
  reorderByFirstDay,
  getISOWeek,
  getISOWeekYear,
  MIN_YEAR,
  MAX_YEAR,
} from '@/utils/date'
import Numeric from '@/components/Numeric.vue'
import { addDays } from 'date-fns'

const props = defineProps({
  scrollTop: { type: Number, default: 0 },
  rowHeight: { type: Number, default: 64 },
  minVirtualWeek: { type: Number, default: 0 },
})

const calendarStore = useCalendarStore()

// Emits year-change events
const emit = defineEmits(['year-change'])

const baseDate = computed(() => new Date(1970, 0, 4 + calendarStore.config.first_day))
const WEEK_MS = 7 * 24 * 60 * 60 * 1000

const topVirtualWeek = computed(() => {
  const topDisplayIndex = Math.floor(props.scrollTop / props.rowHeight)
  return topDisplayIndex + props.minVirtualWeek
})

const currentYear = computed(() => {
  const weekStart = addDays(baseDate.value, topVirtualWeek.value * 7)
  const anchor = addDays(weekStart, (4 - weekStart.getDay() + 7) % 7)
  return getISOWeekYear(anchor)
})

function virtualWeekOf(d) {
  const o = (d.getDay() - calendarStore.config.first_day + 7) % 7
  const fd = addDays(d, -o)
  return Math.floor((fd.getTime() - baseDate.value.getTime()) / WEEK_MS)
}

function isoWeekMonday(isoYear, isoWeek) {
  const jan4 = new Date(isoYear, 0, 4)
  const week1Mon = addDays(jan4, -((jan4.getDay() + 6) % 7))
  return addDays(week1Mon, (isoWeek - 1) * 7)
}

function changeYear(y) {
  if (y == null) return
  y = Math.round(Math.max(MIN_YEAR, Math.min(MAX_YEAR, y)))
  if (y === currentYear.value) return
  const vw = topVirtualWeek.value
  // Fraction within current row
  const weekStartScroll = (vw - props.minVirtualWeek) * props.rowHeight
  const frac = Math.max(0, Math.min(1, (props.scrollTop - weekStartScroll) / props.rowHeight))
  // Anchor Thursday of current calendar week
  const curCalWeekStart = addDays(baseDate.value, vw * 7)
  const curAnchorThu = addDays(curCalWeekStart, (4 - curCalWeekStart.getDay() + 7) % 7)
  let isoW = getISOWeek(curAnchorThu)
  // Build Monday of ISO week
  let weekMon = isoWeekMonday(y, isoW)
  if (getISOWeekYear(weekMon) !== y) {
    isoW--
    weekMon = isoWeekMonday(y, isoW)
  }
  // Align to configured first day
  const shift = (weekMon.getDay() - calendarStore.config.first_day + 7) % 7
  const calWeekStart = addDays(weekMon, -shift)
  const targetVW = virtualWeekOf(calWeekStart)
  let scrollTop = (targetVW - props.minVirtualWeek) * props.rowHeight + frac * props.rowHeight
  if (Math.abs(scrollTop - props.scrollTop) < 0.5) scrollTop += 0.25 * props.rowHeight
  emit('year-change', { year: y, scrollTop })
}

const weekdayNames = computed(() => {
  // Reorder names & weekend flags
  const sundayFirstNames = getLocalizedWeekdayNames()
  const reorderedNames = reorderByFirstDay(sundayFirstNames, calendarStore.config.first_day)
  const reorderedWeekend = reorderByFirstDay(calendarStore.weekend, calendarStore.config.first_day)

  return reorderedNames.map((name, i) => ({
    name,
    isWeekend: reorderedWeekend[i],
  }))
})
</script>

<template>
  <div class="calendar-header">
    <div class="year-label">
      <Numeric
        :model-value="currentYear"
        @update:modelValue="changeYear"
        :min="MIN_YEAR"
        :max="MAX_YEAR"
        :step="1"
        aria-label="Year"
        number-prefix=""
        number-postfix=""
      />
    </div>
    <div
      v-for="day in weekdayNames"
      :key="day.name"
      class="dow"
      :class="{ workday: !day.isWeekend, weekend: day.isWeekend }"
    >
      {{ day.name }}
    </div>
    <div class="overlay-header-spacer"></div>
  </div>
</template>

<style scoped>
.calendar-header {
  display: grid;
  grid-template-columns: var(--week-w) repeat(7, 1fr) var(--month-w);
  border-bottom: 2px solid var(--muted);
  align-items: last baseline;
  flex-shrink: 0;
  width: 100%;
  /* Prevent text selection */
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}
.dow {
  text-transform: uppercase;
  text-align: center;
  font-weight: 600;
  font-size: 1.2em;
}
.dow.weekend {
  color: var(--weekend);
}
.dow.workday {
  color: var(--workday);
}
.overlay-header-spacer {
  grid-area: auto;
}
</style>
