/**
 * 共通スタイルヘルパー関数
 * buttonBasic, textBasic 等の複数ブロックで使用
 */

/**
 * 色をRGBA形式に変換するヘルパー関数
 * @param {string} color - 色の値（hex, rgb, rgba, named color等）
 * @param {number} opacity - 不透明度（0-100）
 * @returns {string} RGBA形式の色
 */
export const convertToRgba = (color, opacity) => {
  const alpha = opacity / 100;

  if (color.startsWith("rgba(")) {
    return color.replace(/,\s*[\d.]+\)$/, `, ${alpha})`);
  }

  if (color.startsWith("rgb(")) {
    return color.replace("rgb(", "rgba(").replace(")", `, ${alpha})`);
  }

  if (color.startsWith("#")) {
    const hex = color.replace("#", "");
    const r = parseInt(hex.substr(0, 2), 16);
    const g = parseInt(hex.substr(2, 2), 16);
    const b = parseInt(hex.substr(4, 2), 16);
    return `rgba(${r}, ${g}, ${b}, ${alpha})`;
  }

  if (color === "transparent") {
    return "rgba(0, 0, 0, 0)";
  }

  const namedColors = {
    black: "rgba(0, 0, 0, " + alpha + ")",
    white: "rgba(255, 255, 255, " + alpha + ")",
    red: "rgba(255, 0, 0, " + alpha + ")",
    green: "rgba(0, 128, 0, " + alpha + ")",
    blue: "rgba(0, 0, 255, " + alpha + ")",
  };

  return namedColors[color] || `rgba(0, 0, 0, ${alpha})`;
};

/**
 * テキストシャドウの値を生成するヘルパー関数（通常状態）
 * @param {Object} attributes - ブロックの属性
 * @returns {string|undefined} CSS用のtext-shadow値
 */
export const getTextShadowValue = (attributes) => {
  if (!attributes.textShadowEnabled) return undefined;

  const offsetX = attributes.textShadowOffsetX || "0";
  const offsetXUnit = attributes.textShadowOffsetXUnit || "px";
  const offsetY = attributes.textShadowOffsetY || "0";
  const offsetYUnit = attributes.textShadowOffsetYUnit || "px";
  const blur = attributes.textShadowBlur || "1";
  const blurUnit = attributes.textShadowBlurUnit || "px";
  const color = attributes.textShadowColor || "#000000";
  // textShadowColorAlpha (0-1) を優先、なければ textShadowOpacity (0-100) をフォールバック
  const alpha = attributes.textShadowColorAlpha !== undefined
    ? attributes.textShadowColorAlpha
    : (attributes.textShadowOpacity !== undefined ? attributes.textShadowOpacity / 100 : 1);

  const colorWithOpacity = convertToRgba(color, alpha * 100);

  return `${offsetX}${offsetXUnit} ${offsetY}${offsetYUnit} ${blur}${blurUnit} ${colorWithOpacity}`;
};

/**
 * ホバー用のテキストシャドウ値を生成するヘルパー関数
 * @param {Object} attributes - ブロックの属性
 * @returns {string|undefined} CSS用のtext-shadow値
 */
export const getTextShadowValueHover = (attributes) => {
  if (!attributes.textShadowEnabledHover) return undefined;

  const offsetX = attributes.textShadowOffsetXHover || "0";
  const offsetXUnit = attributes.textShadowOffsetXUnitHover || "px";
  const offsetY = attributes.textShadowOffsetYHover || "0";
  const offsetYUnit = attributes.textShadowOffsetYUnitHover || "px";
  const blur = attributes.textShadowBlurHover || "1";
  const blurUnit = attributes.textShadowBlurUnitHover || "px";
  const color = attributes.textShadowColorHover || "#000000";
  // textShadowColorAlphaHover (0-1) を優先、なければ textShadowOpacityHover (0-100) をフォールバック
  const alpha = attributes.textShadowColorAlphaHover !== undefined
    ? attributes.textShadowColorAlphaHover
    : (attributes.textShadowOpacityHover !== undefined ? attributes.textShadowOpacityHover / 100 : 1);

  if (color.startsWith("#")) {
    const hex = color.replace("#", "");
    const r = parseInt(hex.substr(0, 2), 16);
    const g = parseInt(hex.substr(2, 2), 16);
    const b = parseInt(hex.substr(4, 2), 16);
    const colorWithOpacity = `rgba(${r}, ${g}, ${b}, ${alpha})`;
    return `${offsetX}${offsetXUnit} ${offsetY}${offsetYUnit} ${blur}${blurUnit} ${colorWithOpacity}`;
  }

  return `${offsetX}${offsetXUnit} ${offsetY}${offsetYUnit} ${blur}${blurUnit} ${color}`;
};

/**
 * ホバー用のフォントサイズ値を生成するヘルパー関数
 * @param {Object} attributes - ブロックの属性
 * @param {string} device - デバイス ("pc" | "tb" | "sp" | "md")
 * @returns {string|undefined} CSS用のfont-size値
 */
export const getFontSizeValueHover = (attributes, device) => {
  const fontSizeData = attributes.fontSizeV2Hover;
  if (fontSizeData && fontSizeData[device]) {
    const { preset, custom, unit } = fontSizeData[device];
    if (preset === 'custom' && custom && custom !== '') {
      return `${custom}${unit || 'px'}`;
    } else if (preset && preset !== '' && preset !== 'custom') {
      return `${preset}${unit || 'px'}`;
    }
  }

  return undefined;
};

/**
 * ホバー用のフォントウェイト値を生成するヘルパー関数
 * @param {Object} attributes - ブロックの属性
 * @param {string} device - デバイス ("pc" | "tb" | "sp" | "md")
 * @returns {string|undefined} CSS用のfont-weight値
 */
export const getFontWeightValueHover = (attributes, device) => {
  const fontWeightData = attributes.fontWeightV2Hover;
  if (!fontWeightData) return undefined;

  const breakpointOrder = ['pc', 'md', 'tb', 'sp'];
  const deviceIndex = breakpointOrder.indexOf(device);

  for (let i = deviceIndex; i >= 0; i--) {
    const bp = breakpointOrder[i];
    if (fontWeightData[bp] && fontWeightData[bp] !== '') {
      return fontWeightData[bp];
    }
  }

  return undefined;
};

/**
 * ホバー用の行間値を生成するヘルパー関数
 * @param {Object} attributes - ブロックの属性
 * @param {string} device - デバイス ("pc" | "tb" | "sp" | "md")
 * @returns {string|undefined} CSS用のline-height値
 */
export const getLineHeightValueHover = (attributes, device) => {
  const lineHeightData = attributes.lineHeightV2Hover;
  if (!lineHeightData) return undefined;

  const breakpointOrder = ['pc', 'md', 'tb', 'sp'];
  const deviceIndex = breakpointOrder.indexOf(device);

  for (let i = deviceIndex; i >= 0; i--) {
    const bp = breakpointOrder[i];
    if (lineHeightData[bp]) {
      const { value, unit } = lineHeightData[bp];
      if (value && value !== '') {
        return `${value}${unit || ''}`;
      }
    }
  }

  return undefined;
};

/**
 * ホバー用の文字間値を生成するヘルパー関数
 * @param {Object} attributes - ブロックの属性
 * @param {string} device - デバイス ("pc" | "tb" | "sp" | "md")
 * @returns {string|undefined} CSS用のletter-spacing値
 */
export const getLetterSpacingValueHover = (attributes, device) => {
  const letterSpacingData = attributes.letterSpacingV2Hover;
  if (!letterSpacingData) return undefined;

  const breakpointOrder = ['pc', 'md', 'tb', 'sp'];
  const deviceIndex = breakpointOrder.indexOf(device);

  for (let i = deviceIndex; i >= 0; i--) {
    const bp = breakpointOrder[i];
    if (letterSpacingData[bp]) {
      const { value, unit } = letterSpacingData[bp];
      if (value && value !== '') {
        return `${value}${unit || 'px'}`;
      }
    }
  }

  return undefined;
};

/**
 * 色文字列をRGBオブジェクトに変換するヘルパー関数
 * @param {string} color - 色の値（hex, rgb, rgba等）
 * @returns {{r: number, g: number, b: number, a: number}|null} RGBオブジェクト
 */
const parseColor = (color) => {
  if (!color) return null;

  color = color.trim();

  // hex形式
  if (color.startsWith("#")) {
    let hex = color.replace("#", "");
    if (hex.length === 3) {
      hex = hex.split("").map((c) => c + c).join("");
    }
    if (hex.length === 6) {
      return {
        r: parseInt(hex.slice(0, 2), 16),
        g: parseInt(hex.slice(2, 4), 16),
        b: parseInt(hex.slice(4, 6), 16),
        a: 1
      };
    }
    if (hex.length === 8) {
      return {
        r: parseInt(hex.slice(0, 2), 16),
        g: parseInt(hex.slice(2, 4), 16),
        b: parseInt(hex.slice(4, 6), 16),
        a: parseInt(hex.slice(6, 8), 16) / 255
      };
    }
  }

  // rgba形式
  const rgbaMatch = color.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+))?\s*\)/);
  if (rgbaMatch) {
    return {
      r: parseInt(rgbaMatch[1], 10),
      g: parseInt(rgbaMatch[2], 10),
      b: parseInt(rgbaMatch[3], 10),
      a: rgbaMatch[4] !== undefined ? parseFloat(rgbaMatch[4]) : 1
    };
  }

  return null;
};

/**
 * 2色間を線形補間する
 * @param {Object} color1 - 開始色 {r, g, b, a}
 * @param {Object} color2 - 終了色 {r, g, b, a}
 * @param {number} t - 補間係数（0-1）
 * @returns {Object} 補間された色 {r, g, b, a}
 */
const lerpColor = (color1, color2, t) => {
  return {
    r: Math.round(color1.r + (color2.r - color1.r) * t),
    g: Math.round(color1.g + (color2.g - color1.g) * t),
    b: Math.round(color1.b + (color2.b - color1.b) * t),
    a: color1.a + (color2.a - color1.a) * t
  };
};

/**
 * グラデーション文字列から指定したパーセンテージの色を取得する
 * @param {string} gradientStr - グラデーション文字列（例: "linear-gradient(135deg, #ff0000 0%, #00ff00 100%)"）
 * @param {number} targetPercent - 取得したい位置（0-100、デフォルト50）
 * @returns {string|null} RGBA形式の色、またはnull
 */
export const getGradientColorAtPosition = (gradientStr, targetPercent = 50) => {
  if (!gradientStr || typeof gradientStr !== 'string') return null;

  // カラーストップを抽出する正規表現
  // 例: "#ff0000 0%", "rgb(255,0,0) 50%", "rgba(0,0,0,0.5) 100%"
  const colorStopRegex = /(#[0-9a-fA-F]{3,8}|rgba?\([^)]+\))\s*(\d+(?:\.\d+)?%?)?/g;

  const stops = [];
  let match;

  while ((match = colorStopRegex.exec(gradientStr)) !== null) {
    const color = parseColor(match[1]);
    if (color) {
      let position = 0;
      if (match[2]) {
        position = parseFloat(match[2].replace('%', ''));
      }
      stops.push({ color, position });
    }
  }

  if (stops.length === 0) return null;
  if (stops.length === 1) {
    const c = stops[0].color;
    return `rgba(${c.r}, ${c.g}, ${c.b}, ${c.a})`;
  }

  // 位置が指定されていない場合、均等配分
  if (stops.every(s => s.position === 0)) {
    stops.forEach((s, i) => {
      s.position = (i / (stops.length - 1)) * 100;
    });
  }

  // 位置でソート
  stops.sort((a, b) => a.position - b.position);

  // targetPercentがストップの範囲外の場合
  if (targetPercent <= stops[0].position) {
    const c = stops[0].color;
    return `rgba(${c.r}, ${c.g}, ${c.b}, ${c.a})`;
  }
  if (targetPercent >= stops[stops.length - 1].position) {
    const c = stops[stops.length - 1].color;
    return `rgba(${c.r}, ${c.g}, ${c.b}, ${c.a})`;
  }

  // 補間する2つのストップを見つける
  for (let i = 0; i < stops.length - 1; i++) {
    if (targetPercent >= stops[i].position && targetPercent <= stops[i + 1].position) {
      const range = stops[i + 1].position - stops[i].position;
      const t = range === 0 ? 0 : (targetPercent - stops[i].position) / range;
      const interpolated = lerpColor(stops[i].color, stops[i + 1].color, t);
      return `rgba(${interpolated.r}, ${interpolated.g}, ${interpolated.b}, ${interpolated.a})`;
    }
  }

  return null;
};

const hexToRgbaForShadow = (hex, alpha = 1) => {
  if (!hex || hex === "transparent") {
    return `rgba(0, 0, 0, 0)`;
  }

  if (hex.startsWith("rgb")) {
    const match = hex.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
    if (match) {
      const r = parseInt(match[1], 10);
      const g = parseInt(match[2], 10);
      const b = parseInt(match[3], 10);
      return `rgba(${r}, ${g}, ${b}, ${alpha})`;
    }
    return hex;
  }

  hex = hex.replace("#", "");

  if (hex.length === 3) {
    hex = hex
      .split("")
      .map((c) => c + c)
      .join("");
  }

  const r = parseInt(hex.slice(0, 2), 16);
  const g = parseInt(hex.slice(2, 4), 16);
  const b = parseInt(hex.slice(4, 6), 16);

  return `rgba(${r}, ${g}, ${b}, ${alpha})`;
};

export const getTextShadowValueV2 = (shadowData, breakpoint = "pc") => {
  if (!shadowData || !shadowData[breakpoint]) return undefined;

  const bp = shadowData[breakpoint];
  const { offsetX, offsetY, blur, color, colorAlpha } = bp;

  if (!offsetX && !offsetY && !blur && !color) return undefined;

  const x = offsetX || "0";
  const y = offsetY || "0";
  const b = blur || "0";
  const c = color || "#000000";
  const alpha = colorAlpha !== "" && colorAlpha !== undefined ? colorAlpha : 1;

  const colorWithAlpha = hexToRgbaForShadow(c, alpha);

  return `${x}px ${y}px ${b}px ${colorWithAlpha}`;
};
