import DateFormat from "./DateFormat";

describe("DateFormat", () => {
  describe("toIso8601DateString", () => {
    it("should format Date object to ISO 8601 date string", () => {
      expect(DateFormat.toIso8601DateString(new Date(2024, 9, 15))).toEqual(
        "2024-10-15",
      );
    });

    it("should format string date to ISO 8601 date string", () => {
      expect(DateFormat.toIso8601DateString("2024-10-15")).toEqual(
        "2024-10-15",
      );
    });

    it("should format with custom format", () => {
      expect(
        DateFormat.toIso8601DateString(
          new Date(2024, 9, 15),
          "YYYY-MM-DD HH:mm:ss",
        ),
      ).toMatch(/2024-10-15 \d{2}:\d{2}:\d{2}/);
    });

    it("should handle leap year dates", () => {
      expect(DateFormat.toIso8601DateString(new Date(2024, 1, 29))).toEqual(
        "2024-02-29",
      );
    });
  });

  describe("toDayjs", () => {
    it("should convert ISO string with timezone to dayjs", () => {
      expect(
        DateFormat.toDayjs("2024-10-10T12:00:00+02:00").toDate().toISOString(),
      ).toEqual("2024-10-10T10:00:00.000Z");
    });

    it("should convert date string to dayjs with Europe/Tallinn timezone", () => {
      expect(DateFormat.toDayjs("2024-10-10").toDate().toISOString()).toEqual(
        "2024-10-09T21:00:00.000Z",
      );
    });

    it("should handle Date objects", () => {
      const date = new Date(2024, 9, 15, 10, 30, 0);
      const result = DateFormat.toDayjs(date);
      expect(result.format("YYYY-MM-DD")).toEqual("2024-10-15");
    });

    it("should handle custom format parsing", () => {
      const result = DateFormat.toDayjs("15/10/2024", "DD/MM/YYYY");
      expect(result.format("YYYY-MM-DD")).toEqual("2024-10-15");
    });

    it("should handle undefined input", () => {
      const result = DateFormat.toDayjs();
      expect(result.isValid()).toBe(true);
    });

    it("should handle edge of day transitions", () => {
      const result = DateFormat.toDayjs("2024-10-10T00:00:00");
      expect(result.format("YYYY-MM-DD HH:mm:ss")).toEqual(
        "2024-10-10 00:00:00",
      );
    });
  });

  describe("toIso8601DateWithZeroHours", () => {
    it("should format date with zero hours", () => {
      const date = new Date(2024, 9, 15, 14, 30, 45);
      expect(DateFormat.toIso8601DateWithZeroHours(date)).toEqual(
        "2024-10-15T00:00:00",
      );
    });

    it("should handle midnight date", () => {
      const date = new Date(2024, 9, 15, 0, 0, 0);
      expect(DateFormat.toIso8601DateWithZeroHours(date)).toEqual(
        "2024-10-15T00:00:00",
      );
    });

    it("should handle end of day", () => {
      const date = new Date(2024, 9, 15, 23, 59, 59);
      expect(DateFormat.toIso8601DateWithZeroHours(date)).toEqual(
        "2024-10-15T00:00:00",
      );
    });

    it("should handle leap year date", () => {
      const date = new Date(2024, 1, 29, 12, 0, 0);
      expect(DateFormat.toIso8601DateWithZeroHours(date)).toEqual(
        "2024-02-29T00:00:00",
      );
    });
  });

  describe("toIso8601DateWithZeroMinutes", () => {
    it("should format date with zero minutes", () => {
      const date = new Date(2024, 9, 15, 14, 30, 45);
      expect(DateFormat.toIso8601DateWithZeroMinutes(date)).toEqual(
        "2024-10-15T14:00:00",
      );
    });

    it("should handle midnight hour", () => {
      const date = new Date(2024, 9, 15, 0, 30, 45);
      expect(DateFormat.toIso8601DateWithZeroMinutes(date)).toEqual(
        "2024-10-15T00:00:00",
      );
    });

    it("should handle noon", () => {
      const date = new Date(2024, 9, 15, 12, 45, 30);
      expect(DateFormat.toIso8601DateWithZeroMinutes(date)).toEqual(
        "2024-10-15T12:00:00",
      );
    });

    it("should handle end of day hour", () => {
      const date = new Date(2024, 9, 15, 23, 59, 59);
      expect(DateFormat.toIso8601DateWithZeroMinutes(date)).toEqual(
        "2024-10-15T23:00:00",
      );
    });

    it("should handle single digit hour", () => {
      const date = new Date(2024, 9, 15, 5, 30, 45);
      expect(DateFormat.toIso8601DateWithZeroMinutes(date)).toEqual(
        "2024-10-15T05:00:00",
      );
    });
  });

  describe("timezone handling", () => {
    it("should handle Europe/Tallinn timezone correctly", () => {
      // Test winter time (EET = UTC+2)
      const winterDate = DateFormat.toDayjs("2024-01-15T12:00:00");
      expect(winterDate.utc().format("HH:mm")).toEqual("10:00");

      // Test summer time (EEST = UTC+3)
      const summerDate = DateFormat.toDayjs("2024-07-15T12:00:00");
      expect(summerDate.utc().format("HH:mm")).toEqual("09:00");
    });

    it("should maintain timezone consistency across different methods", () => {
      const date = new Date(2024, 6, 15, 12, 30, 45); // July 15, 2024
      const dayjsResult = DateFormat.toDayjs(date);
      const isoResult = DateFormat.toIso8601DateString(date);

      expect(dayjsResult.format("YYYY-MM-DD")).toEqual(isoResult);
    });
  });

  describe("edge cases", () => {
    it("should handle invalid date strings gracefully", () => {
      const result = DateFormat.toDayjs("invalid-date");
      expect(result.isValid()).toBe(false);
    });

    it("should handle year boundaries", () => {
      const newYear = new Date(2024, 0, 1, 0, 0, 0);
      expect(DateFormat.toIso8601DateString(newYear)).toEqual("2024-01-01");

      const newYearEve = new Date(2023, 11, 31, 23, 59, 59);
      expect(DateFormat.toIso8601DateString(newYearEve)).toEqual("2023-12-31");
    });

    it("should handle month boundaries", () => {
      const endOfMonth = new Date(2024, 9, 31, 23, 59, 59);
      expect(DateFormat.toIso8601DateString(endOfMonth)).toEqual("2024-10-31");

      const startOfMonth = new Date(2024, 10, 1, 0, 0, 0);
      expect(DateFormat.toIso8601DateString(startOfMonth)).toEqual(
        "2024-11-01",
      );
    });

    it("should handle very old dates", () => {
      const oldDate = new Date(1900, 0, 1);
      expect(DateFormat.toIso8601DateString(oldDate)).toEqual("1900-01-01");
    });

    it("should handle future dates", () => {
      const futureDate = new Date(2050, 11, 31);
      expect(DateFormat.toIso8601DateString(futureDate)).toEqual("2050-12-31");
    });
  });
});
