/**
 * @copyright NHCarrigan
 * @license Naomi's Public License
 * @author Naomi Carrigan
 */

import { ShowStatus, ShowType } from "../src/lib/show.types";
import type { Show, CreateShowDto, UpdateShowDto } from "../src/lib/show.types";

describe("show Types", () => {
  describe("showType enum", () => {
    it("should have the correct values", () => {
      expect(ShowType.tvSeries).toBe("TV_SERIES");
      expect(ShowType.anime).toBe("ANIME");
      expect(ShowType.film).toBe("FILM");
      expect(ShowType.documentary).toBe("DOCUMENTARY");
    });

    it("should have all expected enum values", () => {
      const values = Object.values(ShowType);
      expect(values).toHaveLength(4);
      expect(values).toContain("TV_SERIES");
      expect(values).toContain("ANIME");
      expect(values).toContain("FILM");
      expect(values).toContain("DOCUMENTARY");
    });
  });

  describe("showStatus enum", () => {
    it("should have the correct values", () => {
      expect(ShowStatus.watching).toBe("WATCHING");
      expect(ShowStatus.completed).toBe("COMPLETED");
      expect(ShowStatus.wantToWatch).toBe("WANT_TO_WATCH");
    });

    it("should have all expected enum values", () => {
      const values = Object.values(ShowStatus);
      expect(values).toHaveLength(4);
      expect(values).toContain("WATCHING");
      expect(values).toContain("COMPLETED");
      expect(values).toContain("WANT_TO_WATCH");
      expect(values).toContain("RETIRED");
    });
  });

  describe("show interface", () => {
    it("should accept valid show object with minimal fields", () => {
      const show: Show = {
        createdAt: new Date("2024-01-15"),
        dateAdded: new Date("2024-01-15"),
        id:        "show123",
        links:     [],
        status:    ShowStatus.watching,
        tags:      [],
        title:     "Breaking Bad",
        type:      ShowType.tvSeries,
        updatedAt: new Date("2024-01-16"),
      };

      expect(show.dateCompleted).toBeUndefined();
      expect(show.rating).toBeUndefined();
      expect(show.notes).toBeUndefined();
      expect(show.coverImage).toBeUndefined();
    });

    it("should accept valid show object with all fields", () => {
      const fullShow: Show = {
        coverImage:    "https://example.com/aot-cover.jpg",
        createdAt:     new Date("2024-01-01"),
        dateAdded:     new Date("2024-01-01"),
        dateCompleted: new Date("2024-01-20"),
        id:            "show456",
        links:         [
          { title: "MyAnimeList", url: "https://myanimelist.net/anime/16498" },
          { title: "Crunchyroll", url: "https://crunchyroll.com/attack-on-titan" },
        ],
        notes:     "Incredible story with amazing animation",
        rating:    5,
        status:    ShowStatus.completed,
        tags:      [ "action", "dark fantasy", "shounen" ],
        title:     "Attack on Titan",
        type:      ShowType.anime,
        updatedAt: new Date("2024-01-20"),
      };

      expect(fullShow.type).toBe(ShowType.anime);
      expect(fullShow.rating).toBe(5);
      expect(fullShow.tags).toHaveLength(3);
      expect(fullShow.links).toHaveLength(2);
    });

    it("should accept different show types", () => {
      const film: Show = {
        createdAt: new Date("2024-02-01"),
        dateAdded: new Date("2024-02-01"),
        id:        "show789",
        links:     [],
        rating:    5,
        status:    ShowStatus.completed,
        tags:      [ "sci-fi", "thriller" ],
        title:     "Inception",
        type:      ShowType.film,
        updatedAt: new Date("2024-02-01"),
      };

      const documentary: Show = {
        createdAt: new Date("2024-02-05"),
        dateAdded: new Date("2024-02-05"),
        id:        "show999",
        links:     [],
        status:    ShowStatus.wantToWatch,
        tags:      [ "nature", "wildlife" ],
        title:     "Planet Earth II",
        type:      ShowType.documentary,
        updatedAt: new Date("2024-02-05"),
      };

      expect(film.type).toBe(ShowType.film);
      expect(documentary.type).toBe(ShowType.documentary);
    });
  });

  describe("createShowDto interface", () => {
    it("should accept DTO with required fields only", () => {
      const createDto: CreateShowDto = {
        status: ShowStatus.wantToWatch,
        title:  "Stranger Things",
        type:   ShowType.tvSeries,
      };

      expect(createDto.rating).toBeUndefined();
      expect(createDto.notes).toBeUndefined();
      expect(createDto.coverImage).toBeUndefined();
      expect(createDto.tags).toBeUndefined();
      expect(createDto.links).toBeUndefined();
    });

    it("should accept DTO with all fields", () => {
      const fullCreateDto: CreateShowDto = {
        coverImage: "https://example.com/death-note.jpg",
        links:      [ { title: "Netflix", url: "https://netflix.com/death-note" } ],
        notes:      "Psychological thriller with great plot",
        rating:     4,
        status:     ShowStatus.watching,
        tags:       [ "psychological", "thriller", "supernatural" ],
        title:      "Death Note",
        type:       ShowType.anime,
      };

      expect(fullCreateDto.type).toBe(ShowType.anime);
      expect(fullCreateDto.rating).toBe(4);
      expect(fullCreateDto.tags).toEqual([ "psychological", "thriller", "supernatural" ]);
      expect(fullCreateDto.links).toHaveLength(1);
    });
  });

  describe("updateShowDto type", () => {
    it("should accept empty update DTO", () => {
      const emptyUpdate: UpdateShowDto = {};
      expect(emptyUpdate).toEqual({});
    });

    it("should accept partial updates including dateCompleted", () => {
      const partialUpdate: UpdateShowDto = {
        dateCompleted: new Date("2024-02-10"),
        rating:        5,
        status:        ShowStatus.completed,
      };

      expect(partialUpdate.status).toBe(ShowStatus.completed);
      expect(partialUpdate.dateCompleted).toEqual(new Date("2024-02-10"));
      expect(partialUpdate.rating).toBe(5);
      expect(partialUpdate.title).toBeUndefined();
    });

    it("should accept full update", () => {
      const fullUpdate: UpdateShowDto = {
        coverImage:    "https://example.com/new-show-cover.jpg",
        dateCompleted: new Date("2024-02-15"),
        links:         [ { title: "New Link", url: "https://newlink.com" } ],
        notes:         "Updated after watching",
        rating:        3,
        status:        ShowStatus.completed,
        tags:          [ "updated", "tags" ],
        title:         "Updated Show Title",
        type:          ShowType.documentary,
      };

      expect(fullUpdate.title).toBe("Updated Show Title");
      expect(fullUpdate.type).toBe(ShowType.documentary);
      expect(fullUpdate.dateCompleted).toEqual(new Date("2024-02-15"));
      expect(fullUpdate.links).toHaveLength(1);
    });
  });
});
