import { test as baseTest, describe, vi } from "vitest";
import type { UrlGenerator } from "../../../transcoding/utils/UrlGenerator";
import {
  createMediaEngine,
  handleMediaEngineComplete,
} from "./makeMediaEngineTask";

// Define test fixtures using test.extend
const test = baseTest.extend<{
  mockUrlGenerator: UrlGenerator;
  mockHost: any;
  mockTimegroup: any;
}>({
  mockUrlGenerator: async ({}, use) => {
    const mockUrlGenerator = {
      generateManifestUrl: vi
        .fn()
        .mockReturnValue("https://example.com/manifest.m3u8"),
    } as any;
    await use(mockUrlGenerator);
  },

  mockTimegroup: async ({}, use) => {
    const mockTimegroup = {
      currentTimeMs: 0,
      requestUpdate: vi.fn(),
    };
    await use(mockTimegroup);
  },

  mockHost: async ({ mockTimegroup, mockUrlGenerator }, use) => {
    const mockHost = {
      src: "https://example.com/video.mp4",
      assetId: null,
      urlGenerator: mockUrlGenerator,
      apiHost: "https://api.example.com",
      requestUpdate: vi.fn(),
      rootTimegroup: mockTimegroup,
    };
    await use(mockHost);
  },
});

describe("createMediaEngine", () => {
  describe("input validation", () => {
    test("should reject when assetId provided but apiHost is missing", async ({
      mockHost,
      expect,
    }) => {
      // Set up host with assetId but no apiHost
      mockHost.src = "test.mp4";
      mockHost.assetId = "asset123";
      mockHost.apiHost = null;

      await expect(createMediaEngine(mockHost)).rejects.toThrow(
        "API host is required for AssetID mode",
      );
    });

    test("should reject with empty src", async ({ mockHost, expect }) => {
      // Set up host with empty src
      mockHost.src = "";
      mockHost.assetId = null;

      await expect(createMediaEngine(mockHost)).rejects.toThrow(
        "Unsupported media source",
      );
    });

    test("should reject with null src", async ({ mockHost, expect }) => {
      // Set up host with null src
      mockHost.src = null;
      mockHost.assetId = null;

      await expect(createMediaEngine(mockHost)).rejects.toThrow(
        "Unsupported media source",
      );
    });

    test("should reject with whitespace-only src", async ({
      mockHost,
      expect,
    }) => {
      // Set up host with whitespace-only src
      mockHost.src = "   \t\n  ";
      mockHost.assetId = null;

      await expect(createMediaEngine(mockHost)).rejects.toThrow(
        "Unsupported media source",
      );
    });
  });
});

describe("handleMediaEngineComplete", () => {
  test("should call requestUpdate on host", async ({ mockHost, expect }) => {
    handleMediaEngineComplete(mockHost);

    expect(mockHost.requestUpdate).toHaveBeenCalledWith("intrinsicDurationMs");
    expect(mockHost.requestUpdate).toHaveBeenCalledWith("ownCurrentTimeMs");
  });

  test("should call requestUpdate on rootTimegroup when present", async ({
    mockHost,
    mockTimegroup,
    expect,
  }) => {
    handleMediaEngineComplete(mockHost);

    expect(mockTimegroup.requestUpdate).toHaveBeenCalledWith(
      "ownCurrentTimeMs",
    );
    expect(mockTimegroup.requestUpdate).toHaveBeenCalledWith("durationMs");
  });

  test("should handle missing rootTimegroup gracefully", async ({
    mockHost,
    expect,
  }) => {
    mockHost.rootTimegroup = null;

    // Should not throw
    handleMediaEngineComplete(mockHost);

    expect(mockHost.requestUpdate).toHaveBeenCalledWith("intrinsicDurationMs");
    expect(mockHost.requestUpdate).toHaveBeenCalledWith("ownCurrentTimeMs");
  });
});
