/**
 * Dựng một cơ sở dữ liệu PGlite TRONG BỘ NHỚ cho từng test file (xem `vitest.config.ts`:
 * `PGLITE_DIR=memory://`), áp toàn bộ migration rồi rắc một bộ dữ liệu mẫu tối thiểu —
 * đủ để test phạm vi dữ liệu theo vai trò (`scopeFilter`, `loadCustomerList`, `loadOrderList`…),
 * không phải bộ 40 đại lý đầy đủ của `src/db/seed.ts` (chậm và không cần cho việc này).
 *
 * Gọi `resetTestDb()` một lần trong `beforeAll` của mỗi test file tích hợp.
 */
import { readdirSync, readFileSync } from "node:fs";
import { join } from "node:path";
import { sql } from "drizzle-orm";
import { db } from "@/db";
import { channels, customers, departments, orders, tenants, territories, users } from "@/db/schema";
import type { SessionUser } from "@/lib/auth";

let migrated = false;

/** Áp toàn bộ file trong `drizzle/` lên cơ sở dữ liệu trong bộ nhớ — chỉ chạy một lần cho mỗi worker test. */
export async function migrateTestDb() {
  if (migrated) return;
  const dir = join(process.cwd(), "drizzle");
  const files = readdirSync(dir)
    .filter((f) => f.endsWith(".sql"))
    .sort();
  for (const file of files) {
    const text = readFileSync(join(dir, file), "utf8");
    for (const statement of text.split("--> statement-breakpoint").map((s) => s.trim()).filter(Boolean)) {
      // Nội dung tệp migration do drizzle-kit sinh ra, không phải dữ liệu người dùng — cùng cách `src/db/push.ts` áp migration lên
      // PGlite/Postgres thật; chỉ khác là dùng chung kết nối `db` để test đọc/ghi đúng cơ sở dữ liệu vừa tạo.
      // eslint-disable-next-line no-restricted-syntax
      await db.execute(sql.raw(statement));
    }
  }
  migrated = true;
}

export type Fixture = {
  tenantA: string;
  tenantB: string;
  deptBac: string;
  deptNam: string;
  hanoi: string;
  hcm: string;
  channel: string;
  director: SessionUser;
  managerBac: SessionUser;
  salesBac: string; // id thôi — dùng để dựng session SALES khi cần
  salesBacSession: SessionUser;
  salesNamSession: SessionUser;
  /** Khách của salesBac (nhánh Bắc). */
  custBac: string;
  /** Khách của người thuộc nhánh Nam. */
  custNam: string;
  /** Một tenant khác hẳn, dùng test rò rỉ giữa các công ty. */
  directorTenantB: SessionUser;
  custTenantB: string;
  /** Tên kênh/khu vực thật (dùng khi cần ghi đúng chữ vào file nhập Excel test). */
  channelName: string;
  territoryName: string;
};

const session = (over: Partial<SessionUser> & Pick<SessionUser, "userId" | "tenantId" | "role">): SessionUser => ({
  email: "test@example.com",
  fullName: "Người test",
  territoryId: null,
  tenantName: "Test",
  ...over,
});

/**
 * Rắc dữ liệu mẫu: 2 tenant (A, B, để kiểm tenant không lẫn nhau), tenant A có 2 phòng
 * (Bắc, Nam) mỗi phòng 1 NVKD + 1 khách + 1 đơn CONFIRMED, và 1 quản lý phụ trách phòng Bắc.
 */
export async function seedMinimalFixture(): Promise<Fixture> {
  await migrateTestDb();

  const [tenantA] = await db.insert(tenants).values({ name: "Công ty A", code: `TA-${crypto.randomUUID()}` }).returning();
  const [tenantB] = await db.insert(tenants).values({ name: "Công ty B", code: `TB-${crypto.randomUUID()}` }).returning();

  const [hanoi] = await db.insert(territories).values({ tenantId: tenantA.id, code: "HN", name: "Hà Nội", level: "PROVINCE" }).returning();
  const [hcm] = await db.insert(territories).values({ tenantId: tenantA.id, code: "HCM", name: "TP. Hồ Chí Minh", level: "PROVINCE" }).returning();
  const [channel] = await db.insert(channels).values({ tenantId: tenantA.id, code: "PK", name: "Phòng khám" }).returning();

  const [deptBac] = await db.insert(departments).values({ tenantId: tenantA.id, code: "BAC", name: "Team Miền Bắc" }).returning();
  const [deptNam] = await db.insert(departments).values({ tenantId: tenantA.id, code: "NAM", name: "Team Miền Nam" }).returning();

  const passwordHash = "test-khong-dung-de-dang-nhap";
  const [director] = await db.insert(users).values({ tenantId: tenantA.id, email: "giamdoc@test.local", passwordHash, fullName: "Giám đốc", role: "DIRECTOR" }).returning();
  const [manager] = await db.insert(users).values({ tenantId: tenantA.id, email: "quanly.bac@test.local", passwordHash, fullName: "Quản lý Bắc", role: "MANAGER", departmentId: deptBac.id }).returning();
  const [salesBac] = await db.insert(users).values({ tenantId: tenantA.id, email: "nv.bac@test.local", passwordHash, fullName: "NVKD Bắc", role: "SALES", departmentId: deptBac.id, territoryId: hanoi.id }).returning();
  const [salesNam] = await db.insert(users).values({ tenantId: tenantA.id, email: "nv.nam@test.local", passwordHash, fullName: "NVKD Nam", role: "SALES", departmentId: deptNam.id, territoryId: hcm.id }).returning();

  const [custBac] = await db
    .insert(customers)
    .values({ tenantId: tenantA.id, code: "KHB01", orgName: "Khách Bắc", stage: "DEALER", ownerId: salesBac.id, territoryId: hanoi.id, channelId: channel.id })
    .returning();
  const [custNam] = await db
    .insert(customers)
    .values({ tenantId: tenantA.id, code: "KHN01", orgName: "Khách Nam", stage: "DEALER", ownerId: salesNam.id, territoryId: hcm.id, channelId: channel.id })
    .returning();

  await db.insert(orders).values([
    { tenantId: tenantA.id, code: "DHB01", customerId: custBac.id, orderDate: "2026-08-05", salesUserId: salesBac.id, departmentId: deptBac.id, territoryId: hanoi.id, channelId: channel.id, status: "CONFIRMED", totalAmount: 1_000_000 },
    { tenantId: tenantA.id, code: "DHN01", customerId: custNam.id, orderDate: "2026-08-05", salesUserId: salesNam.id, departmentId: deptNam.id, territoryId: hcm.id, channelId: channel.id, status: "CONFIRMED", totalAmount: 2_000_000 },
  ]);

  // Tenant B: hoàn toàn tách biệt, chỉ để kiểm DIRECTOR của A không bao giờ thấy dữ liệu của B.
  const [deptB] = await db.insert(departments).values({ tenantId: tenantB.id, code: "X", name: "Phòng X" }).returning();
  const [directorB] = await db.insert(users).values({ tenantId: tenantB.id, email: "giamdoc@b.local", passwordHash, fullName: "Giám đốc B", role: "DIRECTOR" }).returning();
  const [salesB] = await db.insert(users).values({ tenantId: tenantB.id, email: "nv@b.local", passwordHash, fullName: "NVKD B", role: "SALES", departmentId: deptB.id }).returning();
  const [custTenantB] = await db.insert(customers).values({ tenantId: tenantB.id, code: "KHX01", orgName: "Khách công ty B", stage: "DEALER", ownerId: salesB.id }).returning();

  return {
    tenantA: tenantA.id,
    tenantB: tenantB.id,
    deptBac: deptBac.id,
    deptNam: deptNam.id,
    hanoi: hanoi.id,
    hcm: hcm.id,
    channel: channel.id,
    director: session({ userId: director.id, tenantId: tenantA.id, role: "DIRECTOR" }),
    managerBac: session({ userId: manager.id, tenantId: tenantA.id, role: "MANAGER" }),
    salesBac: salesBac.id,
    salesBacSession: session({ userId: salesBac.id, tenantId: tenantA.id, role: "SALES", territoryId: hanoi.id }),
    salesNamSession: session({ userId: salesNam.id, tenantId: tenantA.id, role: "SALES", territoryId: hcm.id }),
    custBac: custBac.id,
    custNam: custNam.id,
    directorTenantB: session({ userId: directorB.id, tenantId: tenantB.id, role: "DIRECTOR" }),
    custTenantB: custTenantB.id,
    channelName: channel.name,
    territoryName: hanoi.name,
  };
}
