<script lang="ts">
import { createEventDispatcher } from 'svelte';
import type { Capacity, Holiday, PTO } from '$lib/types/capacity';

  const weekdayLabels = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];

  export let month: string;
  export let capacity: Capacity | null = null;
  export let holidays: Holiday[] = [];
  export let ptos: PTO[] = [];

  const dispatch = createEventDispatcher();
  let overrides: Record<string, number> = {};
  let previousMonth: string | null = null;

  $: if (month && month !== previousMonth) {
    overrides = {};
    previousMonth = month;
  }

  function toIso(date: Date) {
    return date.toISOString().split('T')[0];
  }

  function buildPtoDates(records: PTO[]): Set<string> {
    const set = new Set<string>();

    records.forEach((pto) => {
      const start = new Date(pto.start_date);
      const end = new Date(pto.end_date);
      const cursor = new Date(start);

      while (cursor <= end) {
        set.add(toIso(cursor));
        cursor.setDate(cursor.getDate() + 1);
      }
    });

    return set;
  }

  function availabilityLabel(value: number): string {
    if (value >= 0.99) return 'Full day';
    if (value >= 0.49) return 'Half day';
    return 'Off';
  }

  $: parsedMonth = (() => {
    if (!month) return null;
    const [year, monthPart] = month.split('-').map(Number);
    if (!year || !monthPart) return null;
    return { year, index: monthPart - 1 };
  })();

  $: detailsMap = new Map((capacity?.details ?? []).map((detail) => [detail.date, detail]));
  $: holidayMap = new Map(holidays.map((holiday) => [holiday.date, holiday.name]));
  $: ptoDates = buildPtoDates(ptos);

  $: calendarContext = parsedMonth
    ? (() => {
        const { year, index } = parsedMonth;
        const first = new Date(year, index, 1);
        const totalDays = new Date(year, index + 1, 0).getDate();
        const startWeekday = first.getDay();

        const leading = Array.from({ length: startWeekday });
        const trailing = Array.from({ length: ((7 - ((leading.length + totalDays) % 7)) % 7) });

        const days = Array.from({ length: totalDays }, (_, i) => {
          const current = new Date(year, index, i + 1);
          const iso = toIso(current);
          const dayOfWeek = current.getDay();
          const detail = detailsMap.get(iso);
          const isWeekend = dayOfWeek === 0 || dayOfWeek === 6;
          const isHoliday = holidayMap.has(iso);
          const holidayName = holidayMap.get(iso);
          const isPto = ptoDates.has(iso) || !!detail?.is_pto;
          const isBlocked = isWeekend || isHoliday;
          const fallbackAvailability = isWeekend ? 0 : isPto ? 0 : 1;
          const sourceAvailability = overrides[iso] ?? detail?.availability ?? fallbackAvailability;
          const availability = isPto ? sourceAvailability : (isBlocked ? 0 : sourceAvailability);
          const effectiveHours = Math.round(availability * 8 * 10) / 10;

          return {
            iso,
            day: i + 1,
            dayName: weekdayLabels[dayOfWeek],
            isWeekend,
            isHoliday,
            holidayName,
            isPto,
            isBlocked,
            availability,
            effectiveHours,
            defaultAvailability: fallbackAvailability
          };
        });

        return { leading, days, trailing };
      })()
    : { leading: [], days: [], trailing: [] };

  function handleAvailabilityChange(date: string, value: number) {
    overrides = { ...overrides, [date]: value };
    dispatch('availabilitychange', { date, availability: value });
  }
</script>

<section class="space-y-4" data-testid="capacity-calendar">
  <div class="flex items-center justify-between gap-4">
    <div>
      <h2 class="text-lg font-semibold">Capacity Calendar</h2>
      <p class="text-sm text-base-content/70">{month || 'Select a month to view calendar'}</p>
    </div>
    <span class="text-xs text-base-content/60">Working days: {capacity?.working_days ?? 0}</span>
  </div>

  <div class="grid grid-cols-7 gap-2 text-xs font-semibold uppercase text-center text-base-content/60">
    {#each weekdayLabels as label}
      <div>{label}</div>
    {/each}
  </div>

  <div class="grid grid-cols-7 gap-2">
    {#each calendarContext.leading as _, idx}
      <div class="h-32 rounded-lg border border-base-300 bg-base-100" aria-hidden="true" />
    {/each}

    {#each calendarContext.days as day}
      <div
        class={`flex flex-col rounded-xl border p-3 text-sm shadow-sm transition ${
          day.isWeekend ? 'border-dashed border-base-300 bg-base-200' : 'border-base-200 bg-base-100'
        } ${day.isHoliday ? 'border-error bg-error/10' : ''}`}
        data-date={day.iso}
      >
        <div class="flex items-center justify-between">
          <span class="text-base font-semibold">{day.day}</span>
          <span class="text-[10px] uppercase tracking-wide text-base-content/40">{day.dayName}</span>
        </div>

        <div class="mt-1 space-y-1 text-xs text-base-content/70">
          <div>{availabilityLabel(day.availability)}</div>
          <div>{day.effectiveHours} hrs</div>
          {#if day.isHoliday}
            <div class="badge badge-info badge-sm">{day.holidayName ?? 'Holiday'}</div>
          {/if}
          {#if day.isPto}
            <div class="badge badge-warning badge-sm">PTO</div>
          {/if}
        </div>

        <select
          class="select select-sm mt-3"
          aria-label={`Availability for ${day.iso}`}
          disabled={day.isWeekend || day.isHoliday}
          on:change={(event) => handleAvailabilityChange(day.iso, Number(event.currentTarget.value))}
        >
          <option value="1" selected={day.availability === 1}>Full day (1.0)</option>
          <option value="0.5" selected={day.availability === 0.5}>Half day (0.5)</option>
          <option value="0" selected={day.availability === 0}>Off (0.0)</option>
        </select>
      </div>
    {/each}

    {#each calendarContext.trailing as _, idx}
      <div class="h-32 rounded-lg border border-base-300 bg-base-100" aria-hidden="true" />
    {/each}
  </div>
</section>
