/**
 * RED test stubs for hydrateEvents() — Wave 0 state.
 *
 * These tests encode the concrete contracts that Plan 03 (GREEN phase) must satisfy.
 * The tests reference the not-yet-built module apps/pwa/src/lib/hydrateEvents.ts and
 * are expected to fail until that module is implemented.
 *
 * Contracts locked here:
 *  1. All-day occurrence (allDay:true, start 'YYYY-MM-DD') → start is Temporal.PlainDate
 *  2. Timed occurrence (allDay:false) → start is Temporal.ZonedDateTime
 *  3. Shared occurrence (isShared:true) → Schedule-X calendarId === 'shared'
 *  4. Personal occurrence (isShared:false, ownerUserId:7, calendarId:99) →
 *     Schedule-X calendarId === '7' (String(ownerUserId)), NOT '99' (String(calendarId))
 *     This assertion locks the Plan 03 routing fix.
 */

import 'temporal-polyfill/global';
import { describe, it, expect } from 'vitest';

import { hydrateEvents } from './hydrateEvents.js';

// Minimal CalendarOccurrence shape for test purposes
interface TestOccurrence {
  id: string;
  uid: string;
  calendarId: number;
  calendarName: string;
  ownerUserId: number;
  color: string;
  isShared: boolean;
  title: string;
  start: string;
  end: string;
  allDay: boolean;
  location: string | null;
  description: string | null;
}

function makeOccurrence(overrides: Partial<TestOccurrence>): TestOccurrence {
  return {
    id: 'test::2026-06-15',
    uid: 'test-uid',
    calendarId: 1,
    calendarName: 'Test Calendar',
    ownerUserId: 1,
    color: '#4A90D9',
    isShared: false,
    title: 'Test Event',
    start: '2026-06-15T10:00:00-04:00[America/New_York]',
    end: '2026-06-15T11:00:00-04:00[America/New_York]',
    allDay: false,
    location: null,
    description: null,
    ...overrides,
  };
}

describe('hydrateEvents — RED stubs (Wave 0)', () => {
  describe('Temporal type conversion', () => {
    it('converts all-day occurrence (allDay:true) to Temporal.PlainDate for start and end', () => {
      const occurrences = [
        makeOccurrence({
          allDay: true,
          start: '2026-06-15',
          end: '2026-06-15',
        }),
      ];

      const result = hydrateEvents(occurrences);
      expect(result).toHaveLength(1);

      const evt = result[0];
      // Schedule-X requires Temporal.PlainDate for all-day events
      expect(evt.start).toBeInstanceOf(Temporal.PlainDate);
      expect(evt.end).toBeInstanceOf(Temporal.PlainDate);
    });

    it('converts an all-day exclusive DTEND to an inclusive last day for Schedule-X', () => {
      // Single-day event: iCal DTSTART:24 / DTEND:25 (exclusive). Schedule-X end is
      // inclusive, so a 1-day event must have start === end (renders on one day only).
      const single = hydrateEvents([
        makeOccurrence({ allDay: true, start: '2026-06-24', end: '2026-06-25' }),
      ])[0];
      expect((single.start as Temporal.PlainDate).toString()).toBe('2026-06-24');
      expect((single.end as Temporal.PlainDate).toString()).toBe('2026-06-24');

      // Two-day event: DTSTART:26 / DTEND:28 (exclusive) → inclusive last day = 27.
      const multi = hydrateEvents([
        makeOccurrence({ allDay: true, start: '2026-06-26', end: '2026-06-28' }),
      ])[0];
      expect((multi.start as Temporal.PlainDate).toString()).toBe('2026-06-26');
      expect((multi.end as Temporal.PlainDate).toString()).toBe('2026-06-27');
    });

    it('converts timed occurrence (allDay:false) to Temporal.ZonedDateTime for start and end', () => {
      const occurrences = [
        makeOccurrence({
          allDay: false,
          start: '2026-06-15T10:00:00-04:00[America/New_York]',
          end: '2026-06-15T11:00:00-04:00[America/New_York]',
        }),
      ];

      const result = hydrateEvents(occurrences);
      expect(result).toHaveLength(1);

      const evt = result[0];
      expect(evt.start).toBeInstanceOf(Temporal.ZonedDateTime);
      expect(evt.end).toBeInstanceOf(Temporal.ZonedDateTime);
    });
  });

  describe('calendarId routing — Plan 03 contract', () => {
    it('shared occurrence (isShared:true) gets Schedule-X calendarId "shared"', () => {
      const occurrences = [
        makeOccurrence({
          isShared: true,
          calendarId: 5,
          ownerUserId: 2,
        }),
      ];

      const result = hydrateEvents(occurrences);
      expect(result).toHaveLength(1);

      // Shared-family events must route to the 'shared' calendar slot in Schedule-X config
      expect(result[0].calendarId).toBe('shared');
    });

    it('personal occurrence (isShared:false) gets Schedule-X calendarId === String(ownerUserId), NOT String(calendarId)', () => {
      // This assertion locks the routing decision: personal events are grouped by MEMBER (ownerUserId),
      // not by DB calendarId. If two calendars belong to the same user, they share the same color slot.
      const occurrences = [
        makeOccurrence({
          isShared: false,
          calendarId: 99, // DB calendar row id
          ownerUserId: 7, // DB user id — this is the correct Schedule-X key
        }),
      ];

      const result = hydrateEvents(occurrences);
      expect(result).toHaveLength(1);

      // Must be '7' (String(ownerUserId)), NOT '99' (String(calendarId))
      expect(result[0].calendarId).toBe('7');
      expect(result[0].calendarId).not.toBe('99');
    });
  });
});
