new Vue({
  el: '#app',

  data: {
    currentTheme: 'light',
    language: 'zh-CN',
    languageData: {},

    thumbnailPath: '',
    forceRender: false,
    initialColor: '#ff0000',
    initialTrans: 'rgb(255, 255, 255, 0.5)',
    hexPicker: null,
    rgbPicker: null,
    hslPicker: null,
    transPicker: null,
    linkSize: true,
    aspectRatio: 1,
    alphaValue: 1,
    transValue: 100,
    redValue: 0,
    greenValue: 0,
    blueValue: 0,
    hueValue: 0,
    saturationValue: 0,
    lightnessValue: 0,
    deltas: [],
    hexString: '',
    rgbString: '',
    rgbaString: '',
    hslString: '',
    hslValue: 'hsl(0, 0, 0)',
    dynamicColor: 'rgba(255, 0, 0, 0.5)',
    overlayStyles: [],

    material: {
      itemName: 'Default',
      itemPath: 'Default',
      thumbnailPath: 'Default',
      itemType: 'solid_true@material',
      itemColor: [164, 178, 187, 0.0],
      itemDeltas: [0.0, 0.0, 0.0],
      itemSize: '-',
    },

    texture: {
      textureUnit: 'mm',
      fileName: '',
      textureWidth: '',
      textureHeight: '',
    },
    textured: false,
    texturedColorized: true, // Should be true as default
    colorized: false,
    isUpdatingFromSketchUp: false, // Flag to prevent unwanted callback when updating from SketchUp
  },

  mounted() {
    sketchup.ready();

    this.updateMateriaInfo(this.material);

    // 语言由 Ruby ready 回调推送

    // Theme
    const savedTheme = localStorage.getItem(themeKey) || "light";
    this.currentTheme = savedTheme;
    applyTheme(savedTheme);

    handleTooltip(this);
  },

  watch: {
    'material.itemColor': function (newColor) {
      this.redValue = newColor[0];
      this.greenValue = newColor[1];
      this.blueValue = newColor[2];
      this.alphaValue = newColor[3];
      this.transValue = Math.round(this.alphaValue * 100);

      this.rgbString = `rgb(${this.redValue}, ${this.greenValue}, ${this.blueValue})`
      this.rgbaString = `rgba(${this.redValue}, ${this.greenValue}, ${this.blueValue}, ${this.alphaValue})`
      this.initialTrans = this.rgbaString;
      this.dynamicColor = this.rgbaString;

      const hexValues = this.rgbToHex(this.redValue, this.greenValue, this.blueValue);
      this.initialColor = hexValues;
      this.hexString = hexValues;

      const hslValues = this.rgbaToHsl(this.rgbaString);
      this.hueValue = hslValues.hue;
      this.saturationValue = hslValues.saturation;
      this.lightnessValue = hslValues.lightness;
      this.hslString = hslValues.hslString;

      // Update for Color Picker
      if (this.hexPicker && this.hexPicker.color.hexString !== newColor) {
        this.hexPicker.color.set(this.initialColor);
        this.texturedColorized = true;
      }
      if (this.rgbPicker && this.rgbPicker.color.hexString !== newColor) {    
        this.rgbPicker.color.set(this.initialColor);
        this.texturedColorized = true;
      }
      if (this.hslPicker && this.hslPicker.color.hexString !== newColor) {
        this.hslPicker.color.set(this.initialColor);
        this.texturedColorized = true;
      }
      if (this.pickerTrans && this.pickerTrans.color.rgbaString !== newColor) {
        this.pickerTrans.color.set(this.initialTrans);
      }
    }
  },

  methods: {
    applyPluginLanguage(lang) {
      if (!lang || lang === this.language) {
        if (lang && Object.keys(this.languageData).length === 0) {
          loadLanguage(this);
        }
        return;
      }
      this.language = lang;
      loadLanguage(this);
      handleTooltip(this);
    },

    translated(key) {
      return this.languageData[key] || key;
    },

    switchTheme() {
      const newTheme = this.currentTheme === 'light' ? 'dark' : 'light';
      applyTheme(newTheme);
      this.currentTheme = newTheme;
    },

    createMaterial() {
      sketchup.createMaterial(this.rgbString, this.alphaValue);
    },

    duplicateMaterial() {
      sketchup.duplicateMaterial(this.material.itemPath);
    },

    pickMaterial() {
      sketchup.pickMaterial();
    },

    paintMaterial() {
      sketchup.paintMaterial(this.material.itemName);
    },

    saveOldValue(event) {
      // Save the current name when the input is focused
      this.material.oldName = this.material.itemName.trim();

      // Select all content
      event.target.select();
    },

    // Save new item name
    renameMaterial() {
      const oldName = this.material.oldName;
      const newName = this.material.itemName.trim(); // Get the updated name from input field

      if (newName === '' || newName === oldName) {
        // If the new name is empty or the same as old name, revert to old name
        this.material.itemName = oldName;
        return;
      }

      // Update material name
      this.material.itemName = newName;

      // Create an array to pass to SketchUp
      const item = [
        this.material.itemPath,
        oldName,
        newName,
        'material',
        this.material.thumbnailPath
      ];

      // Blur the input field after rename is complete
      this.$refs.materialNameInput.blur();

      // Call SketchUp method to rename material
      sketchup.renameMaterial(item);
    },

    editTexture(type, value) {
      if (type === 'size') {
        const textureWidth = document.getElementById('textureWidth');
        const textureHeight = document.getElementById('textureHeight');
        widthValue = textureWidth.value;
        heightValue = textureHeight.value;
        value = [widthValue, heightValue];
      } else if (type === 'reset') {
        this.dynamicColor = 'rgba(255, 255, 255, 1.0)';
      }

      sketchup.editTexture(this.material.itemName, type, value, this.texture.fileName);
    },

    // Direction: 'horizontal' or 'vertical'
    flipTextures(type, direction) {
      sketchup.flipTextures(this.material.itemName, type, direction);
    },

    // Direction: 'cw' or 'ccw'
    rotateTexture(type, direction) {
      sketchup.rotateTextures(this.material.itemName, type, direction);
    },

    updateMateriaInfo(inputData) {
      this.isUpdatingFromSketchUp = true; // Set flag to prevent callback

      this.material = inputData;
      this.textured = this.material.itemType.includes('textured');
      this.texturedColorized = this.material.itemType.includes('colorized');
      this.colorized = this.material.itemType.includes('true');
      this.thumbnailPath = this.material.thumbnailPath;

      this.redValue = this.material.itemColor[0];
      this.greenValue = this.material.itemColor[1];
      this.blueValue = this.material.itemColor[2];
      this.alphaValue = this.material.itemColor[3];
      this.transValue = Math.round(this.alphaValue * 100);

      this.rgbString = `rgb(${this.redValue}, ${this.greenValue}, ${this.blueValue})`
      this.rgbaString = `rgba(${this.redValue}, ${this.greenValue}, ${this.blueValue}, ${this.alphaValue})`
      this.dynamicColor = this.rgbString;
      this.initialTrans = this.rgbaString;

      const hexValues = this.rgbToHex(this.redValue, this.greenValue, this.blueValue);
      this.initialColor = hexValues;
      this.hexString = hexValues;

      const hslValues = this.rgbaToHsl(this.rgbaString);
      this.hueValue = hslValues.hue;
      this.saturationValue = hslValues.saturation;
      this.lightnessValue = hslValues.lightness;
      this.hslString = hslValues.hslString;

      if (this.hexPicker) {
        this.hexPicker.color.hexString = this.initialColor;
        this.pickerTrans.color.set(this.initialTrans);
      } else {
        this.initHexPicker();
        this.initTransPicker();
      }

      if (this.rgbPicker) {
        this.rgbPicker.color.hexString = this.initialColor;
      } else {
        this.initRgbPicker();
      }

      if (this.hslPicker) {
        this.hslPicker.color.hexString = this.initialColor;
      } else {
        this.initHslPicker();
      }

      // Reset canvas and overlay when material is solid (no texture)
      if (!this.textured) {
        this.overlayStyles = {
          position: 'absolute',
          top: 0,
          left: 0,
          width: '100%',
          height: '100%',
        };
        
        // Clear canvas
        const canvas = document.getElementById('textureCanvas');
        if (canvas) {
          const ctx = canvas.getContext('2d');
          ctx.clearRect(0, 0, canvas.width, canvas.height);
        }
      }

      // Reset flag after Vue finishes rendering
      this.$nextTick(() => {
        this.isUpdatingFromSketchUp = false;
      });
    },

    updateTextureInfo(data, type) {
      this.texture = data;
      this.forceRender = (type === 'load' || type === 'colorized' || type === 'flip' || type === 'rotate');
      this.updateAspectRatio();

      // Force refresh canvas when texture is changed (flip/rotate/load)
      if (this.forceRender && this.textured) {
        this.updateCanvas();
      }
    },

    updateColorizedDeltas(data) {
      this.deltas = data;
      if (this.textured) {
        this.updateCanvas();
      } else {
        this.overlayStyles = {
          position: 'absolute',
          top: 0,
          left: 0,
          width: `100%`,
          height: `100%`,
        };
      }
    },

    updateCanvas() {
      const img = new Image();

      const basePath = (this.thumbnailPath || '').split('?')[0];
      const url = window.fileUrlFromPath ? window.fileUrlFromPath(basePath) : ('file:///' + (basePath || '').replace(/\\/g, '/'));
      if (this.forceRender) {
        img.src = url + (url.indexOf('?') >= 0 ? '&' : '?') + 't=' + new Date().getTime();
      } else {
        img.src = url;
      }

      img.onload = function() {
        const canvas = document.getElementById('textureCanvas');
        const ctx = canvas.getContext('2d', { willReadFrequently: true });

        const canvasWidth = canvas.width;
        const canvasHeight = canvas.height;
        const imgWidth = img.width;
        const imgHeight = img.height;

        // Handle ratio
        const imgRatio = imgWidth / imgHeight;
        const canvasRatio = canvasWidth / canvasHeight;

        let drawWidth, drawHeight;

        // Check ratio and adjust dimension
        if (imgRatio > canvasRatio) {
          drawWidth = canvasWidth;
          drawHeight = canvasWidth / imgRatio;
        } else {
          drawHeight = canvasHeight;
          drawWidth = canvasHeight * imgRatio;
        }

        // Calculate position to center image
        const x = (canvasWidth - drawWidth) / 2;
        const y = (canvasHeight - drawHeight) / 2;

        // Calculate for overlay
        const leftPercent = (x / canvasWidth) * 100;
        const topPercent = (y / canvasHeight) * 100;
        const widthPercent = (drawWidth / canvasWidth) * 100;
        const heightPercent = (drawHeight / canvasHeight) * 100;
        this.overlayStyles = {
          position: 'absolute',
          top: `${topPercent}%`,
          left: `${leftPercent}%`,
          width: `${widthPercent}%`,
          height: `${heightPercent}%`,
        };

        // Draw image into canvas at position
        ctx.clearRect(0, 0, canvasWidth, canvasHeight);
        ctx.drawImage(img, x, y, drawWidth, drawHeight);

        // Get image data from canvas
        let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
        let data = imageData.data;

        // Get HSL deltas from SketchUp
        // Check if deltas array is valid before accessing
        if (!this.deltas || this.deltas.length < 3) {
          return;
        }

        const deltaH = this.deltas[0] || 0;
        const deltaS = Math.round((this.deltas[1] || 0) * 100);
        const deltaL = Math.round((this.deltas[2] || 0) * 100);

        if (deltaH === 0 && deltaS === 0 && deltaL === 0) {
          return;
        }

        for (let i = 0; i < data.length; i += 4) {
          let [r, g, b, a] = [data[i], data[i + 1], data[i + 2], data[i + 3]];

          // Convert from RGBA to HSL
          let { hue: h, saturation: s, lightness: l } = this.rgbaToHsl(`rgba(${r}, ${g}, ${b}, ${a})`);

          // Apply deltas from SketchUp
          if (this.colorized) {
            // Colorize ON: Replace Hue with deltaH
            h = deltaH;
            if (h < 0) h += 360;
          } else {
            // Colorize OFF: Add deltaH to original Hue
            h = h + deltaH;
            // Ensure Hue is in range 0-360 (handle negative values)
            h = ((h % 360) + 360) % 360;
          }

          l = Math.max(0, Math.min(100, l + deltaL));
          s = Math.max(0, Math.min(100, s + deltaS));

          // Convert back from HSL to RGB (chia saturation và lightness cho 100)
          let { r: newR, g: newG, b: newB } = this.hslToRgb(h, s, l);

          // Update RGB values for image data
          data[i] = newR;
          data[i + 1] = newG;
          data[i + 2] = newB;
        }

        // Update image on canvas
        ctx.putImageData(imageData, 0, 0);
      }.bind(this);
    },

    selectContent(event) {
      const input = event.target;

      if (input.value.startsWith('#') && input.value.length === 7) {
        input.setSelectionRange(1, 7);
      } else {
        input.select();
      }
    },

    initHexPicker() {
      this.hexPicker = new iro.ColorPicker("#hexPicker", {
        width: 86,
        color: this.initialColor,
        layoutDirection: 'horizontal',
        layout: [
          {
            component: iro.ui.Wheel,
            options: {
              sliderType: 'value',
              borderWidth: 0
            }
          },
          {
            component: iro.ui.Slider,
            options: {
              sliderType: 'value',
              sliderSize: 15,
              borderWidth: 1,
              borderColor: "#e1e1e1"
            }
          },
        ]
      });

      this.hexPicker.on('color:change', (color) => {
        this.updateColorValues(color, 'hex');
        // Only call sketchup when user changes color, not when updating from SketchUp
        if (!this.isUpdatingFromSketchUp) {
          sketchup.changeColor(this.material.itemName, this.hexString, this.colorized);
        }
      });
    },

    initRgbPicker() {
      this.rgbPicker = new iro.ColorPicker("#rgbPicker", {
        width: 140,
        color: this.initialColor,
        borderWidth: 1,
        borderColor: "#e1e1e1",
        layout: [
          {
            component: iro.ui.Slider,
            layoutDirection: 'horizontal',
            options: {
              sliderType: 'red',
              sliderSize: 15,
            }
          },
          {
            component: iro.ui.Slider,
            layoutDirection: 'horizontal',
            options: {
              sliderType: 'green',
              sliderSize: 15,
            }
          },
          {
            component: iro.ui.Slider,
            layoutDirection: 'horizontal',
            options: {
              sliderType: 'blue',
              sliderSize: 15,
            }
          },
        ]
      });

      this.rgbPicker.on('color:change', (color) => {
        this.updateColorValues(color, 'rgb');
      });
    },

    initHslPicker() {
      this.hslPicker = new iro.ColorPicker("#hslPicker", {
        width: 140,
        color: this.initialColor,
        borderWidth: 1,
        borderColor: "#e1e1e1",
        layout: [
          {
            component: iro.ui.Slider,
            layoutDirection: 'horizontal',
            options: {
              sliderType: 'hue',
              sliderSize: 15,
            }
          },
          {
            component: iro.ui.Slider,
            layoutDirection: 'horizontal',
            options: {
              sliderType: 'saturation',
              sliderSize: 15,
            }
          },
          {
            component: iro.ui.Slider,
            layoutDirection: 'horizontal',
            options: {
              sliderType: 'value',
              sliderSize: 15,
            }
          },
        ]
      });

      this.hslPicker.on('color:change', (color) => {
        this.updateColorValues(color, 'hsl');
      });
    },

    initTransPicker() {
      this.pickerTrans = new iro.ColorPicker("#transPicker", {
        width: 155,
        color: this.initialTrans,
        borderWidth: 1,
        borderColor: "#e1e1e1",
        layout: [
          {
            component: iro.ui.Slider,
            layoutDirection: 'horizontal',
            options: {
              sliderType: 'alpha',
              sliderSize: 20,
            }
          },
        ]
      });

      this.pickerTrans.on('color:change', (color) => {
        this.initialTrans = color.rgbaString;
        this.alphaValue = color.alpha;
        this.transValue = Math.round(this.alphaValue * 100);
        sketchup.changeAlpha(this.material.itemName, this.initialTrans);
      });
    },

    updateColorValues(color, picker) {
      this.hexString = color.hexString;
      this.rgbString = color.rgbString;
      this.redValue = color.rgb.r;
      this.greenValue = color.rgb.g;
      this.blueValue = color.rgb.b;

      this.hslString = color.hslString;
      this.hueValue = color.hsl.h;
      this.saturationValue = color.hsl.s;
      this.lightnessValueValue = color.hsl.l;

      // this.hslValue = this.hslString.replace('%', '').replace('%', '');
      this.initialTrans = `rgba(${this.redValue}, ${this.greenValue}, ${this.blueValue}, ${this.alphaValue})`

      // Update for Color Picker
      if (this.hexPicker && picker !== 'hex') {
        this.hexPicker.color.set(this.initialTrans);
        this.texturedColorized = true;
      }

      if (this.rgbPicker && picker !== 'rgb') {
        this.rgbPicker.color.set(this.initialTrans);
        this.texturedColorized = true;
      }

      if (this.hslPicker && picker !== 'hsl') {
        this.hslPicker.color.set(this.initialTrans);
        this.texturedColorized = true;
      }

      if (this.pickerTrans && this.pickerTrans.color.rgbaString !== this.initialTrans) {
        this.pickerTrans.color.set(this.initialTrans);
      }
    },

    unlink() {
      this.linkSize = !this.linkSize;
    },

    parseValue(value) {
      const match = value.match(/^([0-9.]+)\s*(\w*)$/);
      if (match) {
        return {
          number: parseFloat(match[1]),
          unit: match[2] || ''
        };
      }
      return { number: 0, unit: '' };
    },

    formatValue(number, unit) {
      return `${number} ${unit}`.trim();
    },

    onTextureWidthChange() {
      const { number: widthValue, unit: widthUnit } = this.parseValue(this.texture.textureWidth);

      if (this.linkSize) {
        const newHeightValue = (widthValue / this.aspectRatio).toFixed(0);
        this.texture.textureHeight = this.formatValue(newHeightValue, widthUnit);
      }

      this.updateAspectRatio();
    },

    onTextureHeightChange() {
      const { number: heightValue, unit: heightUnit } = this.parseValue(this.texture.textureHeight);

      if (this.linkSize) {
        const newWidthValue = (heightValue * this.aspectRatio).toFixed(0);
        this.texture.textureWidth = this.formatValue(newWidthValue, heightUnit);
      }

      this.updateAspectRatio();
    },

    updateAspectRatio() {
      const { number: widthValue } = this.parseValue(this.texture.textureWidth);
      const { number: heightValue } = this.parseValue(this.texture.textureHeight);

      if (widthValue > 0 && heightValue > 0) {
        this.aspectRatio = widthValue / heightValue;
      }
    },

    rgbaToHsl(rgbaString) {
      const rgbaMatch = rgbaString.match(/rgba?\((\d+),\s*(\d+),\s*(\d+),?\s*[\d\.]*\)/i);

      if (!rgbaMatch) {
        throw new Error("Invalid RGBA format");
      }

      let r = parseInt(rgbaMatch[1], 10) / 255;
      let g = parseInt(rgbaMatch[2], 10) / 255;
      let b = parseInt(rgbaMatch[3], 10) / 255;

      let max = Math.max(r, g, b), min = Math.min(r, g, b);
      let h, s, l = (max + min) / 2;

      if (max === min) {
        h = s = 0;
      } else {
        let delta = max - min;
        s = l > 0.5 ? delta / (2 - max - min) : delta / (max + min);
    
        switch (max) {
          case r:
            h = (g - b) / delta + (g < b ? 6 : 0);
            break;
          case g:
            h = (b - r) / delta + 2;
            break;
          case b:
            h = (r - g) / delta + 4;
            break;
        }

        h = Math.round(h * 60);
        if (h < 0) h += 360;
      }

      s = Math.round(s * 100);
      l = Math.round(l * 100);

      return {
        hue: h,
        saturation: s,
        lightness: l,
        hslString: `hsl(${h}, ${s}%, ${l}%)`,
      };
    },

    hslToRgb(h, s, l) {
      s /= 100;
      l /= 100;

      const c = (1 - Math.abs(2 * l - 1)) * s;
      const x = c * (1 - Math.abs((h / 60) % 2 - 1));
      const m = l - c / 2;
      let r = 0, g = 0, b = 0;

      if (h >= 0 && h < 60) {
        r = c; g = x; b = 0;
      } else if (h >= 60 && h < 120) {
        r = x; g = c; b = 0;
      } else if (h >= 120 && h < 180) {
        r = 0; g = c; b = x;
      } else if (h >= 180 && h < 240) {
        r = 0; g = x; b = c;
      } else if (h >= 240 && h < 300) {
        r = x; g = 0; b = c;
      } else if (h >= 300 && h < 360) {
        r = c; g = 0; b = x;
      }

      r = Math.round((r + m) * 255);
      g = Math.round((g + m) * 255);
      b = Math.round((b + m) * 255);

      return { r, g, b };
    },

    rgbToHex(r, g, b) {
      const toHex = (value) => {
        const hex = value.toString(16);
        return hex.length === 1 ? '0' + hex : hex;
      };

      return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
    },

    hexToRgb(hex) {
      // Clear '#' if any
      hex = hex.replace(/^#/, '');

      // Convert from 3 characters to 6 if any
      if (hex.length === 3) {
        hex = hex.split('').map(char => char + char).join('');
      }

      // Covert hex to rgb values
      const bigint = parseInt(hex, 16);
      const r = (bigint >> 16) & 255;
      const g = (bigint >> 8) & 255;
      const b = bigint & 255;

      // Return
      return {
        red: r,
        green: g,
        blue: b,
        rgbString: `rgb(${r}, ${g}, ${b})`,
      }
    },

    isValidHex(color) {
      const hexRegex = /^#[0-9A-Fa-f]{6}$/;
      return hexRegex.test(color);
    },

    validateAndUpdateValue(value, type) {
      if (type === 'hex') {
        if (this.isValidHex(value)) {
          const rgb = this.hexToRgb(value);

          this.redValue = rgb.red;
          this.greenValue = rgb.green;
          this.blueValue = rgb.blue;
          this.alphaValue = 1;
        }

      } else {
        // Convert value to integer
        let intValue = parseInt(value);

        // Define min and max base on (R, G, B, H, S, L, A)
        let min, max;

        if (type === 'red' || type === 'green' || type === 'blue') {
          min = 0;
          max = 255;
        } else if (type === 'hue') {
          min = 0;
          max = 359;
        } else if (type === 'saturation' || type === 'lightness') {
          min = 0;
          max = 100;
        } else if (type === 'alpha') {
          min = 0;
          max = 100;
        }

        // If input < min, set to min
        if (intValue < min) {
          intValue = min;
        }
  
        // If input > max, set to max
        if (intValue > max) {
          intValue = max;
        }

        // Update value base on input type
        if (type === 'red') {
          this.redValue = intValue;
        } else if (type === 'green') {
          this.greenValue = intValue;
        } else if (type === 'blue') {
          this.blueValue = intValue;
        } else if (type === 'hue') {
          this.hueValue = intValue;
        } else if (type === 'saturation') {
          this.saturationValue = intValue;
        } else if (type === 'lightness') {
          this.lightnessValue = intValue;
        } else if (type === 'alpha') {
          this.alphaValue = intValue / 100;
        }

        if (type === 'hue' || type === 'saturation' || type === 'lightness') {
          const rgb = this.hslToRgb(this.hueValue, this.saturationValue, this.lightnessValue);
          this.redValue = rgb.r;
          this.greenValue = rgb.g;
          this.blueValue = rgb.b;
        }
      }

      this.material.itemColor = [this.redValue, this.greenValue, this.blueValue, this.alphaValue];
    },
  },
});

function switchTheme(data) {
  document.getElementById('app').__vue__.switchTheme(data);
};

function applyPluginLanguage(lang) {
  document.getElementById('app').__vue__.applyPluginLanguage(lang);
};

function changeLanguage(data) {
  applyPluginLanguage(data);
};

function updateMateriaInfo(data) {
  document.getElementById('app').__vue__.updateMateriaInfo(data);
};

function updateTextureInfo(data, type) {
  document.getElementById('app').__vue__.updateTextureInfo(data, type);
};

function updateColorizedDeltas(data) {
  document.getElementById('app').__vue__.updateColorizedDeltas(data);
};