import { describe, expect, it } from "vitest";

import {
  countMediaUsageReferences,
  createMediaAsset,
  deleteEntityMediaUsages,
  getAdminMediaAssets,
  getMediaAssetById,
  getMediaOptions,
  getPortfolioMediaBindings,
  replaceEntityMediaUsages,
} from "@/lib/media";
import { db } from "@/lib/db";
import { mediaUsage } from "@/lib/db/schema";
import { createMediaAsset as seedAsset } from "@/tests/helpers/factories";

describe("createMediaAsset / getMediaAssetById", () => {
  it("creates and reads back an asset with usages", async () => {
    const created = await createMediaAsset({
      source: "EXTERNAL",
      kind: "IMAGE",
      url: "https://cdn/x.png",
      fileName: "x.png",
      label: "X",
    });
    const found = await getMediaAssetById(created.id);
    expect(found?.url).toBe("https://cdn/x.png");
    expect(found?.usages).toEqual([]);
  });

  it("returns null for a missing asset", async () => {
    expect(await getMediaAssetById("nope")).toBeNull();
  });
});

describe("getMediaOptions", () => {
  it("filters by kind", async () => {
    await seedAsset({ kind: "IMAGE" });
    await seedAsset({ kind: "DOCUMENT" });
    const images = await getMediaOptions({ kind: "IMAGE" });
    expect(images.every((a) => a.kind === "IMAGE")).toBe(true);
    const all = await getMediaOptions();
    expect(all.length).toBe(2);
  });
});

describe("getAdminMediaAssets", () => {
  it("returns newest first with usage details", async () => {
    const a = await seedAsset();
    await createMediaUsageFor(a.id);
    const list = await getAdminMediaAssets();
    expect(list.length).toBe(1);
    expect(list[0].usages.length).toBe(1);
  });
});

describe("replaceEntityMediaUsages", () => {
  it("replaces existing usages transactionally", async () => {
    const a1 = await seedAsset();
    const a2 = await seedAsset();

    await replaceEntityMediaUsages({
      entityType: "portfolio-project",
      entityId: "p1",
      usages: [{ assetId: a1.id, usageType: "PORTFOLIO_COVER", fieldKey: "cover" }],
    });
    expect(await countMediaUsageReferences(a1.id)).toBe(1);

    await replaceEntityMediaUsages({
      entityType: "portfolio-project",
      entityId: "p1",
      usages: [{ assetId: a2.id, usageType: "PORTFOLIO_COVER", fieldKey: "cover" }],
    });
    expect(await countMediaUsageReferences(a1.id)).toBe(0);
    expect(await countMediaUsageReferences(a2.id)).toBe(1);
  });

  it("clears usages when given an empty list", async () => {
    const a1 = await seedAsset();
    await replaceEntityMediaUsages({
      entityType: "portfolio-project",
      entityId: "p2",
      usages: [{ assetId: a1.id, usageType: "PORTFOLIO_ASSET", fieldKey: "a" }],
    });
    await replaceEntityMediaUsages({ entityType: "portfolio-project", entityId: "p2", usages: [] });
    expect(await countMediaUsageReferences(a1.id)).toBe(0);
  });
});

describe("deleteEntityMediaUsages", () => {
  it("removes only the target entity's usages", async () => {
    const a1 = await seedAsset();
    await replaceEntityMediaUsages({
      entityType: "portfolio-project",
      entityId: "keep",
      usages: [{ assetId: a1.id, usageType: "PORTFOLIO_ASSET", fieldKey: "a" }],
    });
    await replaceEntityMediaUsages({
      entityType: "portfolio-project",
      entityId: "drop",
      usages: [{ assetId: a1.id, usageType: "PORTFOLIO_ASSET", fieldKey: "b" }],
    });
    await deleteEntityMediaUsages("portfolio-project", "drop");
    expect(await countMediaUsageReferences(a1.id)).toBe(1);
  });
});

describe("getPortfolioMediaBindings", () => {
  it("routes usages into cover / section / asset buckets", async () => {
    const cover = await seedAsset();
    const section = await seedAsset();
    const asset = await seedAsset();

    await db.insert(mediaUsage).values([
        { assetId: cover.id, usageType: "PORTFOLIO_COVER", entityType: "portfolio-project", entityId: "proj", fieldKey: "cover" },
        { assetId: section.id, usageType: "PORTFOLIO_SECTION", entityType: "portfolio-project", entityId: "proj", fieldKey: "sec_1" },
        { assetId: asset.id, usageType: "PORTFOLIO_ASSET", entityType: "portfolio-project", entityId: "proj", fieldKey: "ast_1" },
      ]);

    const bindings = await getPortfolioMediaBindings("proj");
    expect(bindings.coverAssetId).toBe(cover.id);
    expect(bindings.sectionAssetIds.sec_1).toBe(section.id);
    expect(bindings.assetIds.ast_1).toBe(asset.id);
  });

  it("returns empty bindings for an unknown project", async () => {
    const bindings = await getPortfolioMediaBindings("missing");
    expect(bindings).toEqual({ coverAssetId: null, sectionAssetIds: {}, assetIds: {} });
  });
});

async function createMediaUsageFor(assetId: string) {
  await db.insert(mediaUsage).values({ assetId, usageType: "GENERIC", entityType: "e", entityId: "1", fieldKey: "f" });
}
