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

import {
  loadFacilityNameIndex,
  type FacilityNameRow,
  type FacilityNameSourcePrisma,
} from "@/lib/db/facility-name-source";

/**
 * 指示書AC 段階2 ★D-6 / 罠7★ — 施設名の解決用の読み取りは `deleted_at` で絞らない。
 *
 * ★★なぜ★★: `cleanLogs()` の `include: { facility: true }` には `deleted_at` の条件が無く、
 *   ★論理削除された施設のログも一覧に出ている★。ここで絞ると、その施設名で検索したときに
 *   ★施設IDが解決結果に入らず、`facility_id: { in: [...] }` から漏れてログが静かに消える★
 *   （★件数が減るだけで例外もテスト失敗も出ない★）。
 *
 * ★★ローカルDBでは検出できません★★ — 実測で `facilities` 12件のうち
 *   ★論理削除された行は0件★（2026-09-13。`db.facilities()` も `facilityNameIndex()` も12件）。
 *   ★だから合成データで固定する★。
 */

/** `findMany()` に渡された引数を控えるスタブ（★DBに接続しない★） */
function stubPrisma(rows: readonly FacilityNameRow[]): {
  prisma: FacilityNameSourcePrisma;
  calls: unknown[];
} {
  const calls: unknown[] = [];
  const prisma: FacilityNameSourcePrisma = {
    facility: {
      async findMany(args) {
        calls.push(args);
        return [...rows];
      },
    },
  };
  return { prisma, calls };
}

describe("loadFacilityNameIndex（指示書AC 段階2 D-6 / 罠7）", () => {
  it("★★`where` を一切付けない★★（＝ `deleted_at` で絞らない。罠7 の唯一の検出手段）", async () => {
    const { prisma, calls } = stubPrisma([]);
    await loadFacilityNameIndex(prisma);

    expect(calls).toEqual([{ select: { id: true, facility_name: true } }]);
    // ★★`where` が足されていないこと（キーが `select` だけ）★★ —
    //   ★`db.facilities()` をそのまま流用すると `where: { deleted_at: null }` が付く★
    for (const args of calls) {
      expect(Object.keys(args as object)).toEqual(["select"]);
    }
  });

  it("読む列は `id` と `facility_name` だけ（★これ以上増やさない★）", async () => {
    const { prisma, calls } = stubPrisma([]);
    await loadFacilityNameIndex(prisma);
    const select = (calls[0] as { select: Record<string, unknown> }).select;
    expect(Object.keys(select).sort()).toEqual(["facility_name", "id"]);
  });

  it("★論理削除された施設も返す★（返す行を間引かないこと）", async () => {
    // ★スタブは「DBが返した行」を表す。`deleted_at` で絞っていないので削除済みも来る★
    const { prisma } = stubPrisma([
      { id: BigInt(1), facility_name: "ドソ・キホーテ戸塚" },
      { id: BigInt(2), facility_name: "ドソ・キホーテ四街道（論理削除済み）" },
    ]);
    const rows = await loadFacilityNameIndex(prisma);
    expect(rows).toHaveLength(2);
    expect(rows.map((r) => r.id)).toEqual([1, 2]);
  });

  it("★BigInt を `number` に直して返す★（`NextResponse.json` が BigInt で例外を投げるため）", async () => {
    const { prisma } = stubPrisma([{ id: BigInt(12), facility_name: "メガバリューマート港南総本店" }]);
    const rows = await loadFacilityNameIndex(prisma);
    expect(rows).toEqual([{ id: 12, facility_name: "メガバリューマート港南総本店" }]);
    expect(typeof rows[0].id).toBe("number");
  });

  it("★照合はここでやらない★（施設名を加工せずそのまま運ぶ）", async () => {
    const { prisma } = stubPrisma([{ id: BigInt(1), facility_name: "ドソ・キホーテ 戸塚－本店" }]);
    const rows = await loadFacilityNameIndex(prisma);
    // ★記号を落とすのは `includesFoldName` の仕事（規則を2箇所に散らさない）★
    expect(rows[0].facility_name).toBe("ドソ・キホーテ 戸塚－本店");
  });
});
