import { Page } from "@playwright/test";
import { test, expect, ACCOUNT } from "../../src/fixture/base-test";
import { PW } from "../../src/utils/PW";
import {
  createBoHoSo,
  createTaiLieu,
  openBoHoSo,
  openTabCauTrucHoSo,
  layTenCacDongCauTruc,
  xoaItemCauTruc,
  XOA_CONFIRM,
  openQuanLyCauTrucDaXoa,
  layDanhSachCauTrucDaXoa,
  khoiPhucCauTrucDaXoa,
  dongModalCauTrucDaXoa,
  EMPTY_CAU_TRUC_DA_XOA,
} from "../../src/screen-instructions/KHO-TAI-LIEU.functions";

/**
 * UC?? — 1.4.16.917
 * **Khôi phục thành công 01 tài liệu đơn lẻ về đúng vị trí cũ**
 *
 * Thao tác (nguyên văn):
 * 1. Tạo 1 bộ hồ sơ và 1 tài liệu
 * 2. Xóa tài liệu và khôi phục tài liệu, thành công là oke
 *
 * **Tiền điều kiện chung của mục** (vai → cách dựng dữ liệu): [`1.4.16.md`](./1.4.16.md).
 * Toàn bộ logic / kỳ vọng / giả định của case này nằm trong khối comment dưới đây.
 *
 * ---
 *
 * ## Cách case này được viết
 *
 * - **Dựng dữ liệu viết thẳng trong spec, không tách `setup.ts` / `steps.ts`**: mục 1.4.16 hiện chỉ
 *   có đúng case này dùng tới, mà việc dựng chỉ gồm 2 lời gọi hàm có sẵn (`createBoHoSo` +
 *   `createTaiLieu`). Có case thứ hai dùng lại thì mới tách ra file dùng chung.
 * - **Tài liệu đặt ở GỐC BHS, không nằm trong thư mục**: mô tả chỉ yêu cầu "1 bộ hồ sơ và 1 tài
 *   liệu". Để ở gốc còn giúp phép so "đúng vị trí cũ" gọn: cây chỉ có 1 dòng nên so được **nguyên
 *   danh sách dòng** trước/sau, gồm cả **mã prefix** (`"A. <tên tài liệu>"`).
 * - **"Đúng vị trí cũ" được đo bằng cách so nguyên danh sách hiển thị của bảng Cấu trúc hồ sơ**
 *   (`layTenCacDongCauTruc`) chụp **trước khi xóa** với danh sách **sau khi khôi phục**. Chuỗi hiển
 *   thị đã bao gồm mã prefix do hệ thống sinh → khôi phục mà đổi vị trí / đổi mã thì assert này
 *   fail. Khảo sát MCP 2026-08-14 cho thấy app trả item về đúng mã cũ, nên đây là kỳ vọng hợp lý.
 * - **Không assert toast lúc khôi phục**: app **không bắn toast** và **không hỏi xác nhận** khi bấm
 *   "Khôi phục" (đo bằng MutationObserver rình `.ant-message-notice` từ trước lúc bấm —
 *   `KHO-TAI-LIEU.MODAL-KHOI-PHUC-CAU-TRUC-DA-XOA.md` mục 3). Tín hiệu "thành công" là **modal tự
 *   đóng** (do `khoiPhucCauTrucDaXoa` assert) + **dòng xuất hiện lại trong bảng**.
 * - **Bước xóa vẫn assert nội dung dialog** (`XOA_CONFIRM.RONG` — tài liệu là item rỗng): xóa là
 *   tiền đề của case, dialog sai loại nghĩa là app đang xử lý khác mong đợi. Lệch nội dung →
 *   `expect.soft` cảnh báo nhưng **vẫn xóa tiếp** để phần khôi phục vẫn được kiểm tra.
 * - **Kiểm chứng 3 lớp sau khi khôi phục**, vì mỗi lớp bắt một loại lỗi khác nhau:
 *   1. Bảng Cấu trúc hồ sơ (bảng tự refresh, không mở lại BHS) — bắt lỗi "app không khôi phục".
 *   2. **Mở lại BHS bằng `openBoHoSo`** rồi đọc lại bảng — bắt lỗi "chỉ đúng trên UI, chưa ghi
 *      xuống server"; đây cũng là bước reset SPA đúng cách (`KHO-TAI-LIEU.md` mục 4.0).
 *   3. Danh sách "Quản lý cấu trúc đã xóa" phải **rỗng** — bắt lỗi "khôi phục nhưng vẫn còn nằm
 *      trong thùng rác" (khảo sát 2026-08-14: dòng đã khôi phục biến mất khỏi danh sách).
 * - **Người thao tác chính là người tạo BHS** nên **không cần `chuyenHoatDong`**: BHS để nguyên
 *   trạng thái `Khai báo`, đúng ràng buộc 1 trong `1.4.16.md`.
 * - **2 test (Thủ thư + Admin)** theo quy ước tối thiểu của dự án (`tests/README.md` mục 6.4).
 *   Mỗi test tự dựng BHS riêng theo `Date.now()` nên chạy song song được.
 *
 * ## Điểm cần QA/DEV chốt
 *
 * 1. **Mã UC** của mục 1.4.16 — đang ghi `UC??`.
 * 2. Case chỉ phủ **tài liệu ở gốc BHS**. Tài liệu **nằm trong thư mục** thì cột "Vị trí" của modal
 *    khôi phục hiển thị gì, và khôi phục có về đúng thư mục cũ không — **chưa khảo sát**
 *    (`KHO-TAI-LIEU.MODAL-KHOI-PHUC-CAU-TRUC-DA-XOA.md` mục 2) → nếu QA cần thì là **case riêng**.
 * 3. Case **không** phủ: khôi phục nhiều item cùng lúc (checkbox "chọn tất cả" ở header bảng chưa
 *    khảo sát), khôi phục **thư mục có dữ liệu bên trong**, và khôi phục bằng vai **không phải người
 *    tạo BHS**. Mỗi hướng là 1 case riêng.
 * 4. Tài liệu ở case này **không có file mềm đính kèm** — chưa rõ file đính kèm có được khôi phục
 *    theo hay không (màn "Quản lý file đã xóa" của tài liệu là chức năng khác, chưa khảo sát).
 */

const runTest = async (page: Page) => {
  const pw = new PW(page);
  const ts = Date.now();
  const tenHoSo = `AT-1.4.16-917-${ts}`;
  const tenTaiLieu = `AT-1.4.16-917-${ts}-TL1`;

  // --- Thao tác 1: tạo 1 bộ hồ sơ + 1 tài liệu ở gốc BHS ---
  const recordUrl = await test.step("Tạo bộ hồ sơ và 1 tài liệu", async () => {
    const url = await createBoHoSo(page, pw, tenHoSo);
    await createTaiLieu(page, pw, url, tenTaiLieu);
    return url;
  });

  // --- Ghi nhận vị trí cũ của tài liệu trong cây cấu trúc ---
  const { danhSachTruocKhiXoa, dongTaiLieu } = await test.step(
    "Ghi nhận vị trí tài liệu trước khi xóa",
    async () => {
      await openTabCauTrucHoSo(page);
      const danhSach = await layTenCacDongCauTruc(page);
      const dong = danhSach.find((t) => t.includes(tenTaiLieu));
      expect(dong, {
        message:
          `Lỗi dựng dữ liệu: không thấy tài liệu "${tenTaiLieu}" trong bảng Cấu trúc hồ sơ. ` +
          `Đang có: [${danhSach.join(" | ") || "không có dòng nào"}]`,
      }).toBeTruthy();
      return { danhSachTruocKhiXoa: danhSach, dongTaiLieu: dong! };
    },
  );

  // --- Thao tác 2a: xóa tài liệu ---
  await test.step("Xóa tài liệu", async () => {
    await xoaItemCauTruc(page, tenTaiLieu, {
      noiDungMongDoi: XOA_CONFIRM.RONG,
    });

    const sauKhiXoa = await layTenCacDongCauTruc(page);
    expect(sauKhiXoa, {
      message: `Lỗi: đã xác nhận xóa nhưng tài liệu "${tenTaiLieu}" vẫn còn trong bảng Cấu trúc hồ sơ`,
    }).not.toContain(dongTaiLieu);
  });

  // --- Thao tác 2b: khôi phục tài liệu từ "Quản lý cấu trúc đã xóa" ---
  await test.step("Khôi phục tài liệu", async () => {
    const modal = await openQuanLyCauTrucDaXoa(page);

    const daXoa = await layDanhSachCauTrucDaXoa(page, modal);
    expect(daXoa.map((d) => d.ten), {
      message: `Lỗi: tài liệu "${tenTaiLieu}" vừa xóa nhưng không có trong danh sách "Quản lý cấu trúc đã xóa"`,
    }).toContain(tenTaiLieu);

    await khoiPhucCauTrucDaXoa(page, tenTaiLieu, { moModal: false });
  });

  // --- Kỳ vọng: tài liệu về lại cây cấu trúc, đúng vị trí cũ ---
  await test.step("Tài liệu trở lại đúng vị trí cũ", async () => {
    // 1. Bảng tự refresh ngay sau khi khôi phục (không mở lại BHS)
    const sauKhiKhoiPhuc = await layTenCacDongCauTruc(page);
    expect(sauKhiKhoiPhuc, {
      message:
        `Lỗi: sau khi khôi phục, bảng Cấu trúc hồ sơ không giống trước khi xóa.\n` +
        `  trước khi xóa: [${danhSachTruocKhiXoa.join(" | ")}]\n` +
        `  sau khôi phục: [${sauKhiKhoiPhuc.join(" | ")}]`,
    }).toEqual(danhSachTruocKhiXoa);

    // 2. Mở lại BHS (reset SPA) — chắc chắn dữ liệu đã ghi xuống server, không chỉ đúng trên UI
    await openBoHoSo(page, recordUrl);
    await openTabCauTrucHoSo(page);
    const sauKhiMoLai = await layTenCacDongCauTruc(page);
    expect(sauKhiMoLai, {
      message:
        `Lỗi: mở lại BHS thì bảng Cấu trúc hồ sơ không giống trước khi xóa.\n` +
        `  trước khi xóa: [${danhSachTruocKhiXoa.join(" | ")}]\n` +
        `  sau mở lại:    [${sauKhiMoLai.join(" | ")}]`,
    }).toEqual(danhSachTruocKhiXoa);
  });

  // --- Kỳ vọng: item đã khôi phục không còn trong danh sách đã xóa ---
  await test.step('Danh sách "Quản lý cấu trúc đã xóa" không còn tài liệu', async () => {
    const modal = await openQuanLyCauTrucDaXoa(page);
    const conLai = await layDanhSachCauTrucDaXoa(page, modal);
    expect(conLai.map((d) => d.ten), {
      message: `Lỗi: đã khôi phục nhưng tài liệu "${tenTaiLieu}" vẫn nằm trong danh sách "Quản lý cấu trúc đã xóa"`,
    }).not.toContain(tenTaiLieu);
    expect(conLai.length, {
      message:
        `Lỗi: danh sách "Quản lý cấu trúc đã xóa" của BHS phải rỗng (${EMPTY_CAU_TRUC_DA_XOA}) ` +
        `nhưng đang có: [${conLai.map((d) => d.ten).join(" | ")}]`,
    }).toBe(0);

    await dongModalCauTrucDaXoa(page, modal);
  });
};

test(
  "UC?? 1.4.16.917 - Khôi phục thành công 01 tài liệu đơn lẻ về đúng vị trí cũ - Thủ thư" +
    ACCOUNT.LIBRARIAN,
  async ({ librarian }) => {
    await runTest(librarian);
  },
);

test(
  "UC?? 1.4.16.917 - Khôi phục thành công 01 tài liệu đơn lẻ về đúng vị trí cũ - Admin" +
    ACCOUNT.ADMIN,
  async ({ admin }) => {
    await runTest(admin);
  },
);
