import _ from "lodash";
import { saveAs } from "file-saver";
import {
  Document,
  Packer,
  Paragraph,
  TextRun,
  Table,
  TableCell,
  TableRow,
  WidthType,
} from "docx";

// eslint-disable-next-line
const buildParagraphOptions = (node, context) => {
  return _.cond([
    [_.matches({ tagName: "H1" }), _.constant({ heading: "Heading1" })],
    [_.matches({ tagName: "H2" }), _.constant({ heading: "Heading2" })],
    [_.matches({ tagName: "H3" }), _.constant({ heading: "Heading3" })],
    [_.matches({ tagName: "H4" }), _.constant({ heading: "Heading4" })],
    [_.matches({ tagName: "H5" }), _.constant({ heading: "Heading5" })],
    [_.matches({ tagName: "H6" }), _.constant({ heading: "Heading6" })],
    [_.stubTrue, _.constant({})],
  ])(node);
};

const buildDocxParagraph = (node, context = {}) =>
  new Paragraph({
    ...buildParagraphOptions(node, context),
    children: _.flatMap(node.childNodes, (c) => buildDocxTextRun(c)),
  });

// eslint-disable-next-line
const buildTextRunOptions = (node) => {
  // TODO 斜体 加粗
  return {};
};

// eslint-disable-next-line
const buildDocxTextRun = (node, context = {}) =>
  new TextRun({ text: node.textContent.trim(), ...buildTextRunOptions(node) });

// NOTE this make sure root is a `Paragraph`, Paragraph can not nest Paragraph
const buildDocxObject = (node, context = {}) =>
  _.cond([
    [
      _.matches({ nodeType: Node.ELEMENT_NODE }),
      _.cond([
        [
          _.conforms({
            tagName: (tag) =>
              ["P", "H1", "H2", "H3", "H4", "H5", "H6"].includes(tag),
          }),
          (c) => buildDocxParagraph(c),
        ],
        [
          _.matches({ tagName: "OL" }),
          (n) => _.flatMap(n.childNodes, (c) => buildDocxObject(c, context)),
        ],
        [
          _.matches({ tagName: "UL" }),
          (n) => _.flatMap(n.childNodes, (c) => buildDocxObject(c, context)),
        ],
        [
          _.matches({ tagName: "LI" }),
          (n) => {
            const childNodes = _.filter(
              n.childNodes,
              (c) => !!c.textContent.trim()
            );
            let i = _.findIndex(childNodes, (c) =>
              ["OL", "UL", "LI"].includes(c.tagName)
            );
            if (i === -1) {
              i = Infinity;
            }
            const preNodes = _.slice(childNodes, 0, i);
            const postNodes = _.slice(childNodes, i);
            return [
              new Paragraph({
                bullet: { level: context.level ?? 0 },
                children: _.map(preNodes, (c) => buildDocxTextRun(c)),
              }),
              ..._.flatMap(postNodes, (c) =>
                buildDocxObject(c, {
                  level: context.level ? context.level + 1 : 1,
                })
              ),
            ];
          },
        ],
        [_.stubTrue, buildDocxParagraph],
      ]),
    ],
    [
      _.matches({ nodeType: Node.TEXT_NODE }),
      (n) => new Paragraph(n.textContent.trim()),
    ],
    [_.stubTrue, (n) => new Paragraph(n.textContent.trim())],
  ])(node);

const buildFormCardRows = (node) => {
  const chunkedFields = _.chunk(_.values(_.get(node, ["content"], {})), 3);
  return chunkedFields.map(
    (fields) =>
      new TableRow({
        children: _.flatten(
          _.assign(
            _.fill(new Array(3), [
              new TableCell({ children: [], columnSpan: 2 }),
            ]),
            fields?.map((field) => {
              return [
                new TableCell({
                  children: [new Paragraph(field.label)],
                  width: { size: 10, type: WidthType.PERCENTAGE },
                }),
                new TableCell({
                  children: [new Paragraph(field.value)],
                  width: { size: 20, type: WidthType.PERCENTAGE },
                }),
              ];
            })
          )
        ),
      })
  );
};

const convertAgentContent = (content) => {
  const node = document.createElement("div");
  node.innerHTML = content;
  return _.flatMap(node.childNodes, buildDocxObject);
};

const buildAgentRows = (node) => {
  return [
    new TableRow({
      children: [
        new TableCell({
          children: [new Paragraph(node.assistantName)],
          width: { size: 10, type: WidthType.PERCENTAGE },
        }),
        new TableCell({
          children: convertAgentContent(node.content),
          width: { size: 90, type: WidthType.PERCENTAGE },
          columnSpan: 5,
        }),
      ],
    }),
  ];
};

const buildRows = (nodes) => {
  const sectionBuilder = _.cond([
    // Form Node
    [_.matches({ type: "form_card" }), buildFormCardRows],
    // Agent Node
    [_.matches({ type: "UserTask" }), buildAgentRows],
    [_.stubTrue, _.constant([])],
  ]);
  return _.flatten(nodes.map(sectionBuilder));
};

export const exportFlowToDocx = async (nodes) => {
  const children: unknown[] = [
    new Paragraph({
      text: "课程设计",
      heading: "Heading1",
      alignment: "center",
    }),
  ];
  const rows = buildRows(nodes);
  if (rows.length) {
    children.push(
      new Table({
        rows,
      })
    );
  }

  const doc = new Document({
    sections: [
      {
        children,
      },
    ],
  });

  // 将文档打包成Buffer并保存为文件
  return await Packer.toBlob(doc)
//  (blob) => {
//     const mimeType =
//       "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
//     saveAs(blob, "课程设计.docx", { type: mimeType });
//   }
};