import { it, expect, beforeEach, describe } from "vitest";
import { defineContractSuite } from "@repo/core-testing/contract";
import type { IMediaRepository } from "../application/repositories/media.repository.interface.js";
import { mediaFactory } from "../__factories__/media.factory.js";

export const mediaRepositoryContract = defineContractSuite<IMediaRepository>(
  "IMediaRepository",
  ({ buildSubject, getTracer }) => {
    let repo: IMediaRepository;

    beforeEach(async () => {
      mediaFactory.reset();
      repo = await buildSubject();
    });

    // --- getMedia ---

    it("getMedia returns undefined for a missing id", async () => {
      const result = await repo.getMedia("does-not-exist");
      expect(result).toBeUndefined();
    });

    // --- listMedia ---

    it("listMedia returns empty array when no media exists", async () => {
      const result = await repo.listMedia();
      expect(result).toHaveLength(0);
    });

    // --- deleteMedia ---

    it("deleteMedia removes the item so getMedia returns undefined", async () => {
      const seed = mediaFactory.build({ id: "contract-1" });
      // @ts-expect-error _store is a test helper on MockMediaRepository
      if (typeof repo._store === "function") {
        // @ts-expect-error _store is a test helper
        await repo._store(seed);
      }
      await repo.deleteMedia("contract-1");
      const result = await repo.getMedia("contract-1");
      expect(result).toBeUndefined();
    });

    it("listMedia with limit returns at most limit items", async () => {
      // Only verifiable on mock; for real impl this checks the interface
      const result = await repo.listMedia({ limit: 0 });
      expect(Array.isArray(result)).toBe(true);
    });

    it("listMedia with offset skips items", async () => {
      const result = await repo.listMedia({ offset: 100 });
      expect(Array.isArray(result)).toBe(true);
    });

    it("getMedia returns undefined for empty string id", async () => {
      const result = await repo.getMedia("");
      expect(result).toBeUndefined();
    });

    describe("span emission", () => {
      it("getMedia emits media.getMedia span with id attribute", async () => {
        if (!getTracer) return;
        const tracer = getTracer();
        tracer.reset();
        await repo.getMedia("nonexistent");
        const span = tracer.findSpan("media.getMedia");
        expect(span).toBeDefined();
        expect(span!.op).toBe("repository");
        expect(span!.attributes.id).toBe("nonexistent");
      });

      it("listMedia emits media.listMedia span with op=repository", async () => {
        if (!getTracer) return;
        const tracer = getTracer();
        tracer.reset();
        await repo.listMedia({ limit: 10 });
        const span = tracer.findSpan("media.listMedia");
        expect(span).toBeDefined();
        expect(span!.op).toBe("repository");
        expect(span!.attributes.limit).toBe(10);
      });

      it("deleteMedia emits media.deleteMedia span with id attribute", async () => {
        if (!getTracer) return;
        const tracer = getTracer();
        tracer.reset();
        await repo.deleteMedia("nonexistent");
        const span = tracer.findSpan("media.deleteMedia");
        expect(span).toBeDefined();
        expect(span!.op).toBe("repository");
        expect(span!.attributes.id).toBe("nonexistent");
      });
    });
  },
);
