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

import {
  getActivePortfolioCategories,
  getActivePortfolioCategoryBySlug,
  getAdminPortfolioCategories,
  getAdminPortfolioProjectById,
  getAdminPortfolioProjects,
  getPublishedPortfolioProjectBySlug,
  getPublishedPortfolioProjects,
} from "@/lib/portfolio";
import { eq } from "drizzle-orm";

import { db } from "@/lib/db";
import { category, mediaUsage, portfolioAsset, portfolioProject, portfolioSection } from "@/lib/db/schema";
import {
  createAsset,
  createCategory,
  createMediaAsset,
  createProject,
  createSection,
} from "@/tests/helpers/factories";

describe("categories", () => {
  it("lists admin categories with project counts, ordered", async () => {
    const a = await createCategory({ slug: "a", sortOrder: 2 });
    await createCategory({ slug: "b", sortOrder: 1 });
    await createProject({ categoryId: a.id });

    const categories = await getAdminPortfolioCategories();
    expect(categories.map((c) => c.slug)).toEqual(["b", "a"]); // sortOrder asc
    expect(categories.find((c) => c.slug === "a")?.projectCount).toBe(1);
    expect(categories.find((c) => c.slug === "b")?.projectCount).toBe(0);
  });

  it("returns only active categories publicly", async () => {
    await createCategory({ slug: "on", isActive: true });
    await createCategory({ slug: "off", isActive: false });
    const active = await getActivePortfolioCategories();
    expect(active.map((c) => c.slug)).toEqual(["on"]);
  });

  it("finds an active category by slug and ignores inactive ones", async () => {
    await createCategory({ slug: "visible", isActive: true });
    await createCategory({ slug: "hidden", isActive: false });
    expect((await getActivePortfolioCategoryBySlug("visible"))?.slug).toBe("visible");
    expect(await getActivePortfolioCategoryBySlug("hidden")).toBeNull();
  });
});

describe("admin projects", () => {
  it("filters by status and category", async () => {
    const cat = await createCategory();
    await createProject({ categoryId: cat.id, slug: "pub", isPublished: true });
    await createProject({ categoryId: cat.id, slug: "draft", isPublished: false });

    const published = await getAdminPortfolioProjects({ status: "published" });
    expect(published.map((p) => p.slug)).toEqual(["pub"]);

    const drafts = await getAdminPortfolioProjects({ status: "draft" });
    expect(drafts.map((p) => p.slug)).toEqual(["draft"]);

    const byCategory = await getAdminPortfolioProjects({ categoryId: cat.id });
    expect(byCategory.length).toBe(2);
  });

  it("maps localized content and nested sections/assets", async () => {
    const project = await createProject({ slug: "mapped" });
    await createSection(project.id, { titleEn: "Intro" });
    await createAsset(project.id, { altEn: "Cover" });

    const detail = await getAdminPortfolioProjectById(project.id);
    expect(detail?.title.en).toBe("Title");
    expect(detail?.sections[0].title.en).toBe("Intro");
    expect(detail?.assets[0].alt.en).toBe("Cover");
  });

  it("attaches media bindings to a project fetched by id", async () => {
    const project = await createProject();
    const cover = await createMediaAsset();
    await db.insert(mediaUsage).values({
        assetId: cover.id,
        usageType: "PORTFOLIO_COVER",
        entityType: "portfolio-project",
        entityId: project.id,
        fieldKey: "cover",
      });
    const detail = await getAdminPortfolioProjectById(project.id);
    expect(detail?.coverMediaAssetId).toBe(cover.id);
  });

  it("returns null for a missing project id", async () => {
    expect(await getAdminPortfolioProjectById("missing")).toBeNull();
  });
});

describe("published projects", () => {
  it("returns only published projects in active categories", async () => {
    const activeCat = await createCategory({ isActive: true });
    const inactiveCat = await createCategory({ isActive: false });
    await createProject({ categoryId: activeCat.id, slug: "shown", isPublished: true });
    await createProject({ categoryId: activeCat.id, slug: "hidden-draft", isPublished: false });
    await createProject({ categoryId: inactiveCat.id, slug: "hidden-cat", isPublished: true });

    const projects = await getPublishedPortfolioProjects();
    expect(projects.map((p) => p.slug)).toEqual(["shown"]);
  });

  it("filters published projects by category slug", async () => {
    const catA = await createCategory({ slug: "cat-a", isActive: true });
    const catB = await createCategory({ slug: "cat-b", isActive: true });
    await createProject({ categoryId: catA.id, slug: "in-a", isPublished: true });
    await createProject({ categoryId: catB.id, slug: "in-b", isPublished: true });

    const projects = await getPublishedPortfolioProjects({ categorySlug: "cat-a" });
    expect(projects.map((p) => p.slug)).toEqual(["in-a"]);
  });

  it("finds a published project by slug and hides drafts", async () => {
    await createProject({ slug: "live", isPublished: true });
    await createProject({ slug: "wip", isPublished: false });
    expect((await getPublishedPortfolioProjectBySlug("live"))?.slug).toBe("live");
    expect(await getPublishedPortfolioProjectBySlug("wip")).toBeNull();
  });
});

describe("referential integrity", () => {
  it("restricts deleting a category that still has projects", async () => {
    const cat = await createCategory();
    await createProject({ categoryId: cat.id });
    await expect(db.delete(category).where(eq(category.id, cat.id))).rejects.toThrow();
  });

  it("cascades section and asset deletion when a project is removed", async () => {
    const project = await createProject();
    await createSection(project.id);
    await createAsset(project.id);
    await db.delete(portfolioProject).where(eq(portfolioProject.id, project.id));
    expect(await db.$count(portfolioSection)).toBe(0);
    expect(await db.$count(portfolioAsset)).toBe(0);
  });
});
