import { prepareEntry } from "../index";

const makeEntry = (overrides = {}): any => ({
  content: { src: "https://example.com/video.mp4", type: "video/mp4" },
  extensions: {},
  ...overrides,
});

describe("prepareEntry", () => {
  it("should return null when entry is null or undefined", () => {
    expect(prepareEntry(null)).toBeNull();
    expect(prepareEntry(undefined)).toBeNull();
  });

  describe("preview_playback_override", () => {
    it("should deep merge override with entry, override taking precedence", () => {
      const override = {
        link: { href: "https://video-preload.com/id", rel: "self" },
        extensions: {
          brightcove: { video_id: 1234 },
          preview: true,
          free: true,
          requires_authentication: false,
        },
      };

      const entry = makeEntry({
        extensions: {
          preview_playback_override: override,
          existing_field: "keep-me",
        },
      });

      const result = prepareEntry(entry);

      expect(result.extensions.brightcove.video_id).toBe(1234);
      expect(result.extensions.preview).toBe(true);
      expect(result.extensions.existing_field).toBe("keep-me");

      expect(result.link).toEqual({
        href: "https://video-preload.com/id",
        rel: "self",
      });

      expect(result.content).toEqual(entry.content);
    });

    it("should override entry fields when both have the same key", () => {
      const override = {
        extensions: {
          brightcove: { video_id: 9999 },
        },
        content: { src: "https://override.com/video.mp4" },
      };

      const entry = makeEntry({
        extensions: {
          preview_playback_override: override,
          brightcove: { video_id: 1111, account_id: "abc" },
        },
        content: { src: "https://original.com/video.mp4", type: "video/mp4" },
      });

      const result = prepareEntry(entry);

      expect(result.extensions.brightcove.video_id).toBe(9999);
      expect(result.extensions.brightcove.account_id).toBe("abc");
      expect(result.content.src).toBe("https://override.com/video.mp4");
      expect(result.content.type).toBe("video/mp4");
    });

    it("should take priority over other playback sources", () => {
      const override = {
        link: { href: "https://override.com" },
        extensions: { brightcove: { video_id: 5555 } },
      };

      const entry = makeEntry({
        extensions: {
          preview_playback_override: override,
          brightcove: { preview_playback: "other-id" },
          preview_playback: "https://other.com/video.mp4",
        },
        content: {
          src: "https://example.com/video.mp4",
          teaser: "https://teaser.com/video.mp4",
        },
      });

      const result = prepareEntry(entry);

      expect(result.link).toEqual({ href: "https://override.com" });
      expect(result.extensions.brightcove.video_id).toBe(5555);
    });
  });

  describe("brightcove preview_playback", () => {
    it("should return entry with brightcove video_id replaced by preview_playback", () => {
      const entry = makeEntry({
        extensions: {
          brightcove: {
            video_id: "original-id",
            preview_playback: "preview-id",
          },
          some_other: "value",
        },
      });

      const result = prepareEntry(entry);

      expect(result).toEqual({
        ...entry,
        extensions: {
          ...entry.extensions,
          brightcove: {
            video_id: "preview-id",
            preview_playback: "preview-id",
          },
        },
      });
    });

    it("should preserve other extensions", () => {
      const entry = makeEntry({
        extensions: {
          brightcove: { preview_playback: "preview-id" },
          custom_field: "keep-me",
        },
      });

      const result = prepareEntry(entry);

      expect(result.extensions.custom_field).toBe("keep-me");
    });
  });

  describe("extensions.preview_playback (non-brightcove)", () => {
    it("should return entry with content.src set to preview_playback URL", () => {
      const entry = makeEntry({
        extensions: { preview_playback: "https://preview.com/video.m3u8" },
        content: { src: "https://original.com/video.mp4" },
      });

      const result = prepareEntry(entry);

      expect(result.content.src).toBe("https://preview.com/video.m3u8");
    });

    it("should preserve other content fields", () => {
      const entry = makeEntry({
        extensions: { preview_playback: "https://preview.com/video.m3u8" },
        content: { src: "https://original.com/video.mp4", type: "video/mp4" },
      });

      const result = prepareEntry(entry);

      expect(result.content.type).toBe("video/mp4");
    });
  });

  describe("content.teaser", () => {
    it("should return entry with content.src set to teaser URL", () => {
      const entry = makeEntry({
        extensions: {},
        content: {
          src: "https://original.com/video.mp4",
          teaser: "https://teaser.com/teaser.mp4",
        },
      });

      const result = prepareEntry(entry);

      expect(result.content.src).toBe("https://teaser.com/teaser.mp4");
    });
  });

  describe("brightcove video_id (without preview_playback)", () => {
    it("should return the entry as-is when brightcove video_id exists", () => {
      const entry = makeEntry({
        extensions: { brightcove: { video_id: "some-id" } },
        content: { src: "" },
      });

      const result = prepareEntry(entry);

      expect(result).toBe(entry);
    });
  });

  describe("content.src fallback", () => {
    it("should return null when content.src is missing", () => {
      const entry = makeEntry({
        extensions: {},
        content: {},
      });

      expect(prepareEntry(entry)).toBeNull();
    });

    it("should return null when content.src is empty", () => {
      const entry = makeEntry({
        extensions: {},
        content: { src: "" },
      });

      expect(prepareEntry(entry)).toBeNull();
    });

    it("should return entry when content.type starts with video", () => {
      const entry = makeEntry({
        extensions: {},
        content: { src: "https://example.com/stream", type: "video/mp4" },
      });

      expect(prepareEntry(entry)).toBe(entry);
    });

    it("should return entry when src has a known video extension", () => {
      const extensions = ["m3u8", "mp4", "m4v", "mkv", "mov", "mpd", "ogv"];

      for (const ext of extensions) {
        const entry = makeEntry({
          extensions: {},
          content: { src: `https://example.com/video.${ext}` },
        });

        expect(prepareEntry(entry)).toBe(entry);
      }
    });

    it("should return entry for audio extensions", () => {
      const extensions = ["mp3", "oga", "opus"];

      for (const ext of extensions) {
        const entry = makeEntry({
          extensions: {},
          content: { src: `https://example.com/audio.${ext}` },
        });

        expect(prepareEntry(entry)).toBe(entry);
      }
    });

    it("should return null for non-video/non-audio URLs", () => {
      const entry = makeEntry({
        extensions: {},
        content: { src: "https://example.com/page.html" },
      });

      expect(prepareEntry(entry)).toBeNull();
    });

    it("should return null for URLs without extensions", () => {
      const entry = makeEntry({
        extensions: {},
        content: { src: "https://example.com/stream" },
      });

      expect(prepareEntry(entry)).toBeNull();
    });
  });

  describe("priority order", () => {
    it("should prefer brightcove.preview_playback over extensions.preview_playback", () => {
      const entry = makeEntry({
        extensions: {
          brightcove: { preview_playback: "bc-preview" },
          preview_playback: "ext-preview",
        },
      });

      const result = prepareEntry(entry);

      expect(result.extensions.brightcove.video_id).toBe("bc-preview");
    });

    it("should prefer extensions.preview_playback over content.teaser", () => {
      const entry = makeEntry({
        extensions: { preview_playback: "https://preview.com/video.mp4" },
        content: {
          src: "https://original.com/video.mp4",
          teaser: "https://teaser.com/video.mp4",
        },
      });

      const result = prepareEntry(entry);

      expect(result.content.src).toBe("https://preview.com/video.mp4");
    });

    it("should prefer preview_playback_override over all other sources", () => {
      const override = {
        extensions: { brightcove: { video_id: "override-id" } },
      };

      const entry = makeEntry({
        extensions: {
          preview_playback_override: override,
          brightcove: { preview_playback: "bc-preview", video_id: "original" },
          preview_playback: "https://ext-preview.com/video.mp4",
        },
        content: {
          src: "https://original.com/video.mp4",
          teaser: "https://teaser.com/video.mp4",
        },
      });

      const result = prepareEntry(entry);

      expect(result.extensions.brightcove.video_id).toBe("override-id");
    });

    it("should prefer content.teaser over brightcove.video_id", () => {
      const entry = makeEntry({
        extensions: { brightcove: { video_id: "some-id" } },
        content: {
          src: "https://original.com/video.mp4",
          teaser: "https://teaser.com/teaser.mp4",
        },
      });

      const result = prepareEntry(entry);

      expect(result.content.src).toBe("https://teaser.com/teaser.mp4");
    });

    it("should prefer content.teaser over content.src URL check", () => {
      const entry = makeEntry({
        extensions: {},
        content: {
          src: "https://original.com/video.mp4",
          teaser: "https://teaser.com/teaser.m3u8",
        },
      });

      const result = prepareEntry(entry);

      expect(result.content.src).toBe("https://teaser.com/teaser.m3u8");
    });

    it("should prefer brightcove.video_id over content.src URL check", () => {
      const entry = makeEntry({
        extensions: { brightcove: { video_id: "bc-id" } },
        content: { src: "https://example.com/page.html" },
      });

      const result = prepareEntry(entry);

      expect(result).toBe(entry);
    });
  });
});
