import path from "path";
import ExcelJS from "exceljs";
import { Page } from "@playwright/test";
import { test, expect } from "../../src/fixture/base-test";
import { TIMEOUT } from "../../src/constant/timeout";
import {
  getActiveTabPane,
  layTenCacDongCauTrucMoiTrang,
  moRongToanBoCayCauTruc,
  nhapCauTrucTuExcel,
  openBoHoSo,
  openTabCauTrucHoSo,
} from "../../src/screen-instructions/KHO-TAI-LIEU.functions";
import { DuLieuNhapExcel } from "./1.4.8.setup";

/**
 * Chuỗi bước dùng chung cho bộ case **1.4.8 — Nhập cấu trúc hồ sơ từ file Excel**.
 * Tiền điều kiện chung của mục: xem [`1.4.8.md`](./1.4.8.md).
 */

/** 1 dòng dữ liệu trong file Excel mẫu (chỉ giữ 3 cột hiển thị được ở bảng Cấu trúc hồ sơ) */
export type ItemTemplate = {
  /** Cột `code` — chỉ mục, vd `"A"`, `"A.1"`, `"A.1.2.1"` */
  ma: string;
  /** Cột `title` — tên thư mục / tài liệu */
  ten: string;
  /** Cột `type` — `"Thư mục"` | `"Tài liệu"` */
  loai: "Thư mục" | "Tài liệu";
};

/** Dòng đầu tiên chứa **dữ liệu thật** trong template (1 = tên cột kỹ thuật, 2 = nhãn, 3 = hướng dẫn) */
const DONG_DU_LIEU_DAU_TIEN = 4;

/**
 * Đọc file Excel mẫu → danh sách thư mục / tài liệu **khai báo trong file**.
 *
 * ⚠️ Đây **không** phải danh sách kỳ vọng: file mẫu có thể chứa **dòng lỗi cố ý** nên app bỏ qua vài
 * dòng vẫn đúng. Danh sách này chỉ dùng để **ghi log** đối chiếu trong
 * {@link expectCoThemThuMucMoi} (file khai báo bao nhiêu / bảng tạo được bao nhiêu).
 * Đọc thẳng từ file thay vì hard-code để sửa template không phải sửa code.
 *
 * Cấu trúc template (`src/template-files/template3A.xlsx`, `Sheet1`) — 3 dòng đầu là mô tả:
 * | dòng | nội dung                                              |
 * | ---- | ----------------------------------------------------- |
 * | 1    | tên cột kỹ thuật (`code`, `title`, `type`…)           |
 * | 2    | nhãn tiếng Việt (`Chỉ mục (index)`, `Tên`, `Loại`…)   |
 * | 3    | hướng dẫn nhập ("Bắt buộc"…)                          |
 * | 4+   | **dữ liệu thật**                                       |
 *
 * Hàm chỉ lấy 3 cột đầu (`code`, `title`, `type`) — các cột còn lại là thuộc tính của tài liệu,
 * không hiển thị ở bảng Cấu trúc hồ sơ nên không đọc.
 */
export const docCauTrucTuTemplate = async (
  duongDanFile: string,
): Promise<ItemTemplate[]> => {
  const wb = new ExcelJS.Workbook();
  await wb.xlsx.readFile(duongDanFile);

  const ws = wb.worksheets[0];
  expect(ws, {
    message: `Lỗi: file template "${path.basename(duongDanFile)}" không có sheet nào`,
  }).toBeTruthy();

  const items: ItemTemplate[] = [];
  ws.eachRow({ includeEmpty: false }, (row, soDong) => {
    if (soDong < DONG_DU_LIEU_DAU_TIEN) return;
    const ma = row.getCell(1).text?.trim() ?? "";
    const ten = row.getCell(2).text?.trim() ?? "";
    const loai = row.getCell(3).text?.trim() ?? "";
    if (!ma || !ten) return;
    if (loai !== "Thư mục" && loai !== "Tài liệu") return;
    items.push({ ma, ten, loai });
  });

  expect(items.length, {
    message: `Lỗi: không đọc được dòng dữ liệu nào từ template "${path.basename(duongDanFile)}"`,
  }).toBeGreaterThan(0);

  return items;
};

/**
 * **Thao tác**: mở BHS → tab "Cấu trúc hồ sơ" → menu `"..."` → "Nhập excel" → chọn `duongDanFile`
 * → "Tiếp theo" → "Cập nhật" → bấm "Tiếp tục" nếu app bật thêm modal xác nhận → chờ toast
 * `"Tạo mới thành công"`.
 *
 * Toàn bộ phần thao tác trong modal do {@link nhapCauTrucTuExcel} làm (🚨 modal đó **chưa khảo sát
 * bằng MCP** — xem JSDoc của hàm). Hàm này chỉ bọc thêm `test.step` cho báo cáo dễ đọc.
 */
export const nhapExcelVaoBoHoSo = async (
  page: Page,
  duLieu: DuLieuNhapExcel,
  duongDanFile: string,
  opts: { moLaiBoHoSo?: boolean } = {},
) => {
  await test.step(`Thao tác: nhập excel "${path.basename(duongDanFile)}" vào BHS "${duLieu.tenBoHoSo}"`, async () => {
    await nhapCauTrucTuExcel(page, duongDanFile, {
      // `false` → dùng luôn màn đang mở ở tab "Cấu trúc hồ sơ" (vừa kiểm tra BHS còn rỗng)
      recordUrl: (opts.moLaiBoHoSo ?? true) ? duLieu.recordUrl : undefined,
    });
  });
};

/**
 * **Mong muốn**: mở lại BHS → bảng "Cấu trúc hồ sơ" **có thêm thư mục mới** (tài liệu chỉ ghi log,
 * xem điểm 4 bên dưới).
 *
 * 🚨 Cố ý **KHÔNG** đòi bảng khớp đủ mọi dòng của file Excel: file mẫu có thể chứa **dòng lỗi cố ý**
 * (dùng cho các case kiểm tra lỗi), nên app bỏ qua một số dòng vẫn là **đúng**. Kỳ vọng của nhóm case
 * này chỉ là *"có thư mục, tài liệu mới được tạo"* (yêu cầu người dùng 2026-08-14).
 *
 * Cách assert:
 * 1. **Mở lại BHS** (không dùng bảng ngay sau khi nhập): tín hiệu đáng tin là dữ liệu **đã ghi
 *    xuống server**, không phải bảng vừa được app vẽ lại tại chỗ.
 * 2. **Mở hết cây** (`moRongToanBoCayCauTruc`) rồi đọc tên **mọi dòng, gộp cả các trang phân trang**.
 * 3. Assert cứng **duy nhất 1 điều**: có **≥ 1 thư mục** của file xuất hiện trong bảng (so theo tên).
 * 4. **Tài liệu chỉ ghi log, KHÔNG assert** — theo mô tả của người dùng (2026-08-14) template hiện
 *    dùng *"chỉ có thư mục, không có tài liệu/file"*. Lưu ý: đọc file thì cột `type` **vẫn có 11 dòng
 *    `Tài liệu`** (`A.1.1`, `A.1.2.1`… `A.3.1`) — nên nếu app tạo cả tài liệu thì đó là **thông tin
 *    trong log**, không phải lỗi; ngược lại app chỉ tạo thư mục cũng không fail. Cần chốt "phải có
 *    tài liệu" thì bật lại assert ở đây (xem `1.4.8.md`).
 * 5. Ghi log số item file khai báo / số dòng bảng có / những item không thấy — **không assert**.
 *
 * 🚨 Đã sửa 2 lần theo DOM thật (trace lần chạy 2026-08-14 10:49, xem `1.4.8.md`):
 * - Bảng Cấu trúc hồ sơ **KHÔNG** có bộ đếm `Thư mục: n` / `Tài liệu: m` như `KHO-TAI-LIEU.md`
 *   mục 4.4 mô tả → đã bỏ assert theo bộ đếm.
 * - Cây **không** expand sẵn hết mọi cấp: sau khi nhập excel bảng chỉ hiện `A`, `A.1`, `A.2`, `A.3`
 *   (cấp 0 + 1), tài liệu nằm sâu hơn → phải mở rộng cây trước khi đọc dòng.
 */
export const expectCoThemThuMucMoi = async (
  page: Page,
  duLieu: DuLieuNhapExcel,
  items: ItemTemplate[],
) => {
  await test.step(`Mong muốn: BHS "${duLieu.tenBoHoSo}" có thêm thư mục mới từ file excel`, async () => {
    await openBoHoSo(page, duLieu.recordUrl);
    await openTabCauTrucHoSo(page);
    await moRongToanBoCayCauTruc(page);

    const tenCacDong = await layTenCacDongCauTrucMoiTrang(page);
    expect(tenCacDong.length, {
      message:
        "Lỗi: nhập excel xong nhưng bảng Cấu trúc hồ sơ vẫn không có dòng nào → " +
        "không có thư mục/tài liệu nào được tạo",
    }).toBeGreaterThan(0);

    const thayTheoLoai = (loai: ItemTemplate["loai"]) =>
      items.filter(
        (item) =>
          item.loai === loai &&
          tenCacDong.some((dong) => dong.includes(item.ten)),
      );

    // --- assert cứng: phải có ≥ 1 THƯ MỤC của file (không đòi đủ mọi dòng) ---
    const thuMucCuaFile = items.filter((i) => i.loai === "Thư mục");
    expect(thayTheoLoai("Thư mục").length, {
      message:
        `Lỗi: nhập excel xong nhưng không thấy thư mục nào của file trong bảng Cấu trúc hồ sơ. ` +
        `File khai báo ${thuMucCuaFile.length} thư mục (vd "${thuMucCuaFile[0]?.ten ?? "-"}"). ` +
        `Các dòng đang có (${tenCacDong.length}): [${tenCacDong.join(" | ")}]`,
    }).toBeGreaterThan(0);

    // --- chỉ ghi log, KHÔNG assert: app bỏ qua dòng lỗi trong file là hành vi đúng; và theo mô tả
    //     của người dùng template hiện dùng chỉ sinh ra thư mục (xem JSDoc) ---
    const thieu = items.filter(
      (item) => !tenCacDong.some((dong) => dong.includes(item.ten)),
    );
    console.log(
      `[1.4.8] BHS "${duLieu.tenBoHoSo}": file excel khai báo ${items.length} item ` +
        `(${thuMucCuaFile.length} thư mục + ${items.length - thuMucCuaFile.length} tài liệu); ` +
        `bảng Cấu trúc hồ sơ có ${tenCacDong.length} dòng, khớp được ` +
        `${thayTheoLoai("Thư mục").length} thư mục + ${thayTheoLoai("Tài liệu").length} tài liệu` +
        (thieu.length
          ? `; ${thieu.length} item của file KHÔNG thấy trong bảng (dòng lỗi cố ý, app bỏ qua, ` +
            `hoặc cây chưa mở hết): ` +
            thieu.map((i) => `${i.loai} "${i.ma} ${i.ten}"`).join(", ")
          : "; khớp đủ mọi item của file"),
    );
  });
};

/**
 * Mở BHS ở tab "Cấu trúc hồ sơ" và assert nó **chưa có** thư mục / tài liệu nào — tiền đề để kết
 * luận mọi item thấy sau khi nhập đều do **thao tác nhập excel** sinh ra.
 *
 * Sau khi chạy xong, BHS **vẫn đang mở ở tab "Cấu trúc hồ sơ"** → bước nhập excel kế tiếp gọi với
 * `moLaiBoHoSo: false` để khỏi mở lại phiếu (~37 s).
 *
 * ⚠️ Trước khi kết luận "rỗng" phải chắc tab đã render: bảng chưa load cũng cho ra 0 dòng.
 * Mốc kiểm tra là ô tìm kiếm `txt-search-ho-so-tai-lieu` của toolbar tab (`KHO-TAI-LIEU.md` mục 4.4).
 */
export const expectBoHoSoConRong = async (
  page: Page,
  duLieu: DuLieuNhapExcel,
) => {
  await test.step(`Tiền đề: BHS "${duLieu.tenBoHoSo}" chưa có thư mục/tài liệu nào`, async () => {
    await openBoHoSo(page, duLieu.recordUrl);
    await openTabCauTrucHoSo(page);

    await expect(
      getActiveTabPane(page).getByTestId("txt-search-ho-so-tai-lieu"),
      { message: 'Lỗi: tab "Cấu trúc hồ sơ" chưa render xong' },
    ).toBeVisible({ timeout: TIMEOUT.DATA_LOADING });

    const tenCacDong = await layTenCacDongCauTrucMoiTrang(page);
    expect(tenCacDong, {
      message:
        "Lỗi: BHS vừa tạo lẽ ra chưa có thư mục/tài liệu nào, nhưng bảng Cấu trúc hồ sơ đang có: " +
        `[${tenCacDong.join(" | ")}]`,
    }).toHaveLength(0);
  });
};
