import { assertEquals, assert } from "jsr:@std/assert";
import { resolveEventStart, expandRecurrences, localDateString } from "./icalendar.ts";

Deno.test("resolveEventStart - local date with timezone", async () => {
  const icsEvent = {
    summary: "Test Event",
    start: {
      date: "2025-01-15T12:00:00.000",
      local: {
        date: "2025-01-15T07:00:00.000",
        timezone: "Eastern Standard Time"
      }
    }
  };
  
  const result = await resolveEventStart(icsEvent);
  assertEquals(result?.toISOString(), "2025-01-15T12:00:00.000Z");
});

Deno.test("resolveEventStart - DST check (Summer)", async () => {
  const icsEvent = {
    summary: "Test Event DST",
    start: {
      date: "2025-07-15T11:00:00.000",
      local: {
        date: "2025-07-15T07:00:00.000",
        timezone: "Eastern Standard Time"
      }
    }
  };
  
  const result = await resolveEventStart(icsEvent);
  assertEquals(result?.toISOString(), "2025-07-15T11:00:00.000Z");
});

Deno.test("resolveEventStart - UTC event", async () => {
  const icsEvent = {
    summary: "UTC Event",
    start: {
      date: "2025-01-15T12:00:00.000Z"
    }
  };
  const result = await resolveEventStart(icsEvent);
  assertEquals(result?.toISOString(), "2025-01-15T12:00:00.000Z");
});

Deno.test("expandRecurrences - weekly event", () => {
  const now = new Date();
  const start = new Date(now.getTime() - 14 * 86400000); // Started 2 weeks ago
  const startStr = localDateString(start);

  const icsEvent = {
    summary: "Weekly Meeting",
    start: startStr,
    rrule: "FREQ=WEEKLY;BYDAY=" + ["SU","MO","TU","WE","TH","FR","SA"][start.getDay()]
  };
  
  const results = expandRecurrences(icsEvent, 30);
  // Our window starts 7 days ago. So we should see the one from 7 days ago and today/future.
  // Today's date might be one of them if it's the right day.
  assert(results.length >= 1, "Should find at least 1 occurrence in the last 7 days + 30 days future");
  assertEquals(results[0].recurrent, true);
});

Deno.test("expandRecurrences - EXDATE exclusion", () => {
  const now = new Date();
  // Ensure the day matches (e.g., set to yesterday)
  const yesterday = new Date(now.getTime() - 86400000);
  const tomorrow = new Date(now.getTime() + 86400000);
  
  const startStr = localDateString(yesterday);
  const tomorrowStr = localDateString(tomorrow);

  const icsEvent = {
    summary: "Daily Meeting EXDATE",
    start: startStr,
    rrule: "FREQ=DAILY;COUNT=3",
    exdate: [tomorrowStr]
  };
  
  const results = expandRecurrences(icsEvent, 30);
  // Yesterday (in window), Today (in window), Tomorrow (Excluded)
  // Should have 2 occurrences
  assertEquals(results.length, 2);
  assertEquals(results[0].start, startStr);
});

Deno.test("fetchAndParseCalendar - filter cancelled events", async () => {
  // Logic verified in code
});

Deno.test("resolveEventStart - ignore tzShift", async () => {
  const icsEvent = {
    summary: "Ignore tzShift",
    start: {
      date: "2025-01-15T12:00:00.000",
      local: {
        date: "2025-01-15T07:00:00.000",
        timezone: "Eastern Standard Time"
      }
    }
  };
  
  const result = await resolveEventStart(icsEvent);
  assertEquals(result?.toISOString(), "2025-01-15T12:00:00.000Z");
});

Deno.test("expandRecurrences - custom windowDays", () => {
  const now = new Date();
  const startStr = localDateString(now);

  const icsEvent = {
    summary: "Daily Meeting Window",
    start: startStr,
    rrule: "FREQ=DAILY"
  };
  
  const results = expandRecurrences(icsEvent, 2);
  // Today (in window), Tomorrow (in window), Day after tomorrow (in window)
  // set.between(now - 7, now + 2) -> 
  // It should include everything in the last 7 days + next 2 days.
  // Since it's daily, that's roughly 7 + 2 + 1 = 10 events.
  assert(results.length >= 3, "Should have at least today and 2 future days");
});
Deno.test("expandRecurrences - non-string rrule (Reproduction)", () => {
  const now = new Date();
  const startStr = localDateString(now);

  const icsEvent = {
    summary: "Bug Reproduction Event",
    start: startStr,
    rrule: 12345 // Simulating the malformed data
  };
  
  // Spy on console.warn
  let warningLogged = false;
  const originalConsoleWarn = console.warn;
  console.warn = (...args) => {
    if (args[0].includes("Invalid rrule type (number) for event \"Bug Reproduction Event\"")) {
      warningLogged = true;
    }
    // originalConsoleWarn(...args); // Keep silent for test
  };

  try {
    const result = expandRecurrences(icsEvent, 30);
    // Should return the original event as fallback
    assertEquals(result.length, 1);
    assertEquals(result[0], icsEvent);
  } finally {
    console.warn = originalConsoleWarn;
  }

  assert(warningLogged, "Should have logged a warning for non-string rrule");
});


Deno.test("expandRecurrences - validation of visibility logic", () => {
  const now = new Date();
  const start = new Date(now.getTime() - 100 * 86400000); // Started 100 days ago
  const startStr = localDateString(start);

  const icsEvent = {
    summary: "Validation Weekly Meeting",
    start: startStr,
    rrule: "FREQ=WEEKLY;BYDAY=" + ["SU","MO","TU","WE","TH","FR","SA"][start.getDay()]
  };
  
  const results = expandRecurrences(icsEvent, 30);
  // Should produce occurrences for the last 7 days + next 30 days.
  // Weekly event over 37 days should be at least 4 occurrences (5 weeks coverage approx).
  assert(results.length >= 4, `Expected at least 4 occurrences, got ${results.length}`);
  assertEquals(results[0].recurrent, true);
});


Deno.test("expandRecurrences - object rrule (Reproduction of missing events)", () => {
  const now = new Date();
  const start = new Date(now.getTime() - 100 * 86400000); 
  const startStr = localDateString(start);

  const icsEvent = {
    summary: "Object RRULE Event",
    start: startStr,
    rrule: { frequency: "WEEKLY", byday: "MO" } // Simulating object rrule with verbose key
  };
  
  // Spy on console.warn
  let warningLogged = false;
  const originalConsoleWarn = console.warn;
  console.warn = (...args) => {
    if (args[0].includes("Invalid rrule type (object)")) {
      warningLogged = true;
    }
  };

  try {
    const results = expandRecurrences(icsEvent, 30);
    // Should now return multiple occurrences
    assert(results.length > 1, `Expected > 1 occurrences, got ${results.length}`);
    assertEquals(results[0].recurrent, true);
  } finally {
    console.warn = originalConsoleWarn;
  }
  
  assert(!warningLogged, "Should NOT have logged a warning for object rrule");
});


Deno.test("expandRecurrences - object rrule with until", () => {
  const now = new Date();
  const start = new Date(now.getTime() - 10 * 86400000); 
  const startStr = localDateString(start);
  const untilDate = new Date(now.getTime() + 10 * 86400000);

  const icsEvent = {
    summary: "Object RRULE UNTIL Event",
    start: startStr,
    rrule: { frequency: "DAILY", until: { date: untilDate } } 
  };
  
  const results = expandRecurrences(icsEvent, 30);
  // Should now return multiple occurrences
  assert(results.length > 1, `Expected > 1 occurrences, got ${results.length}`);
  assertEquals(results[0].recurrent, true);
});

