/**
 * WebGL版本的液化管理器   -  暂时不兼容WebGL的版本  后续看情况支持
 * 使用GPU加速进行高性能液化变形处理，支持持续按压效果
 */
export class LiquifyWebGLManager {
  constructor(options = {}) {
    this.config = {
      meshResolution: options.meshResolution || 64, // WebGL网格精度
      maxStrength: options.maxStrength || 100,
      useFloatTextures: options.useFloatTextures !== false, // 默认启用浮点纹理
    };

    this.params = {
      size: 50,
      pressure: 0.5,
      distortion: 0,
      power: 0.5,
    };

    this.modes = {
      PUSH: "push",
      CLOCKWISE: "clockwise",
      COUNTERCLOCKWISE: "counterclockwise",
      PINCH: "pinch",
      EXPAND: "expand",
      CRYSTAL: "crystal",
      EDGE: "edge",
      RECONSTRUCT: "reconstruct",
    };

    this.currentMode = this.modes.PUSH;
    this.initialized = false;

    // WebGL相关
    this.canvas = null;
    this.gl = null;
    this.program = null;
    this.meshBuffer = null;
    this.originalTexture = null;
    this.currentTexture = null;
    this.framebuffer = null;

    // 持续按压相关状态
    this.pressStartTime = 0;
    this.pressDuration = 0;
    this.accumulatedRotation = 0;
    this.accumulatedScale = 0;
    this.isHolding = false;
    this.continuousTimer = null;
    this.continuousApplyInterval = 50; // 50ms间隔

    // 初始点坐标
    this.initialMouseX = 0;
    this.initialMouseY = 0;
    this.isDragging = false;
  }

  /**
   * 检查WebGL支持
   */
  static isSupported() {
    try {
      const canvas = document.createElement("canvas");
      const gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
      return !!gl;
    } catch (e) {
      return false;
    }
  }

  /**
   * 初始化WebGL液化管理器
   */
  initialize(imageSource) {
    try {
      // 创建WebGL画布
      this.canvas = document.createElement("canvas");
      this.gl = this.canvas.getContext("webgl") || this.canvas.getContext("experimental-webgl");

      if (!this.gl) {
        throw new Error("WebGL不可用");
      }

      // 处理图像源
      if (imageSource instanceof HTMLImageElement) {
        this.canvas.width = imageSource.width;
        this.canvas.height = imageSource.height;
        this._initWebGL(imageSource);
      } else {
        throw new Error("WebGL版本目前只支持HTMLImageElement");
      }

      this.initialized = true;
      return true;
    } catch (error) {
      console.error("WebGL液化管理器初始化失败:", error);
      return false;
    }
  }

  /**
   * 初始化WebGL环境
   */
  _initWebGL(image) {
    const gl = this.gl;

    // 创建着色器程序
    this._createShaderProgram();

    // 创建纹理
    this.originalTexture = this._createTexture(image);
    this.currentTexture = this._createTexture(image);

    // 创建帧缓冲
    this.framebuffer = gl.createFramebuffer();

    // 创建网格缓冲
    this._createMeshBuffer();

    console.log("WebGL液化环境初始化完成");
  }

  /**
   * 创建着色器程序
   */
  _createShaderProgram() {
    const gl = this.gl;

    // 顶点着色器
    const vertexShaderSource = `
      attribute vec2 a_position;
      attribute vec2 a_texCoord;
      varying vec2 v_texCoord;
      void main() {
        gl_Position = vec4(a_position, 0.0, 1.0);
        v_texCoord = a_texCoord;
      }
    `;

    // 片段着色器 - 支持多种液化模式
    const fragmentShaderSource = `
      precision mediump float;
      uniform sampler2D u_texture;
      uniform vec2 u_center;
      uniform float u_radius;
      uniform float u_strength;
      uniform int u_mode;
      uniform float u_time;
      uniform float u_distortion;
      uniform vec2 u_dragVector;
      varying vec2 v_texCoord;

      void main() {
        vec2 coord = v_texCoord;
        vec2 center = u_center;
        float dist = distance(coord, center);
        
        if (dist < u_radius && dist > 0.0) {
          float factor = 1.0 - (dist / u_radius);
          factor = factor * factor * factor * u_strength;
          
          if (u_mode == 0) { // PUSH
            vec2 direction = normalize(u_dragVector);
            coord += direction * factor * 0.1;
          }
          else if (u_mode == 1 || u_mode == 2) { // CLOCKWISE/COUNTERCLOCKWISE
            float angle = atan(coord.y - center.y, coord.x - center.x);
            float rotationSpeed = u_mode == 1 ? 0.1 : -0.1;
            angle += rotationSpeed * factor * (1.0 + u_time * 0.001);
            coord = center + dist * vec2(cos(angle), sin(angle));
          }
          else if (u_mode == 3) { // PINCH
            vec2 direction = center - coord;
            coord += direction * factor * (0.5 + u_time * 0.0005);
          }
          else if (u_mode == 4) { // EXPAND
            vec2 direction = coord - center;
            coord += direction * factor * (0.5 + u_time * 0.0005);
          }
          else if (u_mode == 5) { // CRYSTAL
            float crystalAngle = atan(coord.y - center.y, coord.x - center.x);
            float wave1 = sin(crystalAngle * 8.0 + u_time * 0.005) * 0.6;
            float wave2 = cos(crystalAngle * 12.0 + u_time * 0.003) * 0.4;
            crystalAngle += (wave1 + wave2) * u_distortion * factor;
            coord = center + dist * vec2(cos(crystalAngle), sin(crystalAngle));
          }
          else if (u_mode == 6) { // EDGE
            float edgeAngle = atan(coord.y - center.y, coord.x - center.x);
            float edgeWave = sin(dist * 3.14159 * 4.0 + u_time * 0.004) *
                           cos(edgeAngle * 6.0 + u_time * 0.002);
            float perpAngle = edgeAngle + 3.14159 * 0.5;
            coord += vec2(cos(perpAngle), sin(perpAngle)) * edgeWave * factor * u_distortion * 0.5;
          }
        }
        
        gl_FragColor = texture2D(u_texture, coord);
      }
    `;

    this.program = this._createProgram(vertexShaderSource, fragmentShaderSource);
  }

  /**
   * 创建着色器
   */
  _createShader(type, source) {
    const gl = this.gl;
    const shader = gl.createShader(type);
    gl.shaderSource(shader, source);
    gl.compileShader(shader);

    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
      throw new Error("着色器编译失败: " + gl.getShaderInfoLog(shader));
    }

    return shader;
  }

  /**
   * 创建着色器程序
   */
  _createProgram(vertexSource, fragmentSource) {
    const gl = this.gl;
    const vertexShader = this._createShader(gl.VERTEX_SHADER, vertexSource);
    const fragmentShader = this._createShader(gl.FRAGMENT_SHADER, fragmentSource);

    const program = gl.createProgram();
    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragmentShader);
    gl.linkProgram(program);

    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
      throw new Error("程序链接失败: " + gl.getProgramInfoLog(program));
    }

    return program;
  }

  /**
   * 创建纹理
   */
  _createTexture(image) {
    const gl = this.gl;
    const texture = gl.createTexture();

    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);

    return texture;
  }

  /**
   * 创建网格缓冲
   */
  _createMeshBuffer() {
    const gl = this.gl;
    const vertices = new Float32Array([-1, -1, 0, 0, 1, -1, 1, 0, -1, 1, 0, 1, 1, 1, 1, 1]);

    this.meshBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, this.meshBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
  }

  /**
   * 设置液化模式
   */
  setMode(mode) {
    if (Object.values(this.modes).includes(mode)) {
      this.currentMode = mode;
      return true;
    }
    return false;
  }

  /**
   * 设置参数
   */
  setParam(param, value) {
    if (param in this.params) {
      this.params[param] = value;
      return true;
    }
    return false;
  }

  /**
   * 获取参数
   */
  getParams() {
    return { ...this.params };
  }

  /**
   * 开始液化操作
   */
  startDeformation(x, y) {
    this.initialMouseX = x;
    this.initialMouseY = y;
    this.isDragging = true;

    // 初始化持续按压状态
    this.pressStartTime = Date.now();
    this.pressDuration = 0;
    this.accumulatedRotation = 0;
    this.accumulatedScale = 0;
    this.isHolding = true;

    // 启动持续效果定时器
    // this.startContinuousEffect();

    console.log(`WebGL液化开始，初始点: (${x}, ${y})`);
  }

  /**
   * 结束液化操作
   */
  endDeformation() {
    this.isDragging = false;
    this.isHolding = false;
    this.pressStartTime = 0;
    this.pressDuration = 0;
    this.accumulatedRotation = 0;
    this.accumulatedScale = 0;

    // 停止持续效果定时器
    this.stopContinuousEffect();

    console.log("WebGL液化结束");
  }

  /**
   * 启动持续效果
   */
  startContinuousEffect() {
    this.stopContinuousEffect();

    this.continuousTimer = setInterval(() => {
      if (this.isHolding && this.initialized) {
        this.pressDuration = Date.now() - this.pressStartTime;
        this.applyContinuousDeformation();
      }
    }, this.continuousApplyInterval);
  }

  /**
   * 停止持续效果
   */
  stopContinuousEffect() {
    if (this.continuousTimer) {
      clearInterval(this.continuousTimer);
      this.continuousTimer = null;
    }
  }

  /**
   * 应用持续变形效果
   */
  applyContinuousDeformation() {
    if (!this.isHolding || !this.initialized) return;

    return this.applyDeformation(this.initialMouseX, this.initialMouseY);
  }

  /**
   * 应用液化变形
   */
  applyDeformation(x, y) {
    if (!this.initialized || !this.gl) return null;

    const gl = this.gl;
    const { size, pressure, power, distortion } = this.params;

    // 设置视口
    gl.viewport(0, 0, this.canvas.width, this.canvas.height);

    // 使用着色器程序
    gl.useProgram(this.program);

    // 绑定属性
    const positionLoc = gl.getAttribLocation(this.program, "a_position");
    const texCoordLoc = gl.getAttribLocation(this.program, "a_texCoord");

    gl.bindBuffer(gl.ARRAY_BUFFER, this.meshBuffer);
    gl.enableVertexAttribArray(positionLoc);
    gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 16, 0);
    gl.enableVertexAttribArray(texCoordLoc);
    gl.vertexAttribPointer(texCoordLoc, 2, gl.FLOAT, false, 16, 8);

    // 设置uniform变量
    const centerLoc = gl.getUniformLocation(this.program, "u_center");
    const radiusLoc = gl.getUniformLocation(this.program, "u_radius");
    const strengthLoc = gl.getUniformLocation(this.program, "u_strength");
    const modeLoc = gl.getUniformLocation(this.program, "u_mode");
    const timeLoc = gl.getUniformLocation(this.program, "u_time");
    const distortionLoc = gl.getUniformLocation(this.program, "u_distortion");
    const dragVectorLoc = gl.getUniformLocation(this.program, "u_dragVector");

    // 计算参数
    const centerX = x / this.canvas.width;
    const centerY = 1.0 - y / this.canvas.height; // WebGL坐标系Y轴翻转
    const radius = (size / Math.max(this.canvas.width, this.canvas.height)) * 2;

    // 计算强度，考虑持续按压效果
    let strength = pressure * power;
    if (this.isHolding) {
      const timeFactor = Math.min(this.pressDuration / 1000, 3.0);
      if (this.currentMode === this.modes.PUSH) {
        strength *= 0.2 + timeFactor * 0.3;
      } else {
        strength *= 0.5 + timeFactor * 0.5;
      }
    }

    // 计算拖拽向量（用于推拉模式）
    const dragX = this.isDragging ? (x - this.initialMouseX) / this.canvas.width : 0;
    const dragY = this.isDragging ? -(y - this.initialMouseY) / this.canvas.height : 0;

    // 获取模式索引
    const modeIndex = Object.values(this.modes).indexOf(this.currentMode);

    // 设置uniform值
    gl.uniform2f(centerLoc, centerX, centerY);
    gl.uniform1f(radiusLoc, radius);
    gl.uniform1f(strengthLoc, strength);
    gl.uniform1i(modeLoc, modeIndex);
    gl.uniform1f(timeLoc, this.pressDuration);
    gl.uniform1f(distortionLoc, distortion);
    gl.uniform2f(dragVectorLoc, dragX, dragY);

    // 绑定纹理
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, this.currentTexture);
    gl.uniform1i(gl.getUniformLocation(this.program, "u_texture"), 0);

    // 渲染到帧缓冲
    gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
    gl.framebufferTexture2D(
      gl.FRAMEBUFFER,
      gl.COLOR_ATTACHMENT0,
      gl.TEXTURE_2D,
      this.currentTexture,
      0
    );

    // 绘制
    gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

    // 读取结果并转换为ImageData
    const pixels = new Uint8Array(this.canvas.width * this.canvas.height * 4);
    gl.readPixels(0, 0, this.canvas.width, this.canvas.height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);

    // 翻转Y轴以匹配ImageData格式
    const flippedPixels = new Uint8ClampedArray(pixels.length);
    for (let y = 0; y < this.canvas.height; y++) {
      for (let x = 0; x < this.canvas.width; x++) {
        const srcIndex = ((this.canvas.height - 1 - y) * this.canvas.width + x) * 4;
        const dstIndex = (y * this.canvas.width + x) * 4;
        flippedPixels[dstIndex] = pixels[srcIndex];
        flippedPixels[dstIndex + 1] = pixels[srcIndex + 1];
        flippedPixels[dstIndex + 2] = pixels[srcIndex + 2];
        flippedPixels[dstIndex + 3] = pixels[srcIndex + 3];
      }
    }

    return new ImageData(flippedPixels, this.canvas.width, this.canvas.height);
  }

  /**
   * 重置到原始状态
   */
  reset() {
    if (!this.initialized) return null;

    const gl = this.gl;

    // 将原始纹理复制到当前纹理
    gl.bindTexture(gl.TEXTURE_2D, this.currentTexture);
    gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, this.canvas.width, this.canvas.height, 0);

    // 读取原始纹理数据
    gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
    gl.framebufferTexture2D(
      gl.FRAMEBUFFER,
      gl.COLOR_ATTACHMENT0,
      gl.TEXTURE_2D,
      this.originalTexture,
      0
    );

    const pixels = new Uint8Array(this.canvas.width * this.canvas.height * 4);
    gl.readPixels(0, 0, this.canvas.width, this.canvas.height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);

    return new ImageData(new Uint8ClampedArray(pixels), this.canvas.width, this.canvas.height);
  }

  /**
   * 重置参数为默认值
   */
  resetParams() {
    this.params = {
      size: 50,
      pressure: 0.5,
      distortion: 0,
      power: 0.5,
    };
  }

  /**
   * 释放资源
   */
  dispose() {
    if (this.gl) {
      if (this.program) this.gl.deleteProgram(this.program);
      if (this.meshBuffer) this.gl.deleteBuffer(this.meshBuffer);
      if (this.originalTexture) this.gl.deleteTexture(this.originalTexture);
      if (this.currentTexture) this.gl.deleteTexture(this.currentTexture);
      if (this.framebuffer) this.gl.deleteFramebuffer(this.framebuffer);
    }

    this.stopContinuousEffect();
    this.initialized = false;
    this.canvas = null;
    this.gl = null;

    console.log("WebGL液化管理器资源已释放");
  }
}
