import colorMap from "./color";


export class IdGenerator {
  static CHARS = '0123456789abcdefghijklmnopqrstuvwxyz';
  static ID_LENGTH = 8;

  /**
   * 生成类似语雀的段落ID
   * 格式: 8位随机字符（数字+小写字母）
   * 示例: 'ag7k9pq2'
   */
  static generateId() {
    let result = '';
    const chars = IdGenerator.CHARS;
    const length = IdGenerator.ID_LENGTH;

    for (let i = 0; i < length; i++) {
      result += chars.charAt(Math.floor(Math.random() * chars.length));
    }

    return result;
  }

  /**
   * 检查ID是否有效
   */
  static isValidId(id) {
    if (!id || id.length !== IdGenerator.ID_LENGTH) return false;
    return /^[0-9a-z]+$/.test(id);
  }
}

export function generateId() {
  return IdGenerator.generateId();
}


export function getModificationDate(date = new Date()) {
  const buffer = [
    date.getUTCFullYear().toString(),
    (date.getUTCMonth() + 1).toString().padStart(2, "0"),
    date.getUTCDate().toString().padStart(2, "0"),
    date.getUTCHours().toString().padStart(2, "0"),
    date.getUTCMinutes().toString().padStart(2, "0"),
    date.getUTCSeconds().toString().padStart(2, "0"),
  ];

  return buffer.join("");
}
const InvisibleCharactersRegExp = /[\x01-\x1F]/g;

export function removeNullCharacters(str, replaceInvisible = false) {
  if (typeof str !== "string") {
    console.error(`The argument must be a string.`);
    return str;
  }
  if (replaceInvisible) {
    str = str.replace(InvisibleCharactersRegExp, " ");
  }
  return str.replace(/\\x00/g, "");
}

export function findCommonSubstring(text1, text2) {
  const m = text1.length;
  const n = text2.length;
  const dp = Array.from(Array(m + 1), () => Array(n + 1).fill(0));
  let maxLength = 0;
  let endIndex = 0;

  for (let i = 1; i <= m; i++) {
    for (let j = 1; j <= n; j++) {
      if (text1[i - 1] === text2[j - 1]) {
        dp[i][j] = dp[i - 1][j - 1] + 1;
        if (dp[i][j] > maxLength) {
          maxLength = dp[i][j];
          endIndex = i - 1;
        }
      }
    }
  }

  if (maxLength === 0) {
    return "";
  }

  return text1.substring(endIndex - maxLength + 1, endIndex + 1);
}
export function convertColorToRGB(color) {
  // 如果颜色已经是 RGB 格式，则直接返回该颜色
  if (Array.isArray(color) && color.length === 3) {
    return color;
  }

  // 将颜色转换为 RGB 格式
  let rgbColor = [0, 0, 0];

  if (typeof color === "string") {
    // 如果颜色是十六进制格式，则将其转换为 RGB 格式
    if (color.startsWith("#")) {
      const hexColor = color.slice(1);
      const r = parseInt(hexColor.substr(0, 2), 16);
      const g = parseInt(hexColor.substr(2, 2), 16);
      const b = parseInt(hexColor.substr(4, 2), 16);
      rgbColor = [r, g, b];
    }
    // 如果颜色是 CSS 颜色关键字，则将其转换为 RGB 格式
    else if (colorMap.has(color)) {
      rgbColor = colorMap.get(color);
    }
  }
  // 如果颜色是 RGB 格式，则将其转换为 `[R, G, B]` 格式
  else if (Array.isArray(color)) {
    rgbColor = color;
  }

  return rgbColor;
}

export const AnnotationType = {
  TEXT: 1,
  LINK: 2,
  FREETEXT: 3,
  LINE: 4,
  SQUARE: 5,
  CIRCLE: 6,
  POLYGON: 7,
  POLYLINE: 8,
  HIGHLIGHT: 9,
  UNDERLINE: 10,
  SQUIGGLY: 11,
  STRIKEOUT: 12,
  STAMP: 13,
  CARET: 14,
  INK: 15,
  POPUP: 16,
  FILEATTACHMENT: 17,
  SOUND: 18,
  MOVIE: 19,
  WIDGET: 20,
  SCREEN: 21,
  PRINTERMARK: 22,
  TRAPNET: 23,
  WATERMARK: 24,
  THREED: 25,
  REDACT: 26,
};
export class IdManager {
  constructor() {
    this._id = 0;
  }
  getId(page) {
    return page + '-' + generateId();
  }
}

export class Annotation {
  constructor(param) {
    this._data = {
      annotationFlags: 4,
      annotationType: this.getType(param.subtype),
      borderStyle: {
        dashArray: [3],
        horizontalCornerRadius: 0,
        style: 1,
        verticalCornerRadius: 0,
        width: 0,
      },
      color: new Uint8ClampedArray(param.color),
      contents: param.contents || "",
      userId: param.userId || "",
      nickName: param.nickName || "",
      hasAppearance: false,
      id: param.id,
      rect: param.rect,
      quadPoints: param.quadPoints,
      subtype: param.subtype,
      createTime: param.createTime,
      noteType: param.noteType,
      percentRect: param.percentRect,
      rotation: param.rotation,
      title: "author",
    };
  }
  getType(type) {
    const p = type.toLocaleUpperCase();
    return AnnotationType[p];
  }
  getData() {
    return this._data;
  }
}

export class PdfAnnotation {
  constructor(param) {
    this._pdfViewer = param.pdfViewer;
    this._pdfJs = param.pdfJs;

    this._idManager = new IdManager();
    this._annotations = [];
  }

  getAnnoations() {
    return this._annotations;
  }


  addAnnots(annots) {

    if (Array.isArray(annots)) {
      // 先清除现有的所有注解，避免重叠
      this.removeAllAnnots();

      const s = {};

      // 先整理注解数据
      for (const t of annots) {
        if (!s[t.page]) {
          s[t.page] = [];
        }
        s[t.page].push(t);
      }

      // 移动到循环外部，避免重复创建 promises 数组
      // 只处理有效的页面索引
      const validPages = Object.keys(s).filter(pageIndex => {
        const pageNum = +pageIndex + 1;
        return pageNum > 0 && pageNum <= this._pdfJs.numPages;
      });

      if (validPages.length > 0) {
        const promises = validPages.map((pageIndex) => {
          const pageNum = +pageIndex + 1; // PDF页面从1开始计数
          return this._pdfJs.getPage(pageNum);
        });

        Promise.all(promises).then((pages) => {
          for (const page of pages) {
            const pageIndex = page.pageIndex; // pageIndex从0开始
            if (s[pageIndex]) { // 确保存在该页面的注解
              page.rAddAnnotation(s[pageIndex]);
              // 添加检查确保页面视图和注解层存在
              if (this._pdfViewer._pages[pageIndex] &&
                this._pdfViewer._pages[pageIndex].annotationLayer) {
                this._pdfViewer._pages[pageIndex].updateAnnotationLayer(
                  s[pageIndex]
                );
              }
            }
          }
        }).catch(error => {
          console.error('Error loading pages for annotations:', error);
        });
      }

      // 更新_annotations数组
      this._annotations = annots;
    }
  }

  removeAnnots(annotIds) {
    // 确保参数是数组格式
    const idsToRemove = Array.isArray(annotIds) ? annotIds : [annotIds];

    // 保存将要删除的注解信息（包括页面信息）
    const annotsToRemove = this._annotations.filter(annot => idsToRemove.includes(annot.id));

    // 从_annotations数组中移除指定ID的注解
    this._annotations = this._annotations.filter(annot => !idsToRemove.includes(annot.id));

    // 按页面分组需要更新的注解
    const pagesToUpdate = {};

    // 收集需要更新的页面和注解
    annotsToRemove.forEach(annot => {
      const page = annot.page;
      if (!pagesToUpdate[page]) {
        pagesToUpdate[page] = [];
      }
      pagesToUpdate[page].push(annot.id);
    });

    // 更新每个页面的注解层
    Object.keys(pagesToUpdate).forEach(pageIndex => {
      const pageView = this._pdfViewer._pages[pageIndex];
      if (pageView) {
        // 更新注解层，只保留该页面剩余的注解
        const remainingAnnots = this._annotations.filter(a => a.page === parseInt(pageIndex));
        pageView.updateAnnotationLayer(remainingAnnots);
      }
    });
  }


  removeAllAnnots() {
    // 清空所有注解
    this._annotations = [];

    // 更新所有页面的注解层
    for (let i = 0; i < this._pdfViewer._pages.length; i++) {
      const pageView = this._pdfViewer._pages[i];
      // 添加保护措施，确保pageView存在且已初始化
      if (pageView && pageView.annotationLayer && typeof pageView.updateAnnotationLayer === 'function') {
        try {
          // 强制清空注解层的DOM元素
          if (pageView.annotationLayer.div) {
            pageView.annotationLayer.div.innerHTML = '';
          }
          // 然后更新注解层（传入空数组）
          pageView.updateAnnotationLayer([]);
        } catch (error) {
          console.warn('Failed to update annotation layer for page', i, error);
        }
      }
    }
  }

  setAnno(param) {
    return new Promise((resolve) => {
      const annos = this.getPageAnno();

      // 获取页对象
      const promises = Object.keys(annos).map((i) => this._pdfJs.getPage(+i));
      const str = document.getSelection().toString();
      Promise.all(promises)
        .then(async (pages) => {
          const annots = [];
          for (const page of pages) {
            const ind = page.pageIndex + 1;
            const rec = annos[ind];
            let Anno = new Annotation({
              subtype: param.subtype,
              id: this._idManager.getId(ind),
              quadPoints: rec.quadPoints,
              color: convertColorToRGB(param.color),
              contents: param.contents,
              userId: param.userId,
              nickName: param.nickName,
              createTime: param.createTime,
              noteType: param.noteType,
              percentRect: rec.percentRect,
              rect: rec.rect,
              rotation: this._pdfViewer.pagesRotation
            }).getData();
            Anno = {
              ...Anno,
              page: page.pageIndex,
              color: convertColorToRGB(param.color),
            };
            const texts = [];
            const buffer = [];
            const { items } = await page.getTextContent();
            for (const item of items) {
              if (item.str) {
                buffer.push(item.str);
              }
              if (item.hasEOL) {
                buffer.push("\n");
              }
            }
            texts.push(removeNullCharacters(buffer.join("")));
            let a = texts.join("\n");
            let b = str.replace(/ﬁ/g, "fi").replace(/ﬂ/g, "fl") || "";
            // 行数据处理

            let f = findCommonSubstring(a, b);

            Anno.info = f;
            annots.push(Anno);
            page.addAnnotation(Anno);
            this._pdfViewer._pages[page.pageIndex].updateAnnotationLayer([
              Anno,
            ]);
            this._annotations = [...this._annotations, ...annots];
          }
          resolve(annots)
        })
        .finally(() => {
          document.getSelection().empty();
          // resolve(this._annotations);
        });
    });
  }

  /**
 * 把绝对像素坐标转成相对于页面尺寸的百分比
 * @param page  页码（从 1 开始）
 * @param absRect  绝对坐标 [x1, y1, x2, y2]
 * @returns [x1%, y1%, x2%, y2%]
 */
  getRectAsPercent(page, absRect) {
    // 拿到对应 page 的 viewport
    // pageIndex 从 0 开始
    const pdfPage = pdfViewer.getPageView(pageIndex);   // 或 pdfViewer._pages[pageIndex]
    const { width, height } = pdfPage.pdfPage.view;

    const [x1, y1, x2, y2] = absRect;
    return [
      (x1 / width).toFixed(3),
      (y1 / height).toFixed(3),
      (x2 / width).toFixed(3),
      (y2 / height).toFixed(3),
    ];

  }
  /**
 * @param pageIndex 从 0 开始
 * @param absRect   
 * @returns        
 */
  getPercentRect(page, quadPoints) {
    const p = flat(quadPoints);
    const rect = geintegrationRect(p);
    let pg = document.querySelector(`.page[data-page-number='${page}']`);
    var pageRect = pg.getBoundingClientRect();
    const { width, height } = pageRect;
    // debugger
    if (rect && pageRect) {
      const x = rect.left - pageRect.left;
      const y = Math.abs(pageRect.top - rect.top);
      const x1 = rect.right - pageRect.left;
      const y1 = Math.abs(pageRect.top - rect.bottom);
      const left = Math.round((x / width) * 1000) / 1000
      const top = Math.round((1 - (y / height)) * 1000) / 1000
      const right = Math.round((x1 / width) * 1000) / 1000
      const bottom = Math.round((1 - (y1 / height)) * 1000) / 1000
      // 当前行相对于当前页面的坐标
      const Coord = normalizeRect([left, top, right, bottom]);
      return Coord;
    }
    Math.round()
    return [];
  }


  note(param, savedRange = null) {
    return new Promise((resolve) => {
      const annos = this.getPageAnno(savedRange);

      // 获取页对象
      const promises = Object.keys(annos).map((i) => this._pdfJs.getPage(+i));
      const str = savedRange ? savedRange.toString() : document.getSelection().toString(); // 修改：优先使用传入选区
      Promise.all(promises).then(async (pages) => {
        const annots = [];
        for (const page of pages) {
          const ind = page.pageIndex + 1;
          const rec = annos[ind];
          let Anno = new Annotation({
            subtype: param.subtype,
            id: this._idManager.getId(ind),
            quadPoints: rec.quadPoints,
            color: convertColorToRGB(param.color),
            contents: param.contents,
            userId: param.userId,
            nickName: param.nickName,
            createTime: param.createTime,
            noteType: param.noteType,
            percentRect: rec.percentRect,
            rect: rec.rect,
            rotation: this._pdfViewer.pagesRotation,
          }).getData();
          Anno = {
            ...Anno,
            page: page.pageIndex,
            color: convertColorToRGB(param.color),
          };
          const texts = [];
          const buffer = [];
          const { items } = await page.getTextContent();
          for (const item of items) {
            if (item.str) {
              buffer.push(item.str);
            }
            if (item.hasEOL) {
              buffer.push("\n");
            }
          }
          texts.push(removeNullCharacters(buffer.join("")));
          let a = texts.join("\n");
          let b = str.replace(/ﬁ/g, "fi").replace(/ﬂ/g, "fl") || "";
          // 行数据处理

          let f = findCommonSubstring(a, b);
          // @ts-ignore
          Anno.info = f;
          annots.push(Anno);
          // 新增渲染逻辑
          page.addAnnotation(Anno);
          this._pdfViewer._pages[page.pageIndex].updateAnnotationLayer([Anno]);
          this._annotations = [...this._annotations, ...annots];
        }
        resolve(annots);
      }).catch(err => {
        console.log('err', err);
      });
    });
  }
  getPageAnno(savedRange = null) {
    // 获取当前选择的所有页
    const selection = savedRange || window.getSelection();
    if (!selection.rangeCount) return {};
    const pageIndexs = this.getPageIndexs(selection);  // 传入selection
    let carr = []; // 每页的行数组 [页:[行],页:[行]]
    if (pageIndexs.length > 0) {
      // 获取页数据判断分页的行数据
      const pageRect = this.getPageView();
      const rects = selection.getRangeAt(0).getClientRects();
      const pagesRow = [];
      // 将数据划分到每页
      if (rects) {
        let index = 0;
        for (const o of Array.from(rects)) {
          // 宽度与页面宽度相等为分页行
          // @ts-ignore
          if (o.width === pageRect.width) {
            index += 1;
            continue;
          }
          // 将数据放到对应的页数组中
          pagesRow[index] ? pagesRow[index].push(o) : (pagesRow[index] = [o]);
        }
      }
      // 清除空元素
      let _arr = [...pagesRow].filter((o) => o);

      carr = _arr.map((u) => {
        // 重新构建分配好的行数据
        const newRow = [];
        let Index = 0;

        for (const [ind, o] of u.entries()) {
          // 第一个数据不做判断
          if (ind === 0) {
            newRow[Index] = [o];
          } else if (o.width === 0) {
            // width为0为换行
            Index += 1;
          } else if (u[ind - 1].width === 0) {
            // 对于存在width为0的页行数据处理
            // 换行行的后一行数据直接添加
            newRow[Index] = [o];
          } else if (ind > 0) {
            // 对于没有明显的换行行（即width===0）的处理
            // 判断当前行与前一行的行间距
            // 行间距大于阈值的换行到下一行
            // 不同的行间距基本大于10
            const L = Math.abs(o.top - u[ind - 1].top);
            if (L > 9) {
              Index += 1;
              newRow[Index] = [o];
            } else {
              newRow[Index].push(o);
            }
          }
        }
        return newRow;
      });
    }
    // 整页行划分
    const p = {};
    // 遍历页

    for (const [ind, t] of carr.entries()) {
      // 遍历页的行
      const da = {
        rect: [],
        quadPoints: [],
      };

      da.rect = this.getRect(+pageIndexs[ind], t);
      da.percentRect = this.getPercentRect(+pageIndexs[ind], t);

      for (const s of t) {
        const r = geintegrationRect(s);

        if (r) {
          const re = this.getPointFromRect(+pageIndexs[ind], r);
          da.quadPoints.push(getQuadPoints(re));
        }
      }

      p[pageIndexs[ind]] = da;
    }

    return p;
  }
  getPageIndexs(selection = window.getSelection()) {

    if (!selection.rangeCount) return [];
    const r = selection.getRangeAt(0).commonAncestorContainer;
    let pages = [];

    // 页面获取
    if (r.nodeType === 1) {
      pages = [];
      // 当前页
      if (r.classList.contains("textLayer")) {
        pages.push(r.parentNode.dataset.pageNumber);
      } else if (r.classList.contains("page")) {
        pages.push(r.dataset.pageNumber);
      } else {
        // 跨页
        const nodes =
          selection.getRangeAt(0).cloneContents().childNodes || [];
        nodes.forEach((element) => {
          pages.push(element.dataset.pageNumber);
        });
      }
    } else if (r.nodeType === 3) {
      // 单行

      const t = findElementsWithClass(r.parentNode, "page");

      if (t) {
        pages = [t.dataset.pageNumber];
      }
    }
    console.log(409, pages);
    return pages;
  }

  getRect(page, rects) {
    const p = flat(rects);
    const rect = geintegrationRect(p);
    let a = [];
    if (rect) {
      a = this.getPointFromRect(page, rect);
    }
    return a;
  }
  /**
   * @name 当前行相对于当前页面的坐标-基于pdf
   * @param page [number]
   * @param rect 行矩阵对象
   */
  getPointFromRect(page, rect) {
    let pg = document.querySelector(`.page[data-page-number='${page}']`);
    var pageRect = pg.getBoundingClientRect();

    if (rect && pageRect) {
      const x = rect.left - pageRect.left;
      const y = Math.abs(pageRect.top - rect.top);
      const x1 = rect.right - pageRect.left;
      const y1 = Math.abs(pageRect.top - rect.bottom);
      // 当前行相对于当前页面的坐标

      const [_x1, _y1] = this.getViewPort(page, x, y);
      const [_x2, _y2] = this.getViewPort(page, x1, y1);
      const Coord = normalizeRect([_x1, _y1, _x2, _y2]);

      return Coord;
    }
    return [];
  }
  /**
   * @name 获取视口坐标
   * @param page 页面
   * @param x 要转换的坐标X
   * @param y 要转换的坐标Y
   */
  getViewPort(page, x, y) {
    let x_1_y_1 = this._pdfViewer._pages[page - 1].viewport.convertToPdfPoint(
      x,
      y
    );

    return x_1_y_1;
  }

  getPageView() {
    let pg = document.querySelector(`.page[data-page-number='${1}']`);
    var rect = pg.getBoundingClientRect();
    return rect;
  }
}

/**
 * @name 获取行数据的最大最小坐标
 * @param rect 行坐标对象
 */
export function geintegrationRect(rects) {
  if (rects.length === 0) {
    return null;
  }
  if (rects.length === 1) {
    return {
      left: rects[0].left,
      top: rects[0].top,
      right: rects[0].right,
      bottom: rects[0].bottom,
    };
  }

  let minX = rects[0].left,
    minY = rects[0].top,
    maxX = rects[0].right,
    maxY = rects[0].bottom;
  // 遍历一行中所有的区域块，获取最大最小X
  for (const t of rects) {
    if (t.left < minX) {
      minX = t.left;
    }
    if (t.right > maxX) {
      maxX = t.right;
    }
    if (t.top < minY) {
      minY = t.top;
    }
    if (t.bottom > maxY) {
      maxY = t.bottom;
    }
  }

  return {
    left: minX,
    top: minY,
    right: maxX,
    bottom: maxY,
  };
}
export function normalizeRect(rect) {
  const r = rect.slice(0); // clone rect
  if (rect[0] > rect[2]) {
    r[0] = rect[2];
    r[2] = rect[0];
  }
  if (rect[1] > rect[3]) {
    r[1] = rect[3];
    r[3] = rect[1];
  }
  return r;
}
export function flat(arr) {
  let result = [];
  for (let i = 0; i < arr.length; i++) {
    if (Array.isArray(arr[i])) {
      result = result.concat(flat(arr[i]));
    } else {
      result.push(arr[i]);
    }
  }
  return result;
}
export function getQuadPoints(Coord) {
  return [
    {
      x: Coord[0] + 0.5,
      y: Coord[3] - 2,
    },
    {
      x: Coord[2] - 0.5,
      y: Coord[3] - 2,
    },
    {
      x: Coord[0] + 0.5,
      y: Coord[1] + 1.5,
    },
    {
      x: Coord[2] - 0.5,
      y: Coord[1] + 1.5,
    },
  ];
}

export function findElementsWithClass(node, className) {
  // 如果当前节点为空，则返回一个空数组
  if (!node) {
    return null;
  }

  // 收集当前节点下的所有包含指定类的子节点
  let elements = null;

  if (node.classList.contains(className)) {
    return node;
  }

  // 对当前节点的父节点进行递归查找，并将结果合并到elements数组中
  let parent = node.parentNode;
  if (parent) {
    elements = findElementsWithClass(parent, className);
  }

  return elements;
}
