import { Page } from "@playwright/test";
import { test, expect } from "../../src/fixture/base-test";
import { TIMEOUT } from "../../src/constant/timeout";
import {
  getCauTrucRow,
  layTenCacDongCauTruc,
  openBoHoSo,
  openTabCauTrucHoSo,
  xoaItemCauTruc,
  XOA_CONFIRM,
} from "../../src/screen-instructions/KHO-TAI-LIEU.functions";
import { DuLieuXoaThuMuc, ThuMucCoTaiLieu } from "./1.4.7.setup";

/**
 * Chuỗi bước dùng chung cho bộ case **1.4.7 — Xóa thư mục / tài liệu trong Cấu trúc hồ sơ**.
 * Tiền điều kiện chung của mục: xem [`1.4.7.md`](./1.4.7.md).
 */

/**
 * **Thao tác**: mở BHS bằng `userPage` → tab "Cấu trúc hồ sơ" → xoá thư mục `tm.tenThuMuc`
 * (đang có tài liệu `tm.tenTaiLieu` bên trong) → **mong muốn**: mất cả thư mục và tài liệu bên trong.
 *
 * Trình tự bên trong:
 * 1. Assert **tiền đề của case** — thấy cả dòng thư mục **và** dòng tài liệu bên trong. Không có
 *    tài liệu bên trong thì app hiện dialog xoá loại khác (`XOA_CONFIRM.RONG`) → case mất ý nghĩa.
 * 2. `xoaItemCauTruc` với `noiDungMongDoi = XOA_CONFIRM.CO_DU_LIEU_BEN_TRONG`: nội dung dialog lệch
 *    mong đợi thì báo bằng **`expect.soft`** (test vẫn fail ở cuối) nhưng **vẫn bấm xác nhận xoá** —
 *    đúng yêu cầu "cảnh báo nhưng thực hiện xóa tiếp".
 * 3. Assert **ngay trên bảng đang mở** rằng cả 2 dòng đã biến mất.
 *
 * 🚨 Cố ý **không mở lại BHS** để assert: vai chỉ có quyền tại đúng thư mục vừa xoá (vd Owner của
 * 1 thư mục) sau khi xoá **không còn quyền nào trong BHS** → mở lại có thể bị chặn với toast
 * `"Bạn không có quyền xem!"` (`PHAN-QUYEN-THEO-VAI.md` mục 1) và đó không phải lỗi của thao tác xoá.
 * Việc kiểm chứng "đã xoá thật, đã ghi xuống server" do
 * {@link expectDaXoaHetThuMucVaTaiLieu} làm bằng phiên **người tạo BHS**.
 *
 * @param moTaVai Mô tả vai đang thao tác, chỉ dùng cho tên `test.step` + message lỗi
 *   (vd `"admin (người tạo BHS)"`).
 */
export const xoaThuMucCoTaiLieuBenTrong = async (
  userPage: Page,
  duLieu: DuLieuXoaThuMuc,
  tm: ThuMucCoTaiLieu,
  moTaVai: string,
) => {
  await test.step(`Thao tác: ${moTaVai} xóa thư mục "${tm.tenThuMuc}" (có tài liệu "${tm.tenTaiLieu}" bên trong)`, async () => {
    await openBoHoSo(userPage, duLieu.recordUrl);
    await openTabCauTrucHoSo(userPage);

    // --- tiền đề: thư mục đang có tài liệu bên trong ---
    await expect(getCauTrucRow(userPage, tm.tenThuMuc), {
      message: `Lỗi: ${moTaVai} không thấy thư mục "${tm.tenThuMuc}" trong bảng Cấu trúc hồ sơ`,
    }).toBeVisible({ timeout: TIMEOUT.DATA_LOADING });
    await expect(getCauTrucRow(userPage, tm.tenTaiLieu), {
      message:
        `Lỗi: không thấy tài liệu "${tm.tenTaiLieu}" bên trong thư mục "${tm.tenThuMuc}" → ` +
        "không kiểm chứng được việc xóa thư mục CÓ dữ liệu bên trong",
    }).toBeVisible({ timeout: TIMEOUT.DATA_LOADING });

    // --- xoá + kiểm tra nội dung dialog cảnh báo ---
    await xoaItemCauTruc(userPage, tm.tenThuMuc, {
      noiDungMongDoi: XOA_CONFIRM.CO_DU_LIEU_BEN_TRONG,
    });

    // --- mong muốn: mất cả thư mục và tài liệu bên trong (bảng tự refresh sau khi xoá) ---
    await expect(getCauTrucRow(userPage, tm.tenThuMuc), {
      message: `Lỗi: xóa xong nhưng thư mục "${tm.tenThuMuc}" vẫn còn trong bảng Cấu trúc hồ sơ`,
    }).toHaveCount(0, { timeout: TIMEOUT.DATA_LOADING });
    await expect(getCauTrucRow(userPage, tm.tenTaiLieu), {
      message:
        `Lỗi: xóa thư mục "${tm.tenThuMuc}" nhưng tài liệu "${tm.tenTaiLieu}" bên trong vẫn còn ` +
        "trong bảng Cấu trúc hồ sơ",
    }).toHaveCount(0, { timeout: TIMEOUT.DATA_LOADING });
  });
};

/**
 * **Thao tác**: mở BHS bằng `userPage` → tab "Cấu trúc hồ sơ" → xoá **1 tài liệu** (`tenTaiLieu`)
 * → **mong muốn**: mất dòng tài liệu đó, thư mục chứa nó (nếu có) **vẫn còn**.
 *
 * Trình tự bên trong:
 * 1. Assert thấy dòng tài liệu (và dòng thư mục chứa nó, nếu truyền `opts.tenThuMucChua`).
 * 2. `xoaItemCauTruc` với `noiDungMongDoi = XOA_CONFIRM.RONG` — tài liệu là item **rỗng** nên app
 *    dùng dialog `"Bạn có chắc chắn muốn xóa?"` với nút theo nhãn `Xác nhận` (`KHO-TAI-LIEU.md`
 *    mục 4.4), khác dialog cảnh báo xoá lan xuống của thư mục có dữ liệu bên trong. Nội dung lệch
 *    mong đợi → `expect.soft` cảnh báo nhưng **vẫn xoá tiếp**.
 * 3. Assert **ngay trên bảng đang mở**: dòng tài liệu biến mất, thư mục chứa nó còn nguyên
 *    (xoá tài liệu **không** được xoá theo thư mục cha).
 *
 * 🚨 Cố ý **không mở lại BHS** để assert — cùng lý do như {@link xoaThuMucCoTaiLieuBenTrong}: vai chỉ
 * có quyền tại đúng item vừa xoá (vd Owner của 1 tài liệu ở gốc BHS) sau khi xoá **không còn quyền
 * nào trong BHS** → mở lại có thể bị chặn với toast `"Bạn không có quyền xem!"`
 * (`PHAN-QUYEN-THEO-VAI.md` mục 1), và đó không phải lỗi của thao tác xoá. Việc kiểm chứng "đã xoá
 * thật, đã ghi xuống server" do {@link expectDaXoaTaiLieu} làm bằng phiên **người tạo BHS**.
 *
 * @param moTaVai Mô tả vai đang thao tác, chỉ dùng cho tên `test.step` + message lỗi.
 * @param opts.tenThuMucChua Tên thư mục chứa tài liệu — truyền vào thì hàm assert thư mục này
 *   **còn nguyên** sau khi xoá. Bỏ trống với tài liệu nằm ở gốc BHS.
 */
export const xoaTaiLieuTrongCauTruc = async (
  userPage: Page,
  duLieu: DuLieuXoaThuMuc,
  tenTaiLieu: string,
  moTaVai: string,
  opts: { tenThuMucChua?: string } = {},
) => {
  const viTri = opts.tenThuMucChua
    ? `bên trong thư mục "${opts.tenThuMucChua}"`
    : "ở gốc bộ hồ sơ";

  await test.step(`Thao tác: ${moTaVai} xóa tài liệu "${tenTaiLieu}" (${viTri})`, async () => {
    await openBoHoSo(userPage, duLieu.recordUrl);
    await openTabCauTrucHoSo(userPage);

    // --- tiền đề: thấy tài liệu cần xoá (và thư mục chứa nó) ---
    await expect(getCauTrucRow(userPage, tenTaiLieu), {
      message: `Lỗi: ${moTaVai} không thấy tài liệu "${tenTaiLieu}" trong bảng Cấu trúc hồ sơ`,
    }).toBeVisible({ timeout: TIMEOUT.DATA_LOADING });
    if (opts.tenThuMucChua) {
      await expect(getCauTrucRow(userPage, opts.tenThuMucChua), {
        message: `Lỗi: ${moTaVai} không thấy thư mục "${opts.tenThuMucChua}" chứa tài liệu "${tenTaiLieu}"`,
      }).toBeVisible({ timeout: TIMEOUT.DATA_LOADING });
    }

    // --- xoá + kiểm tra nội dung dialog xác nhận ---
    await xoaItemCauTruc(userPage, tenTaiLieu, {
      noiDungMongDoi: XOA_CONFIRM.RONG,
    });

    // --- mong muốn: mất tài liệu, thư mục chứa nó còn nguyên (bảng tự refresh sau khi xoá) ---
    await expect(getCauTrucRow(userPage, tenTaiLieu), {
      message: `Lỗi: xóa xong nhưng tài liệu "${tenTaiLieu}" vẫn còn trong bảng Cấu trúc hồ sơ`,
    }).toHaveCount(0, { timeout: TIMEOUT.DATA_LOADING });
    if (opts.tenThuMucChua) {
      await expect(getCauTrucRow(userPage, opts.tenThuMucChua), {
        message:
          `Lỗi: xóa tài liệu "${tenTaiLieu}" nhưng thư mục chứa nó ` +
          `"${opts.tenThuMucChua}" cũng biến mất khỏi bảng Cấu trúc hồ sơ`,
      }).toBeVisible({ timeout: TIMEOUT.DATA_LOADING });
    }
  });
};

/**
 * **Mong muốn (kiểm chứng cuối)**: mở lại BHS bằng phiên **người tạo BHS** (thấy được toàn bộ cấu
 * trúc) → các item trong `opts.canMatHet` **không còn** dòng nào trong bảng Cấu trúc hồ sơ, còn các
 * item trong `opts.canConLai` thì **vẫn còn nguyên**.
 *
 * Vì sao cần thêm bước này dù mỗi lần xoá đã assert tại chỗ: assert tại chỗ đọc bảng **của vai vừa
 * xoá** — bảng đó đã bị app lọc theo quyền (`PHAN-QUYEN-THEO-VAI.md` mục 3), nên "không thấy dòng"
 * chưa tách được **đã xoá** với **mất quyền xem**. Mở lại bằng người tạo BHS thì phân biệt được, và
 * đồng thời chứng minh dữ liệu đã ghi xuống server chứ không chỉ đổi trên UI.
 *
 * @param opts.canMatHet  Tên các item **phải mất** khỏi bảng (vd các tài liệu đã xoá).
 * @param opts.canConLai  Tên các item **phải còn** trong bảng (vd các thư mục chứa tài liệu đã xoá).
 */
export const expectDaXoaTaiLieu = async (
  nguoiTaoBoHoSo: Page,
  duLieu: DuLieuXoaThuMuc,
  opts: { canMatHet: string[]; canConLai?: string[] },
) => {
  await test.step("Mong muốn: mở lại BHS bằng người tạo — các tài liệu đã xóa không còn, thư mục còn nguyên", async () => {
    await openBoHoSo(nguoiTaoBoHoSo, duLieu.recordUrl);
    await openTabCauTrucHoSo(nguoiTaoBoHoSo);

    const tenCacDong = await layTenCacDongCauTruc(nguoiTaoBoHoSo);
    const coTrongBang = (ten: string) =>
      tenCacDong.some((dong) => dong.includes(ten));

    const conSot = opts.canMatHet.filter(coTrongBang);
    expect(conSot, {
      message:
        `Lỗi: các item lẽ ra đã bị xóa nhưng vẫn còn trong bảng Cấu trúc hồ sơ: ` +
        `[${conSot.join(" | ")}]. Các dòng đang có: [${tenCacDong.join(" | ")}]`,
    }).toHaveLength(0);

    const biMat = (opts.canConLai ?? []).filter((ten) => !coTrongBang(ten));
    expect(biMat, {
      message:
        `Lỗi: các item lẽ ra vẫn còn nhưng đã biến mất khỏi bảng Cấu trúc hồ sơ: ` +
        `[${biMat.join(" | ")}]. Các dòng đang có: [${tenCacDong.join(" | ")}]`,
    }).toHaveLength(0);
  });
};

/**
 * **Mong muốn (kiểm chứng cuối)**: mở lại BHS bằng phiên **người tạo BHS** (thấy được toàn bộ cấu
 * trúc) → bảng Cấu trúc hồ sơ **không còn** thư mục nào và tài liệu nào trong danh sách `thuMuc`.
 *
 * Vì sao cần thêm bước này dù mỗi lần xoá đã assert tại chỗ: assert tại chỗ đọc bảng **của vai vừa
 * xoá** — bảng đó đã bị app lọc theo quyền (`PHAN-QUYEN-THEO-VAI.md` mục 3), nên "không thấy dòng"
 * chưa tách được **đã xoá** với **mất quyền xem**. Mở lại bằng người tạo BHS thì phân biệt được, và
 * đồng thời chứng minh dữ liệu đã ghi xuống server chứ không chỉ đổi trên UI.
 */
export const expectDaXoaHetThuMucVaTaiLieu = async (
  nguoiTaoBoHoSo: Page,
  duLieu: DuLieuXoaThuMuc,
) => {
  await test.step("Mong muốn: mở lại BHS bằng người tạo — không còn thư mục / tài liệu nào đã xóa", async () => {
    await openBoHoSo(nguoiTaoBoHoSo, duLieu.recordUrl);
    await openTabCauTrucHoSo(nguoiTaoBoHoSo);

    const tenCacDong = await layTenCacDongCauTruc(nguoiTaoBoHoSo);
    const canMatHet = duLieu.thuMuc.flatMap((tm) => [
      tm.tenThuMuc,
      tm.tenTaiLieu,
    ]);
    const conSot = canMatHet.filter((ten) =>
      tenCacDong.some((dong) => dong.includes(ten)),
    );

    expect(conSot, {
      message:
        `Lỗi: sau khi xóa 4 thư mục, bảng Cấu trúc hồ sơ vẫn còn: [${conSot.join(" | ")}]. ` +
        `Các dòng đang có: [${tenCacDong.join(" | ")}]`,
    }).toHaveLength(0);
  });
};
