import { fabric } from "fabric-with-all";
import { generateId } from "../../utils/helper";
import { OperationType } from "../../utils/layerHelper";
import { CreateSelectionCommand } from "../../commands/SelectionCommands";
import { ClearSelectionCommand } from "../../commands/LassoCutoutCommand";

/**
 * 选区管理器
 * 负责管理画布上的选区操作
 */
export class SelectionManager {
  /**
   * 创建选区管理器
   * @param {Object} options 配置选项
   * @param {Object} options.canvas fabric.js画布实例
   * @param {Object} options.commandManager 命令管理器实例
   * @param {Object} options.layerManager 图层管理实例
   */
  constructor(options = {}) {
    this.canvas = options.canvas;
    this.commandManager = options.commandManager;
    this.layerManager = options.layerManager;

    // 选区状态
    this.isActive = false;
    this.selectionType = OperationType.LASSO_RECTANGLE; // 使用常量而不是字符串
    this.selectionObject = null; // 当前选区对象
    this.selectionId = "selection_" + Date.now();
    this.featherAmount = 0; // 羽化值

    // 选区样式配置
    this.selectionStyle = {
      stroke: "#0096ff",
      strokeWidth: 1,
      strokeDashArray: [5, 5],
      fill: "rgba(0, 150, 255, 0.1)",
      selectable: false,
      evented: false,
      excludeFromExport: true,
      hoverCursor: "default",
      moveCursor: "default",
    };

    // 绘制状态
    this.drawingObject = null;
    this.startPoint = null;
    this.selectionPath = null; // 存储选区路径数据

    // 自由选区相关状态
    this.drawingPoints = null;
    this.currentPathString = null;

    // 不再直接绑定事件处理函数
    this._mouseDownHandler = null;
    this._mouseMoveHandler = null;
    this._mouseUpHandler = null;
    this._keyDownHandler = null;

    // 选区相关的工具类型
    this.selectionTools = [
      OperationType.LASSO,
      OperationType.LASSO_RECTANGLE,
      OperationType.LASSO_ELLIPSE,
    ];

    // 当前工具
    this.currentTool = OperationType.SELECT;

    // 选区状态变化回调
    this.onSelectionChanged = null;

    // 不再自动初始化事件，改为手动控制
    // this.initEvents();
  }

  /**
   * 设置当前工具
   * @param {String} toolId 工具ID
   */
  setCurrentTool(toolId) {
    this.currentTool = toolId;

    // 检查是否为选区工具
    const wasActive = this.isActive;
    this.isActive = this.selectionTools.includes(toolId);

    // 如果从非选区工具切换到选区工具，初始化事件
    if (!wasActive && this.isActive) {
      this.initEvents();
    }
    // 如果从选区工具切换到非选区工具，清理事件和选区
    else if (wasActive && !this.isActive) {
      this.cleanupEvents();
      this.clearSelection();
    }

    // 根据工具类型设置选区类型
    if (this.isActive) {
      this.selectionType = toolId;
    }
  }

  /**
   * 初始化选区相关事件
   */
  initEvents() {
    if (!this.canvas || this._mouseDownHandler) return; // 避免重复初始化

    // 保存实例引用，用于事件处理函数中
    const self = this;

    // 鼠标按下事件处理
    this._mouseDownHandler = (options) => {
      // 如果选区功能未激活，不处理事件
      if (!this.isActive) return;

      // 如果点击的是已有对象且不是选区对象，则不处理
      if (
        options.target &&
        options.target.id !== this.selectionId &&
        options.target.selectable !== false &&
        options.target.type !== "selection"
      ) {
        return;
      }

      // 阻止事件冒泡，避免与 CanvasEventManager 冲突
      options.e.stopPropagation();

      // 根据选区类型执行不同的起始操作
      switch (this.selectionType) {
        case OperationType.LASSO:
          this.startFreeSelection(options);
          break;
        case OperationType.LASSO_ELLIPSE:
          this.startEllipseSelection(options);
          break;
        case OperationType.LASSO_RECTANGLE:
          this.startRectangleSelection(options);
          break;
      }
    };

    // 鼠标移动事件处理
    this._mouseMoveHandler = (options) => {
      // 如果选区功能未激活或没有正在绘制的对象，不处理事件
      if (!this.isActive || !this.drawingObject) return;

      // 阻止事件冒泡
      options.e.stopPropagation();

      // 根据选区类型执行不同的绘制操作
      switch (this.selectionType) {
        case OperationType.LASSO_RECTANGLE:
          this.drawRectangleSelection(options);
          break;
        case OperationType.LASSO_ELLIPSE:
          this.drawEllipseSelection(options);
          break;
        case OperationType.LASSO:
          this.drawFreeSelection(options);
          break;
      }
    };

    // 鼠标抬起事件处理
    this._mouseUpHandler = (options) => {
      // 如果选区功能未激活或没有正在绘制的对象，不处理事件
      if (!this.isActive || !this.drawingObject) return;

      // 阻止事件冒泡
      if (options && options.e) {
        options.e.stopPropagation();
      }

      // 根据选区类型执行不同的完成操作
      switch (this.selectionType) {
        case OperationType.LASSO_RECTANGLE:
          this.endRectangleSelection();
          break;
        case OperationType.LASSO_ELLIPSE:
          this.endEllipseSelection();
          break;
        case OperationType.LASSO:
          this.endFreeSelection();
          break;
      }

      // 如果有命令管理器，使用命令模式记录选区创建
      if (this.commandManager && this.selectionObject) {
        this.commandManager.execute(
          new CreateSelectionCommand({
            canvas: this.canvas,
            selectionManager: this,
            selectionObject: this.selectionObject,
            selectionType: this.selectionType,
          })
        );
      }
    };

    // 键盘事件处理
    this._keyDownHandler = (event) => {
      // 只在选区功能激活时处理键盘事件
      if (!this.isActive) return;

      if (event.key === "Escape") {
        // ESC键取消当前选区操作
        if (this.drawingObject) {
          this.canvas.remove(this.drawingObject);
          this.drawingObject = null;
          this.startPoint = null;
        }
        // 清除已有选区
        else if (this.selectionObject) {
          if (this.commandManager) {
            this.commandManager.execute(
              new ClearSelectionCommand({
                selectionManager: this,
              })
            );
          } else {
            this.clearSelection();
          }
        }
      }
    };

    // 添加事件监听
    this.canvas.on("mouse:down", this._mouseDownHandler);
    this.canvas.on("mouse:move", this._mouseMoveHandler);
    this.canvas.on("mouse:up", this._mouseUpHandler);

    // 添加键盘事件监听
    document.addEventListener("keydown", this._keyDownHandler);
  }

  /**
   * 清理事件监听
   */
  cleanupEvents() {
    if (!this.canvas) return;

    // 移除事件监听
    if (this._mouseDownHandler) {
      this.canvas.off("mouse:down", this._mouseDownHandler);
      this._mouseDownHandler = null;
    }
    if (this._mouseMoveHandler) {
      this.canvas.off("mouse:move", this._mouseMoveHandler);
      this._mouseMoveHandler = null;
    }
    if (this._mouseUpHandler) {
      this.canvas.off("mouse:up", this._mouseUpHandler);
      this._mouseUpHandler = null;
    }
    if (this._keyDownHandler) {
      document.removeEventListener("keydown", this._keyDownHandler);
      this._keyDownHandler = null;
    }
  }

  /**
   * 获取选区对象
   * @returns {Object} 选区对象
   */
  getSelectionObject() {
    return this.selectionObject;
  }

  /**
   * 获取选区路径
   * @returns {Array|String} 选区路径数据
   */
  getSelectionPath() {
    return this.selectionPath;
  }

  /**
   * 获取羽化值
   * @returns {Number} 羽化值
   */
  getFeatherAmount() {
    return this.featherAmount;
  }

  /**
   * 设置羽化值
   * @param {Number} amount 羽化值
   */
  setFeatherAmount(amount) {
    this.featherAmount = amount;
    return this.updateSelectionAppearance();
  }

  /**
   * 设置选区对象
   * @param {Object} object 选区对象
   */
  setSelectionObject(object) {
    // 如果已存在选区，先移除
    if (this.selectionObject) {
      this.removeSelectionFromCanvas();
    }

    // 更新选区对象
    this.selectionObject = object;
    this.selectionPath = object.path;
    this.selectionId = object.id || generateId();

    // 更新外观
    this.updateSelectionAppearance();

    // 添加到画布（确保在顶层）
    if (this.canvas && this.selectionObject) {
      this.canvas.add(this.selectionObject);
      this.canvas.bringToFront(this.selectionObject);
      this.canvas.renderAll();
    }

    // 触发选区变化回调
    if (this.onSelectionChanged && typeof this.onSelectionChanged === "function") {
      this.onSelectionChanged();
    }

    return true;
  }

  /**
   * 从路径数据设置选区
   * @param {Array|String} path 选区路径数据
   */
  setSelectionFromPath(path) {
    if (!path) return false;

    // 创建选区对象
    const selectionObj = new fabric.Path(path, {
      ...this.selectionStyle,
      id: `selection_${Date.now()}`,
      name: "selection",
    });

    // 设置选区
    return this.setSelectionObject(selectionObj);
  }

  /**
   * 更新选区外观
   */
  updateSelectionAppearance() {
    if (!this.selectionObject) return false;

    // 应用基本样式
    Object.assign(this.selectionObject, this.selectionStyle);

    // 应用羽化效果
    if (this.featherAmount > 0) {
      this.selectionObject.shadow = new fabric.Shadow({
        color: "rgba(0, 150, 255, 0.5)",
        blur: this.featherAmount,
        offsetX: 0,
        offsetY: 0,
      });
    } else {
      this.selectionObject.shadow = null;
    }

    // 更新画布
    this.canvas.renderAll();
    return true;
  }

  /**
   * 移除选区
   */
  removeSelectionFromCanvas() {
    if (this.canvas && this.selectionObject) {
      this.canvas.remove(this.selectionObject);
      this.canvas.renderAll();
    }
  }

  /**
   * 清除选区
   */
  clearSelection() {
    // 移除选区对象
    this.removeSelectionFromCanvas();

    // 重置选区状态
    this.selectionObject = null;
    this.selectionPath = null;
    this.selectionId = null;
    this.featherAmount = 0;

    // 触发选区变化回调
    if (this.onSelectionChanged && typeof this.onSelectionChanged === "function") {
      this.onSelectionChanged();
    }

    return true;
  }

  /**
   * 反转选区
   */
  async invertSelection() {
    if (!this.canvas || !this.selectionObject) return false;

    // 获取画布范围
    const canvasRect = new fabric.Rect({
      left: 0,
      top: 0,
      width: this.canvas.width,
      height: this.canvas.height,
      selectable: false,
    });

    // 创建反选路径
    let invertedPath;
    try {
      invertedPath = canvasRect.subtractPathFromRect(this.selectionObject.path);
    } catch (error) {
      console.error("无法反转选区:", error);
      return false;
    }

    // 设置新的选区
    const newSelection = new fabric.Path(invertedPath.path, {
      ...this.selectionStyle,
      id: `selection_${Date.now()}`,
      name: "selection",
    });

    return this.setSelectionObject(newSelection);
  }

  /**
   * 添加到选区
   * @param {Object} newSelection 要添加的选区对象
   */
  async addToSelection(newSelection) {
    if (!this.canvas) return false;

    // 如果当前没有选区，直接使用新选区
    if (!this.selectionObject) {
      return this.setSelectionObject(newSelection);
    }

    // 合并选区
    let combinedPath;
    try {
      combinedPath = this.selectionObject.union(newSelection);
    } catch (error) {
      console.error("无法添加到选区:", error);
      return false;
    }

    // 设置新的选区
    const combinedSelection = new fabric.Path(combinedPath.path, {
      ...this.selectionStyle,
      id: `selection_${Date.now()}`,
      name: "selection",
    });

    return this.setSelectionObject(combinedSelection);
  }

  /**
   * 从选区中移除
   * @param {Object} removeSelection 要移除的选区对象
   */
  async removeFromSelection(removeSelection) {
    if (!this.canvas || !this.selectionObject) return false;

    // 从当前选区中减去新选区
    let resultPath;
    try {
      resultPath = this.selectionObject.subtract(removeSelection);
    } catch (error) {
      console.error("无法从选区中移除:", error);
      return false;
    }

    // 设置新的选区
    const newSelection = new fabric.Path(resultPath.path, {
      ...this.selectionStyle,
      id: `selection_${Date.now()}`,
      name: "selection",
    });

    return this.setSelectionObject(newSelection);
  }

  /**
   * 应用羽化效果
   * @param {Number} amount 羽化值
   */
  async featherSelection(amount) {
    if (!this.selectionObject) return false;

    // 更新羽化值
    this.featherAmount = amount;

    // 更新选区外观
    return this.updateSelectionAppearance();
  }

  /**
   * 检查对象是否在选区内
   * @param {Object} object 要检查的对象
   * @returns {Boolean} 是否在选区内
   */
  isObjectInSelection(object) {
    if (!this.selectionObject || !object) return false;

    // 获取对象的边界框
    const bounds = object.getBoundingRect();
    const { left, top, width, height } = bounds;

    // 检查对象的中心点和四个角是否在选区内
    const centerX = left + width / 2;
    const centerY = top + height / 2;

    // 检查中心点
    if (this.isPointInSelection(centerX, centerY)) return true;

    // 检查四个角
    if (this.isPointInSelection(left, top)) return true;
    if (this.isPointInSelection(left + width, top)) return true;
    if (this.isPointInSelection(left, top + height)) return true;
    if (this.isPointInSelection(left + width, top + height)) return true;

    return false;
  }

  /**
   * 检查点是否在选区内
   * @param {Number} x X坐标
   * @param {Number} y Y坐标
   * @returns {Boolean} 是否在选区内
   */
  isPointInSelection(x, y) {
    if (!this.selectionObject) return false;

    // 使用fabric.js的containsPoint方法判断点是否在选区内
    return this.selectionObject.containsPoint({ x, y });
  }

  /**
   * 开始自由选区
   * @param {Object} options 事件对象
   */
  startFreeSelection(options) {
    if (!this.canvas || !this.isActive) return;

    // 获取鼠标位置
    const pointer = this.canvas.getPointer(options.e);
    this.startPoint = pointer;

    // 创建用于绘制轨迹的点数组
    this.drawingPoints = [pointer];

    // 初始化SVG路径字符串
    this.currentPathString = `M ${pointer.x} ${pointer.y}`;

    // 创建临时路径对象用于实时显示
    this.drawingObject = new fabric.Path(this.currentPathString, {
      stroke: this.selectionStyle.stroke,
      strokeWidth: this.selectionStyle.strokeWidth,
      strokeDashArray: this.selectionStyle.strokeDashArray,
      fill: "transparent",
      selectable: false,
      evented: false,
      strokeLineCap: "round",
      strokeLineJoin: "round",
    });

    // 添加到画布
    this.canvas.add(this.drawingObject);
    this.canvas.renderAll();
  }

  /**
   * 绘制自由选区
   * @param {Object} options 事件对象
   */
  drawFreeSelection(options) {
    if (!this.drawingObject || !this.drawingPoints || !this.isActive) return;

    // 获取鼠标位置
    const pointer = this.canvas.getPointer(options.e);

    // 添加新的点，但避免添加过于密集的点
    const lastPoint = this.drawingPoints[this.drawingPoints.length - 1];
    const distance = Math.sqrt(
      Math.pow(pointer.x - lastPoint.x, 2) + Math.pow(pointer.y - lastPoint.y, 2)
    );

    // 只有当距离大于2像素时才添加新点，避免路径过于复杂
    if (distance > 2) {
      this.drawingPoints.push(pointer);

      // 更新路径字符串
      this.currentPathString += ` L ${pointer.x} ${pointer.y}`;

      // 移除旧的绘制对象
      this.canvas.remove(this.drawingObject);

      // 创建新的路径对象
      this.drawingObject = new fabric.Path(this.currentPathString, {
        stroke: this.selectionStyle.stroke,
        strokeWidth: this.selectionStyle.strokeWidth,
        strokeDashArray: this.selectionStyle.strokeDashArray,
        fill: "transparent",
        selectable: false,
        evented: false,
        strokeLineCap: "round",
        strokeLineJoin: "round",
      });

      // 重新添加到画布
      this.canvas.add(this.drawingObject);
      this.canvas.renderAll();
    }
  }

  /**
   * 结束自由选区
   */
  endFreeSelection() {
    if (!this.drawingObject || !this.drawingPoints || !this.isActive) return;

    // 检查是否有足够的点来形成选区
    if (this.drawingPoints.length < 3) {
      // 点太少，清除绘制对象
      this.canvas.remove(this.drawingObject);
      this.drawingObject = null;
      this.drawingPoints = null;
      this.startPoint = null;
      this.currentPathString = null;
      return;
    }

    // 自动闭合路径 - 连接最后一点到第一点
    const firstPoint = this.drawingPoints[0];
    const lastPoint = this.drawingPoints[this.drawingPoints.length - 1];
    const closingDistance = Math.sqrt(
      Math.pow(firstPoint.x - lastPoint.x, 2) + Math.pow(firstPoint.y - lastPoint.y, 2)
    );

    // 如果首尾距离较大，自动添加闭合线段
    let finalPathString = this.currentPathString;
    if (closingDistance > 10) {
      finalPathString += ` L ${firstPoint.x} ${firstPoint.y}`;
    }
    finalPathString += " Z"; // 闭合路径

    // 创建最终选区对象
    const selectionObj = new fabric.Path(finalPathString, {
      ...this.selectionStyle,
      id: `selection_${Date.now()}`,
      name: "selection",
      fill: this.selectionStyle.fill, // 恢复填充
    });

    // 移除绘制中的临时对象
    this.canvas.remove(this.drawingObject);

    // 重置绘制状态
    this.drawingObject = null;
    this.drawingPoints = null;
    this.startPoint = null;
    this.currentPathString = null;

    // 设置选区
    this.setSelectionObject(selectionObj);
  }

  /**
   * 开始矩形选区
   * @param {Object} options 事件对象
   */
  startRectangleSelection(options) {
    if (!this.canvas || !this.isActive) return;

    // 获取鼠标位置
    const pointer = this.canvas.getPointer(options.e);
    this.startPoint = pointer;

    // 创建矩形对象
    this.drawingObject = new fabric.Rect({
      left: pointer.x,
      top: pointer.y,
      width: 0,
      height: 0,
      ...this.selectionStyle,
      fill: "transparent", // 在绘制过程中不显示填充
    });

    // 添加到画布
    this.canvas.add(this.drawingObject);
    this.canvas.renderAll();
  }

  /**
   * 绘制矩形选区
   * @param {Object} options 事件对象
   */
  drawRectangleSelection(options) {
    if (!this.drawingObject || !this.startPoint || !this.isActive) return;

    // 获取鼠标位置
    const pointer = this.canvas.getPointer(options.e);

    // 计算宽度和高度
    const width = Math.abs(pointer.x - this.startPoint.x);
    const height = Math.abs(pointer.y - this.startPoint.y);

    // 确定左上角坐标
    const left = Math.min(this.startPoint.x, pointer.x);
    const top = Math.min(this.startPoint.y, pointer.y);

    // 更新矩形
    this.drawingObject.set({
      left: left,
      top: top,
      width: width,
      height: height,
    });

    this.canvas.renderAll();
  }

  /**
   * 结束矩形选区
   */
  endRectangleSelection() {
    if (!this.drawingObject || !this.startPoint || !this.isActive) return;

    // 将矩形转换为路径
    const left = this.drawingObject.left;
    const top = this.drawingObject.top;
    const width = this.drawingObject.width;
    const height = this.drawingObject.height;

    // 如果矩形太小，忽略
    if (width < 5 || height < 5) {
      this.canvas.remove(this.drawingObject);
      this.drawingObject = null;
      this.startPoint = null;
      return;
    }

    // 创建矩形路径字符串
    const pathString = `M ${left} ${top} L ${left + width} ${top} L ${
      left + width
    } ${top + height} L ${left} ${top + height} Z`;

    // 创建最终选区对象
    const selectionObj = new fabric.Path(pathString, {
      ...this.selectionStyle,
      id: `selection_${Date.now()}`,
      name: "selection",
      fill: this.selectionStyle.fill, // 恢复填充
    });

    // 移除绘制中的临时对象
    this.canvas.remove(this.drawingObject);

    // 重置绘制状态
    this.drawingObject = null;
    this.startPoint = null;

    // 设置选区
    this.setSelectionObject(selectionObj);
  }

  /**
   * 开始椭圆选区
   * @param {Object} options 事件对象
   */
  startEllipseSelection(options) {
    if (!this.canvas || !this.isActive) return;

    // 获取鼠标位置
    const pointer = this.canvas.getPointer(options.e);
    this.startPoint = pointer;

    // 创建椭圆对象
    this.drawingObject = new fabric.Ellipse({
      left: pointer.x,
      top: pointer.y,
      rx: 0,
      ry: 0,
      ...this.selectionStyle,
      fill: "transparent", // 在绘制过程中不显示填充
      // originX: "left",
      // originY: "top",
      originX: "center",
      originY: "center",
    });

    // 添加到画布
    this.canvas.add(this.drawingObject);
    this.canvas.renderAll();
  }

  /**
   * 绘制椭圆选区
   * @param {Object} options 事件对象
   */
  drawEllipseSelection(options) {
    if (!this.drawingObject || !this.startPoint || !this.isActive) return;

    // 获取鼠标位置
    const pointer = this.canvas.getPointer(options.e);

    // 计算半径
    const rx = Math.abs(pointer.x - this.startPoint.x) / 2;
    const ry = Math.abs(pointer.y - this.startPoint.y) / 2;

    // 确定中心坐标
    const left = Math.min(this.startPoint.x, pointer.x);
    const top = Math.min(this.startPoint.y, pointer.y);

    // 更新椭圆
    this.drawingObject.set({
      left: left,
      top: top,
      rx: rx,
      ry: ry,
      originX: "left",
      originY: "top",
    });

    this.canvas.renderAll();
  }

  /**
   * 结束椭圆选区
   */
  endEllipseSelection() {
    if (!this.drawingObject || !this.startPoint || !this.isActive) return;

    // 获取椭圆参数
    const { left, top, rx, ry } = this.drawingObject;

    // 如果椭圆太小，忽略
    if (rx < 2 || ry < 2) {
      this.canvas.remove(this.drawingObject);
      this.drawingObject = null;
      this.startPoint = null;
      return;
    }

    // 计算中心点
    const cx = left + rx;
    const cy = top + ry;

    // 将椭圆转换为路径字符串
    const pathString = this.ellipseToSVGPath(cx, cy, rx, ry);

    // 创建最终选区对象
    const selectionObj = new fabric.Path(pathString, {
      ...this.selectionStyle,
      id: `selection_${Date.now()}`,
      name: "selection",
      fill: this.selectionStyle.fill, // 恢复填充
    });

    // 移除绘制中的临时对象
    this.canvas.remove(this.drawingObject);

    // 重置绘制状态
    this.drawingObject = null;
    this.startPoint = null;

    // 设置选区
    this.setSelectionObject(selectionObj);
  }

  /**
   * 将椭圆转换为SVG路径字符串
   * @param {Number} cx 中心点X坐标
   * @param {Number} cy 中心点Y坐标
   * @param {Number} rx X半径
   * @param {Number} ry Y半径
   * @returns {String} SVG路径字符串
   */
  ellipseToSVGPath(cx, cy, rx, ry) {
    // 使用椭圆弧命令创建完整椭圆
    return `M ${cx - rx} ${cy} A ${rx} ${ry} 0 1 0 ${
      cx + rx
    } ${cy} A ${rx} ${ry} 0 1 0 ${cx - rx} ${cy} Z`;
  }

  /**
   * 设置选区工具
   * @param {string} type 选区类型：OperationType.LASSO, OperationType.LASSO_RECTANGLE, OperationType.LASSO_ELLIPSE
   */
  setSelectionType(type) {
    this.selectionType = type;

    // 如果正在绘制，清除临时对象
    if (this.drawingObject) {
      this.canvas.remove(this.drawingObject);
      this.drawingObject = null;
      this.startPoint = null;
    }
  }

  /**
   * 设置选区工具的鼠标事件
   */
  setupSelectionEvents() {
    // 选区事件现在通过 setCurrentTool 方法管理
    // 这个方法现在主要用于刷新或重置事件监听
    if (!this.canvas || !this.isActive) return;

    // 确保选区处于激活状态
    if (this.selectionTools.includes(this.currentTool)) {
      this.isActive = true;
      // 如果事件还没有初始化，初始化它们
      if (!this._mouseDownHandler) {
        this.initEvents();
      }
    }
  }

  /**
   * 清理资源
   */
  dispose() {
    this.cleanupEvents();
    this.clearSelection();
    this.canvas = null;
    this.commandManager = null;
    this.layerManager = null;
  }
}
