<script setup lang="ts">
import { ref, computed, watch, onBeforeUnmount, nextTick } from 'vue'
import { Calendar, ChevronLeft, ChevronRight } from 'lucide-vue-next'
import { getLocaleCode } from '../utils/locale'

interface Props {
  modelValue: string
  placeholder?: string
}

const props = withDefaults(defineProps<Props>(), {
  placeholder: 'Select date',
})

const emit = defineEmits<{
  'update:modelValue': [value: string]
}>()

const isOpen = ref(false)
const triggerRef = ref<HTMLButtonElement | null>(null)
const panelRef = ref<HTMLDivElement | null>(null)
const panelStyle = ref<Record<string, string>>({})

// The month/year currently displayed in the calendar
const viewYear = ref(new Date().getFullYear())
const viewMonth = ref(new Date().getMonth()) // 0-indexed

// ── Formatting ──────────────────────────────────────────────────────
const displayText = computed(() => {
  if (!props.modelValue) return null
  const [y, m, d] = props.modelValue.split('-').map(Number)
  const date = new Date(y, m - 1, d)
  return date.toLocaleDateString(getLocaleCode(), {
    month: 'short',
    day: 'numeric',
    year: 'numeric',
  })
})

const viewMonthLabel = computed(() => {
  const date = new Date(viewYear.value, viewMonth.value, 1)
  return date.toLocaleDateString(getLocaleCode(), { month: 'long', year: 'numeric' })
})

// ── Today helpers ───────────────────────────────────────────────────
function todayString(): string {
  const now = new Date()
  return formatDate(now.getFullYear(), now.getMonth(), now.getDate())
}

function formatDate(y: number, m: number, d: number): string {
  const mm = String(m + 1).padStart(2, '0')
  const dd = String(d).padStart(2, '0')
  return `${y}-${mm}-${dd}`
}

// ── Calendar grid ───────────────────────────────────────────────────
interface DayCell {
  date: number
  month: number   // 0-indexed
  year: number
  isCurrentMonth: boolean
  dateString: string
}

const dayCells = computed<DayCell[]>(() => {
  const y = viewYear.value
  const m = viewMonth.value

  // First day of the month (0=Sun, 1=Mon, ...)
  const firstDayOfWeek = new Date(y, m, 1).getDay()
  // Shift so Monday=0
  const startOffset = (firstDayOfWeek + 6) % 7

  const daysInMonth = new Date(y, m + 1, 0).getDate()
  const daysInPrevMonth = new Date(y, m, 0).getDate()

  const cells: DayCell[] = []

  // Previous month padding
  const prevMonth = m === 0 ? 11 : m - 1
  const prevYear = m === 0 ? y - 1 : y
  for (let i = startOffset - 1; i >= 0; i--) {
    const d = daysInPrevMonth - i
    cells.push({
      date: d,
      month: prevMonth,
      year: prevYear,
      isCurrentMonth: false,
      dateString: formatDate(prevYear, prevMonth, d),
    })
  }

  // Current month days
  for (let d = 1; d <= daysInMonth; d++) {
    cells.push({
      date: d,
      month: m,
      year: y,
      isCurrentMonth: true,
      dateString: formatDate(y, m, d),
    })
  }

  // Next month padding (fill up to 42 cells = 6 rows)
  const nextMonth = m === 11 ? 0 : m + 1
  const nextYear = m === 11 ? y + 1 : y
  let nextDay = 1
  while (cells.length < 42) {
    cells.push({
      date: nextDay,
      month: nextMonth,
      year: nextYear,
      isCurrentMonth: false,
      dateString: formatDate(nextYear, nextMonth, nextDay),
    })
    nextDay++
  }

  return cells
})

const dayHeaders = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su']

// ── Positioning ─────────────────────────────────────────────────────
function getZoomFactor(): number {
  const app = document.getElementById('app')
  if (!app) return 1
  const zoom = (app.style as any).zoom
  return zoom ? parseFloat(zoom) / 100 : 1
}

function updatePosition() {
  if (!triggerRef.value) return
  const rect = triggerRef.value.getBoundingClientRect()
  const zoom = getZoomFactor()
  const panelWidth = 280
  const renderedWidth = panelWidth * zoom

  // Compute left in viewport space, then convert to panel's zoomed coordinate space
  let leftViewport = rect.left
  if (leftViewport + renderedWidth > window.innerWidth) {
    leftViewport = window.innerWidth - renderedWidth - 8
  }
  if (leftViewport < 0) leftViewport = 0

  panelStyle.value = {
    position: 'fixed',
    top: `${(rect.bottom + 4) / zoom}px`,
    left: `${leftViewport / zoom}px`,
    width: `${panelWidth}px`,
    zIndex: '9999',
    zoom: `${zoom * 100}%`,
  }
}

// ── Open / Close ────────────────────────────────────────────────────
function toggle() {
  if (isOpen.value) {
    close()
  } else {
    open()
  }
}

function open() {
  // Sync view to modelValue or today
  if (props.modelValue) {
    const [y, m] = props.modelValue.split('-').map(Number)
    viewYear.value = y
    viewMonth.value = m - 1
  } else {
    const now = new Date()
    viewYear.value = now.getFullYear()
    viewMonth.value = now.getMonth()
  }

  isOpen.value = true
  updatePosition()

  nextTick(() => {
    document.addEventListener('click', onClickOutside, true)
    document.addEventListener('scroll', onScrollOrResize, true)
    window.addEventListener('resize', onScrollOrResize)
  })
}

function close() {
  isOpen.value = false
  document.removeEventListener('click', onClickOutside, true)
  document.removeEventListener('scroll', onScrollOrResize, true)
  window.removeEventListener('resize', onScrollOrResize)
}

// ── Month navigation ────────────────────────────────────────────────
function prevMonthNav() {
  if (viewMonth.value === 0) {
    viewMonth.value = 11
    viewYear.value--
  } else {
    viewMonth.value--
  }
}

function nextMonthNav() {
  if (viewMonth.value === 11) {
    viewMonth.value = 0
    viewYear.value++
  } else {
    viewMonth.value++
  }
}

// ── Selection ───────────────────────────────────────────────────────
function selectDay(cell: DayCell) {
  if (!cell.isCurrentMonth) return
  emit('update:modelValue', cell.dateString)
  close()
}

function selectToday() {
  emit('update:modelValue', todayString())
  close()
}

// ── Event handlers ──────────────────────────────────────────────────
function onClickOutside(e: MouseEvent) {
  const target = e.target as Node
  if (
    triggerRef.value?.contains(target) ||
    panelRef.value?.contains(target)
  ) {
    return
  }
  close()
}

function onScrollOrResize() {
  if (isOpen.value) {
    updatePosition()
  }
}

// ── Sync view when modelValue changes externally ────────────────────
watch(
  () => props.modelValue,
  (val) => {
    if (val && isOpen.value) {
      const [y, m] = val.split('-').map(Number)
      viewYear.value = y
      viewMonth.value = m - 1
    }
  }
)

// ── Cleanup ─────────────────────────────────────────────────────────
onBeforeUnmount(() => {
  document.removeEventListener('click', onClickOutside, true)
  document.removeEventListener('scroll', onScrollOrResize, true)
  window.removeEventListener('resize', onScrollOrResize)
})
</script>

<template>
  <div class="relative">
    <!-- Trigger button -->
    <button
      ref="triggerRef"
      type="button"
      @click="toggle"
      class="w-full flex items-center justify-between gap-2 px-3 py-2 bg-bg-inset border border-border-subtle rounded-xl text-[0.8125rem] text-left cursor-pointer transition-colors"
      :style="
        isOpen
          ? {
              borderColor: 'var(--color-accent)',
              boxShadow: '0 0 0 2px var(--color-accent-muted)',
              outline: 'none',
            }
          : {}
      "
    >
      <span
        :class="displayText ? 'text-text-primary' : 'text-text-tertiary'"
        class="truncate"
      >
        {{ displayText ?? placeholder }}
      </span>
      <Calendar
        class="w-4 h-4 text-text-secondary shrink-0"
        :stroke-width="2"
      />
    </button>

    <!-- Calendar popover -->
    <Teleport to="body">
      <div
        v-if="isOpen"
        ref="panelRef"
        :style="panelStyle"
        class="bg-bg-surface border border-border-visible rounded-xl shadow-[0_4px_24px_rgba(0,0,0,0.4)] overflow-hidden animate-dropdown-enter"
      >
        <!-- Month/year header -->
        <div class="flex items-center justify-between px-3 py-2.5">
          <button
            type="button"
            @click="prevMonthNav"
            class="p-1 rounded-lg hover:bg-bg-elevated transition-colors cursor-pointer text-text-secondary hover:text-text-primary"
          >
            <ChevronLeft class="w-4 h-4" :stroke-width="2" />
          </button>
          <span class="text-[0.8125rem] font-medium text-text-primary select-none">
            {{ viewMonthLabel }}
          </span>
          <button
            type="button"
            @click="nextMonthNav"
            class="p-1 rounded-lg hover:bg-bg-elevated transition-colors cursor-pointer text-text-secondary hover:text-text-primary"
          >
            <ChevronRight class="w-4 h-4" :stroke-width="2" />
          </button>
        </div>

        <!-- Day-of-week headers -->
        <div class="grid grid-cols-7 px-2">
          <div
            v-for="header in dayHeaders"
            :key="header"
            class="text-center text-[0.6875rem] font-medium text-text-tertiary py-1 select-none"
          >
            {{ header }}
          </div>
        </div>

        <!-- Day grid -->
        <div class="grid grid-cols-7 px-2 pb-2">
          <button
            v-for="(cell, index) in dayCells"
            :key="index"
            type="button"
            :disabled="!cell.isCurrentMonth"
            @click="selectDay(cell)"
            class="relative flex items-center justify-center h-8 w-full text-[0.75rem] rounded-lg transition-colors select-none"
            :class="[
              !cell.isCurrentMonth
                ? 'text-text-tertiary/40 cursor-default'
                : cell.dateString === modelValue
                  ? 'bg-accent text-bg-base font-medium cursor-pointer'
                  : cell.dateString === todayString()
                    ? 'ring-1 ring-accent text-accent-text cursor-pointer hover:bg-bg-elevated'
                    : 'text-text-primary cursor-pointer hover:bg-bg-elevated',
            ]"
          >
            {{ cell.date }}
          </button>
        </div>

        <!-- Today shortcut -->
        <div class="border-t border-border-subtle px-3 py-2">
          <button
            type="button"
            @click="selectToday"
            class="w-full text-center text-[0.75rem] text-accent-text hover:text-accent cursor-pointer transition-colors py-0.5"
          >
            Today
          </button>
        </div>
      </div>
    </Teleport>
  </div>
</template>
