/**
 * UC22 — Case 249: **2 (hoặc nhiều) người cùng tạo mới thư mục tại cùng một thời điểm**
 * (tên thư mục khác nhau).
 *
 * Kịch bản (theo mô tả người dùng):
 *   1. Tạo 1 Bộ hồ sơ.
 *   2. Mở 2 trình duyệt, mỗi trình duyệt chuẩn bị **đầy đủ** dữ liệu tạo thư mục (chưa lưu),
 *      sau đó **cả 2 bấm Xác nhận cùng lúc**.
 *   3. Mong muốn: **tạo được cả 2 thư mục** chính xác (đúng tên, không mất, không nhân đôi).
 *      Chỉ mục (mã prefix `A`/`B`) **không quan trọng** vì 2 thư mục sinh cùng thời điểm.
 *
 * 📌 Ghi chú cách viết (theo yêu cầu người dùng 2026-08-01):
 * - Toàn bộ bước dựng dữ liệu + thao tác viết **thẳng trong file spec này**, không đẩy vào
 *   `1.4.1.setup.ts` / `1.4.1.steps.ts` — kịch bản 2 phiên song song là đặc thù của case 249,
 *   không dùng lại được ở case khác.
 * - "Cùng một thời điểm" được mô phỏng bằng `Promise.all`: 2 lệnh click chạy trên 2 context
 *   khác nhau và được **phát đi trong cùng một tick**, không có rào chắn nào ở giữa. Đây là mức
 *   đồng thời tối đa Playwright cho phép trong 1 test (không thể đảm bảo 2 request tới server
 *   trùng đúng mili-giây).
 * - 1 test duy nhất nhưng **phủ cả 2 vai** mặc định của dự án: Thủ thư (`ecm01`) tạo BHS và là
 *   người thứ nhất, Admin (`ecm09`) là người thứ hai. Muốn thử "nhiều người" hơn thì chỉ cần
 *   thêm phần tử vào mảng `nguoiThamGia` (xem `runTest`).
 *
 * ⚠️ Giả định khi dựng dữ liệu (chưa khảo sát, ghi ở `1.4.1.md` mục 4):
 * - Người thứ hai được cấp **Quyền Owner ở BHS** ngay lúc tạo + BHS `chuyenHoatDong` — bắt buộc
 *   vì vai không phải người tạo BHS chỉ mở được BHS ở trạng thái "Hoạt động"
 *   (`KHO-TAI-LIEU.PHAN-QUYEN-THEO-VAI.md` mục 1). Riêng vai Admin chưa được khảo sát nên không
 *   dựa vào "Admin mặc định thấy mọi BHS".
 * - BHS tạo bằng loại hồ sơ `AUTO-TEST-TYPE` không có cấu trúc thư mục mẫu
 *   (`KHO-TAI-LIEU.md` mục 3e) → sau thao tác, bảng Cấu trúc hồ sơ phải có **đúng 2 dòng**.
 */
import { Locator, Page } from "@playwright/test";
import { test, expect, ACCOUNT } from "../../src/fixture/base-test";
import { TIMEOUT } from "../../src/constant/timeout";
import { PW } from "../../src/utils/PW";
import {
  DOC_PERM,
  THU_MUC_FIELD,
  createBoHoSo,
  chuyenHoatDong,
  openBoHoSo,
  openTabCauTrucHoSo,
  openModalThemThuMuc,
  luuModalThuMuc,
  pickFirstOption,
  getActiveTabPane,
  getCauTrucRow,
} from "../../src/screen-instructions/KHO-TAI-LIEU.functions";

/** 1 người tham gia thao tác đồng thời: phiên browser riêng + thư mục người đó sẽ tạo */
type NguoiThamGia = {
  /** Fixture (phiên đăng nhập) của người này */
  page: Page;
  /** Account id — người **đầu tiên** là người tạo BHS, những người sau được cấp Owner ở BHS */
  account: string;
  /** Nhãn ngắn để đặt tên thư mục + đọc log, vd `"TT"`, `"AD"` */
  ma: string;
  /** Tên thư mục người này sẽ tạo (gán trong `runTest`) */
  tenThuMuc: string;
  /** Modal "Thêm thư mục" đã chuẩn bị xong dữ liệu, chờ bấm Xác nhận */
  modal?: Locator;
};

/**
 * Mở modal "Thêm thư mục" ở gốc BHS và **điền đủ dữ liệu bắt buộc nhưng KHÔNG lưu**.
 *
 * Điền đúng những trường mà `createThuMuc` điền (Tên + Đơn vị soạn thảo — trường bắt buộc tuỳ
 * cấu hình Cấu trúc hồ sơ, xem `KHO-TAI-LIEU.MODAL-TAO-THU-MUC.md` mục 5); Độ mật / Trạng thái
 * hiển thị để mặc định kế thừa từ BHS.
 */
const chuanBiDuLieuTaoThuMuc = async (
  page: Page,
  recordUrl: string,
  tenThuMuc: string,
): Promise<Locator> => {
  const modal = await openModalThemThuMuc(page, recordUrl);

  await modal.getByTestId(THU_MUC_FIELD.TEN).fill(tenThuMuc);

  // Field metadata có thể bị ẩn tuỳ cấu hình Cấu trúc hồ sơ → luôn guard isVisible (mục 3a)
  const donViSoanThao = modal.getByTestId(THU_MUC_FIELD.DON_VI_SOAN_THAO);
  if (await donViSoanThao.isVisible().catch(() => false)) {
    await pickFirstOption(page, donViSoanThao);
  }

  await expect(modal.getByTestId(THU_MUC_FIELD.TEN), {
    message: `Lỗi: modal "Thêm thư mục" chưa nhận tên "${tenThuMuc}" trước khi bấm lưu`,
  }).toHaveValue(tenThuMuc, { timeout: TIMEOUT.VALIDATE_WAITING });

  return modal;
};

/**
 * Mong muốn: trên phiên của `page`, bảng Cấu trúc hồ sơ có **đủ và đúng** các thư mục vừa tạo.
 *
 * - Mỗi tên xuất hiện **đúng 1 dòng** (không mất, không nhân đôi).
 * - Bảng có **đúng `tenThuMucs.length` dòng** — BHS dựng mới, không có cấu trúc mẫu.
 * - **Không** assert mã prefix (chỉ mục) của từng thư mục: 2 thư mục tạo cùng thời điểm nên thứ tự
 *   `A`/`B` là ngẫu nhiên (yêu cầu của người dùng).
 */
const expectDayDuThuMuc = async (
  page: Page,
  recordUrl: string,
  tenThuMucs: string[],
) => {
  await openBoHoSo(page, recordUrl);
  await openTabCauTrucHoSo(page);

  for (const ten of tenThuMucs) {
    const row = getCauTrucRow(page, ten);
    await expect(row, {
      message: `Lỗi: không thấy thư mục "${ten}" trong bảng Cấu trúc hồ sơ sau khi 2 người cùng lưu`,
    }).toBeVisible({ timeout: TIMEOUT.DATA_LOADING });

    // Tên hiển thị có dạng "<mã prefix>. <tên>" — chỉ kiểm tên, bỏ qua mã prefix
    await expect(row.locator('[data-testid^="lnk-ten-ho-so-tai-lieu-"]').first(), {
      message: `Lỗi: dòng của thư mục "${ten}" hiển thị sai tên`,
    }).toContainText(ten, { timeout: TIMEOUT.CONTROL_LOADING });

    await expect(
      getActiveTabPane(page)
        .locator(".ant-table-tbody tr.ant-table-row")
        .filter({ hasText: ten }),
      {
        message: `Lỗi: thư mục "${ten}" bị tạo trùng (nhiều hơn 1 dòng) trong bảng Cấu trúc hồ sơ`,
      },
    ).toHaveCount(1, { timeout: TIMEOUT.DATA_LOADING });
  }

  await expect(
    getActiveTabPane(page).locator(".ant-table-tbody tr.ant-table-row"),
    {
      message:
        `Lỗi: bảng Cấu trúc hồ sơ không có đúng ${tenThuMucs.length} thư mục ` +
        `(chỉ 2 thư mục do 2 người vừa tạo, BHS không có cấu trúc mẫu)`,
    },
  ).toHaveCount(tenThuMucs.length, { timeout: TIMEOUT.DATA_LOADING });
};

/**
 * @param nguoiThamGia danh sách người thao tác đồng thời — phần tử **đầu tiên** là người tạo BHS,
 *   các phần tử sau được cấp **Quyền Owner ở BHS** ngay lúc tạo.
 */
const runTest = async (maCase: string, nguoiThamGia: NguoiThamGia[]) => {
  const nguoiTaoBHS = nguoiThamGia[0];
  const goc = `AT-UC22-${maCase}-${Date.now()}`;
  for (const n of nguoiThamGia) n.tenThuMuc = `${goc}-TM-${n.ma}`;

  let recordUrl = "";

  await test.step(
    `Tiền điều kiện: ${nguoiTaoBHS.account} tạo BHS "${goc}" (cấp Owner cho ` +
      `${nguoiThamGia
        .slice(1)
        .map((n) => n.account)
        .join(", ")}) → chuyển "Hoạt động"`,
    async () => {
      recordUrl = await createBoHoSo(
        nguoiTaoBHS.page,
        new PW(nguoiTaoBHS.page),
        goc,
        {
          peoplePickers: nguoiThamGia.slice(1).map((n) => ({
            testId: DOC_PERM.OWNER,
            account: n.account,
          })),
        },
      );

      // Vai không phải người tạo BHS chỉ mở được BHS ở trạng thái "Hoạt động"
      await chuyenHoatDong(nguoiTaoBHS.page, recordUrl);
    },
  );

  await test.step(
    `Thao tác 1: ${nguoiThamGia.length} trình duyệt cùng mở modal "Thêm thư mục" và chuẩn bị ` +
      `đầy đủ dữ liệu (${nguoiThamGia.map((n) => n.tenThuMuc).join(", ")}) — chưa lưu`,
    async () => {
      const modals = await Promise.all(
        nguoiThamGia.map((n) =>
          chuanBiDuLieuTaoThuMuc(n.page, recordUrl, n.tenThuMuc),
        ),
      );
      nguoiThamGia.forEach((n, i) => (n.modal = modals[i]));
    },
  );

  await test.step(
    `Thao tác 2: ${nguoiThamGia.length} trình duyệt bấm "Xác nhận" CÙNG LÚC → mỗi phiên đều phải ` +
      `nhận toast "Thành công"`,
    async () => {
      // Promise.all: các lệnh click được phát đi trong cùng 1 tick, không chờ nhau
      await Promise.all(
        nguoiThamGia.map((n) =>
          luuModalThuMuc(
            n.page,
            n.modal,
            `Tạo thư mục ${n.tenThuMuc} (${n.account})`,
          ),
        ),
      );
    },
  );

  await test.step(
    `Mong muốn: cả ${nguoiThamGia.length} thư mục đều được tạo chính xác và mọi phiên đều thấy ` +
      `đủ (không xét chỉ mục)`,
    async () => {
      const tenThuMucs = nguoiThamGia.map((n) => n.tenThuMuc);
      await Promise.all(
        nguoiThamGia.map((n) =>
          expectDayDuThuMuc(n.page, recordUrl, tenThuMucs),
        ),
      );
    },
  );
};

test(
  "UC22 249 - 2 người cùng tạo mới thư mục tại cùng một thời điểm (tên khác nhau) - Thủ thư + Admin" +
    ACCOUNT.LIBRARIAN +
    ACCOUNT.ADMIN,
  async ({ librarian, admin }) => {
    await runTest("249", [
      { page: librarian, account: ACCOUNT.LIBRARIAN, ma: "TT", tenThuMuc: "" },
      { page: admin, account: ACCOUNT.ADMIN, ma: "AD", tenThuMuc: "" },
    ]);
  },
);
