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

import { GameStatus, BookStatus, MangaStatus, MusicStatus, MusicType, ShowStatus, ShowType } from "../src";
import { SuggestionEntity, SuggestionStatus } from "../src/lib/suggestion.types";
import type {
  Suggestion,
  SuggestionUser,
  CreateSuggestionDto,
  DeclineSuggestionDto,
  CreateGameSuggestionDto,
  CreateBookSuggestionDto,
  CreateMusicSuggestionDto,
  CreateArtSuggestionDto,
  CreateShowSuggestionDto,
  CreateMangaSuggestionDto,
  AcceptWithEditsDto,
} from "../src/lib/suggestion.types";

describe("suggestion Types", () => {
  describe("suggestionEntity enum", () => {
    it("should have the correct values", () => {
      expect(SuggestionEntity.game).toBe("GAME");
      expect(SuggestionEntity.book).toBe("BOOK");
      expect(SuggestionEntity.music).toBe("MUSIC");
      expect(SuggestionEntity.art).toBe("ART");
      expect(SuggestionEntity.show).toBe("SHOW");
      expect(SuggestionEntity.manga).toBe("MANGA");
    });

    it("should have all expected enum values", () => {
      const values = Object.values(SuggestionEntity);
      expect(values).toHaveLength(6);
      expect(values).toContain("GAME");
      expect(values).toContain("BOOK");
      expect(values).toContain("MUSIC");
      expect(values).toContain("ART");
      expect(values).toContain("SHOW");
      expect(values).toContain("MANGA");
    });
  });

  describe("suggestionStatus enum", () => {
    it("should have the correct values", () => {
      expect(SuggestionStatus.unreviewed).toBe("UNREVIEWED");
      expect(SuggestionStatus.accepted).toBe("ACCEPTED");
      expect(SuggestionStatus.declined).toBe("DECLINED");
    });

    it("should have all expected enum values", () => {
      const values = Object.values(SuggestionStatus);
      expect(values).toHaveLength(3);
      expect(values).toContain("UNREVIEWED");
      expect(values).toContain("ACCEPTED");
      expect(values).toContain("DECLINED");
    });
  });

  describe("suggestionUser interface", () => {
    it("should accept valid user object", () => {
      const user: SuggestionUser = {
        avatar:    "https://example.com/avatar.png",
        id:        "user123",
        inDiscord: true,
        isMod:     false,
        isStaff:   false,
        isVip:     false,
        username:  "suggester",
      };

      expect(user.inDiscord).toBeTruthy();
      expect(user.isVip).toBeFalsy();
    });

    it("should accept user without avatar", () => {
      const user: SuggestionUser = {
        id:        "user456",
        inDiscord: true,
        isMod:     false,
        isStaff:   true,
        isVip:     true,
        username:  "vipuser",
      };

      expect(user.avatar).toBeUndefined();
      expect(user.isVip).toBeTruthy();
      expect(user.isStaff).toBeTruthy();
    });
  });

  describe("suggestion interface", () => {
    it("should accept game suggestion", () => {
      const gameSuggestion: Suggestion = {
        createdAt:  new Date("2024-01-15"),
        entityType: SuggestionEntity.game,
        gameData:   {
          coverImage: "https://example.com/hades.jpg",
          notes:      "Amazing roguelike",
          platform:   "Nintendo Switch",
          status:     GameStatus.backlog,
          title:      "Hades",
        },
        id:        "sug123",
        status:    SuggestionStatus.unreviewed,
        title:     "Hades",
        updatedAt: new Date("2024-01-15"),
        user:      {
          id:        "user123",
          inDiscord: true,
          isMod:     false,
          isStaff:   false,
          isVip:     false,
          username:  "gamer",
        },
        userId: "user123",
      };

      expect(gameSuggestion.entityType).toBe(SuggestionEntity.game);
      expect(gameSuggestion.gameData).toBeDefined();
      expect(gameSuggestion.bookData).toBeUndefined();
    });

    it("should accept book suggestion", () => {
      const bookSuggestion: Suggestion = {
        bookData: {
          author: "George Orwell",
          isbn:   "978-0-452-28423-4",
          notes:  "Dystopian classic",
          status: BookStatus.toRead,
          title:  "1984",
        },
        createdAt:  new Date("2024-01-20"),
        entityType: SuggestionEntity.book,
        id:         "sug456",
        status:     SuggestionStatus.accepted,
        title:      "1984",
        updatedAt:  new Date("2024-01-21"),
        user:       {
          id:        "user456",
          inDiscord: false,
          isMod:     false,
          isStaff:   false,
          isVip:     true,
          username:  "reader",
        },
        userId: "user456",
      };

      expect(bookSuggestion.entityType).toBe(SuggestionEntity.book);
      expect(bookSuggestion.bookData).toBeDefined();
      expect(bookSuggestion.gameData).toBeUndefined();
    });

    it("should accept declined suggestion with reason", () => {
      const declinedSuggestion: Suggestion = {
        createdAt:     new Date("2024-02-01"),
        declineReason: "Already in the library",
        entityType:    SuggestionEntity.music,
        id:            "sug789",
        musicData:     {
          artist: "Pink Floyd",
          status: MusicStatus.wantToListen,
          title:  "Dark Side of the Moon",
          type:   MusicType.album,
        },
        status:    SuggestionStatus.declined,
        title:     "Dark Side of the Moon",
        updatedAt: new Date("2024-02-02"),
        user:      {
          id:        "user789",
          inDiscord: true,
          isMod:     false,
          isStaff:   false,
          isVip:     false,
          username:  "suggester",
        },
        userId: "user789",
      };

      expect(declinedSuggestion.status).toBe(SuggestionStatus.declined);
      expect(declinedSuggestion.declineReason).toBe("Already in the library");
    });

    it("should accept art suggestion", () => {
      const artSuggestion: Suggestion = {
        artData: {
          artist:      "Jane Doe",
          description: "A stunning sunset painting",
          imageUrl:    "https://example.com/sunset.jpg",
          title:       "Beautiful Sunset",
        },
        createdAt:  new Date("2024-02-10"),
        entityType: SuggestionEntity.art,
        id:         "sug999",
        status:     SuggestionStatus.unreviewed,
        title:      "Beautiful Sunset",
        updatedAt:  new Date("2024-02-10"),
        user:       {
          id:        "user999",
          inDiscord: true,
          isMod:     true,
          isStaff:   false,
          isVip:     false,
          username:  "artlover",
        },
        userId: "user999",
      };

      expect(artSuggestion.entityType).toBe(SuggestionEntity.art);
      expect(artSuggestion.artData).toBeDefined();
    });

    it("should accept show and manga suggestions", () => {
      const showSuggestion: Suggestion = {
        createdAt:  new Date("2024-02-15"),
        entityType: SuggestionEntity.show,
        id:         "sug111",
        showData:   {
          status: ShowStatus.wantToWatch,
          title:  "Breaking Bad",
          type:   ShowType.tvSeries,
        },
        status:    SuggestionStatus.unreviewed,
        title:     "Breaking Bad",
        updatedAt: new Date("2024-02-15"),
        user:      {
          id:        "user111",
          inDiscord: false,
          isMod:     false,
          isStaff:   true,
          isVip:     false,
          username:  "tvfan",
        },
        userId: "user111",
      };

      const mangaSuggestion: Suggestion = {
        createdAt:  new Date("2024-02-20"),
        entityType: SuggestionEntity.manga,
        id:         "sug222",
        mangaData:  {
          author: "Eiichiro Oda",
          status: MangaStatus.reading,
          title:  "One Piece",
        },
        status:    SuggestionStatus.accepted,
        title:     "One Piece",
        updatedAt: new Date("2024-02-21"),
        user:      {
          id:        "user222",
          inDiscord: true,
          isMod:     true,
          isStaff:   true,
          isVip:     true,
          username:  "mangareader",
        },
        userId: "user222",
      };

      expect(showSuggestion.entityType).toBe(SuggestionEntity.show);
      expect(mangaSuggestion.entityType).toBe(SuggestionEntity.manga);
    });
  });

  describe("createSuggestionDto types", () => {
    it("should accept game suggestion DTO", () => {
      const gameDto: CreateGameSuggestionDto = {
        coverImage: "https://example.com/hollow.jpg",
        entityType: SuggestionEntity.game,
        notes:      "Great metroidvania",
        platform:   "PC",
        title:      "Hollow Knight",
      };

      expect(gameDto.entityType).toBe(SuggestionEntity.game);
      expect(gameDto.platform).toBe("PC");
    });

    it("should accept book suggestion DTO", () => {
      const bookDto: CreateBookSuggestionDto = {
        author:     "J.R.R. Tolkien",
        coverImage: "https://example.com/hobbit.jpg",
        entityType: SuggestionEntity.book,
        isbn:       "978-0-547-92822-7",
        notes:      "Fantasy classic",
        title:      "The Hobbit",
      };

      expect(bookDto.entityType).toBe(SuggestionEntity.book);
      expect(bookDto.author).toBe("J.R.R. Tolkien");
    });

    it("should accept music suggestion DTO", () => {
      const musicDto: CreateMusicSuggestionDto = {
        artist:     "Pink Floyd",
        coverArt:   "https://example.com/wall.jpg",
        entityType: SuggestionEntity.music,
        notes:      "Rock opera",
        title:      "The Wall",
        type:       "ALBUM",
      };

      expect(musicDto.entityType).toBe(SuggestionEntity.music);
      expect(musicDto.type).toBe("ALBUM");
    });

    it("should accept art suggestion DTO", () => {
      const artDto: CreateArtSuggestionDto = {
        artist:      "Vincent van Gogh",
        description: "Famous painting",
        entityType:  SuggestionEntity.art,
        imageUrl:    "https://example.com/starry.jpg",
        title:       "Starry Night",
      };

      expect(artDto.entityType).toBe(SuggestionEntity.art);
      expect(artDto.imageUrl).toBe("https://example.com/starry.jpg");
    });

    it("should accept show suggestion DTO", () => {
      const showDto: CreateShowSuggestionDto = {
        coverImage: "https://example.com/office.jpg",
        entityType: SuggestionEntity.show,
        notes:      "Comedy series",
        title:      "The Office",
        type:       "TV_SERIES",
      };

      expect(showDto.entityType).toBe(SuggestionEntity.show);
      expect(showDto.type).toBe("TV_SERIES");
    });

    it("should accept manga suggestion DTO", () => {
      const mangaDto: CreateMangaSuggestionDto = {
        author:     "Tsugumi Ohba",
        coverImage: "https://example.com/deathnote.jpg",
        entityType: SuggestionEntity.manga,
        notes:      "Psychological thriller",
        title:      "Death Note",
      };

      expect(mangaDto.entityType).toBe(SuggestionEntity.manga);
      expect(mangaDto.author).toBe("Tsugumi Ohba");
    });

    it("should work with union type", () => {
      const suggestions: Array<CreateSuggestionDto> = [
        {
          entityType: SuggestionEntity.game,
          title:      "Game Title",
        },
        {
          author:     "Author Name",
          entityType: SuggestionEntity.book,
          title:      "Book Title",
        },
      ];

      expect(suggestions).toHaveLength(2);
      expect(suggestions[0].entityType).toBe(SuggestionEntity.game);
      expect(suggestions[1].entityType).toBe(SuggestionEntity.book);
    });
  });

  describe("declineSuggestionDto interface", () => {
    it("should accept empty decline DTO", () => {
      const declineDto: DeclineSuggestionDto = {};
      expect(declineDto.reason).toBeUndefined();
    });

    it("should accept decline DTO with reason", () => {
      const declineDto: DeclineSuggestionDto = {
        reason: "Already exists in the library",
      };
      expect(declineDto.reason).toBe("Already exists in the library");
    });
  });

  describe("acceptWithEditsDto interface", () => {
    it("should accept empty edits DTO", () => {
      const editsDto: AcceptWithEditsDto = {};
      expect(editsDto).toEqual({});
    });

    it("should accept edits for book fields", () => {
      const editsDto: AcceptWithEditsDto = {
        author:     "Corrected Author",
        coverImage: "https://example.com/new-cover.jpg",
        isbn:       "978-0-123-45678-9",
        links:      [ { label: "Goodreads", url: "https://goodreads.com" } ],
        notes:      "Updated notes",
        tags:       [ "fiction", "classic" ],
        title:      "Corrected Title",
      };

      expect(editsDto.title).toBe("Corrected Title");
      expect(editsDto.author).toBe("Corrected Author");
      expect(editsDto.tags).toHaveLength(2);
    });

    it("should accept edits for music fields", () => {
      const editsDto: AcceptWithEditsDto = {
        artist:   "Artist Name",
        coverArt: "https://example.com/album.jpg",
        title:    "Album Title",
        type:     "ALBUM",
      };

      expect(editsDto.artist).toBe("Artist Name");
      expect(editsDto.type).toBe("ALBUM");
      expect(editsDto.coverArt).toBe("https://example.com/album.jpg");
    });

    it("should accept edits for game fields", () => {
      const editsDto: AcceptWithEditsDto = {
        coverImage: "https://example.com/game.jpg",
        notes:      "Action RPG",
        platform:   "PlayStation 5",
        title:      "Game Title",
      };

      expect(editsDto.platform).toBe("PlayStation 5");
    });

    it("should accept edits for art fields", () => {
      const editsDto: AcceptWithEditsDto = {
        artist:      "Artist Name",
        description: "Beautiful artwork",
        imageUrl:    "https://example.com/art.jpg",
        title:       "Art Title",
      };

      expect(editsDto.description).toBe("Beautiful artwork");
      expect(editsDto.imageUrl).toBe("https://example.com/art.jpg");
    });
  });
});
