import { describe, it, expect } from "vitest";
import { PgDialect } from "drizzle-orm/pg-core";
import { tagFilterCondition } from "./tagFilterSql";
import { emptyTagFilter } from "./viewState";

const render = (frag: ReturnType<typeof tagFilterCondition>) =>
  new PgDialect().sqlToQuery(frag);

describe("tagFilterCondition", () => {
  it("is a no-op TRUE when the filter is empty (never filters everything out)", () => {
    const { sql, params } = render(tagFilterCondition(emptyTagFilter()));
    expect(sql.trim().toLowerCase()).toBe("true");
    expect(params).toEqual([]);
  });

  it("include (any) → EXISTS over property_tag with the ids bound", () => {
    const { sql, params } = render(
      tagFilterCondition({ include: ["10", "20"], exclude: [], includeMode: "any" }),
    );
    expect(sql).toMatch(/EXISTS/);
    expect(sql).not.toMatch(/NOT EXISTS/);
    expect(sql).toMatch(/property_tag/);
    expect(params).toEqual([10n, 20n]);
  });

  it("include (all) → COUNT(DISTINCT …) = include size", () => {
    const { sql } = render(
      tagFilterCondition({ include: ["10", "20"], exclude: [], includeMode: "all" }),
    );
    expect(sql).toMatch(/COUNT\(DISTINCT/i);
    expect(sql).toMatch(/= \$3/); // the size literal is the 3rd bound param
  });

  it("exclude → NOT EXISTS", () => {
    const { sql, params } = render(
      tagFilterCondition({ include: [], exclude: ["30"], includeMode: "any" }),
    );
    expect(sql).toMatch(/NOT EXISTS/);
    expect(params).toEqual([30n]);
  });

  it("include + exclude are ANDed together", () => {
    const { sql } = render(
      tagFilterCondition({ include: ["10"], exclude: ["30"], includeMode: "any" }),
    );
    expect(sql).toMatch(/EXISTS[\s\S]*AND[\s\S]*NOT EXISTS/);
  });
});
