/**
 * CustomBoxShadow - Block editor drop-shadow + hover-shadow controls
 *
 * Adds a "Shadow" panel under the Inspector "styles" group on shadow-supporting
 * blocks (and core/avatar, core/paragraph, core/heading, woocommerce/product-button).
 * Two pickers: Drop shadow (writes style.shadow / --box-shadow) and Hover drop
 * shadow (writes style.hoverShadow / --hover-box-shadow).
 *
 * Single file by design: matches HoverSettings/AutoHoverColor convention.
 * No build step, no imports — consumes wp.* globals only.
 */
(function () {
  var el = wp.element.createElement;
  var Fragment = wp.element.Fragment;
  var useState = wp.element.useState;
  var useMemo = wp.element.useMemo;
  var __ = wp.i18n.__;
  var addFilter = wp.hooks.addFilter;
  var createHigherOrderComponent = wp.compose.createHigherOrderComponent;
  var hasBlockSupport = wp.blocks.hasBlockSupport;

  var InspectorControls = wp.blockEditor.InspectorControls;
  var useSetting = wp.blockEditor.useSetting;

  var PanelBody = wp.components.PanelBody;
  var Button = wp.components.Button;
  var FlexItem = wp.components.FlexItem;
  var Dropdown = wp.components.Dropdown;
  var ColorPalette = wp.components.ColorPalette;
  var VStack = wp.components.__experimentalVStack;
  var HStack = wp.components.__experimentalHStack;
  var DropdownContentWrapper =
    wp.components.__experimentalDropdownContentWrapper;
  var UnitControl = wp.components.__experimentalUnitControl;
  var Grid = wp.components.__experimentalGrid;
  var ToggleGroupControl = wp.components.__experimentalToggleGroupControl;
  var ToggleGroupControlOption =
    wp.components.__experimentalToggleGroupControlOption;

  // ── utils ─────────────────────────────────────────────────────────

  function parseBoxShadow(shadow) {
    if (!shadow) return null;

    var parts = shadow.match(/(?:[^(,]+|\([^)]*\))+/g);
    if (!parts) return null;

    return parts.map(function (shadowPart) {
      var obj = {
        inset: false,
        offsetX: null,
        offsetY: null,
        blurRadius: null,
        spreadRadius: null,
        color: null,
      };

      var str = shadowPart.trim();

      if (str.indexOf("inset") !== -1) {
        obj.inset = true;
        str = str.replace(/\binset\b/, "").trim();
      }

      var colorMatch = str.match(
        /(rgba?\([^)]+\)|hsla?\([^)]+\)|#[0-9a-fA-F]{3,8})/
      );
      if (colorMatch) {
        obj.color = convertColorToHex(colorMatch[0]);
        str = str.replace(colorMatch[0], "").trim();
      }

      var values = str.match(/-?\d+(\.\d+)?(px|em|rem|%)?/g) || [];

      obj.offsetX = values[0] || 0;
      obj.offsetY = values[1] || 0;
      obj.blurRadius = values[2] || 0;
      obj.spreadRadius = values[3] || 0;

      var keys = ["offsetX", "offsetY", "blurRadius", "spreadRadius"];
      for (var i = 0; i < keys.length; i++) {
        var k = keys[i];
        if (obj[k] && /^\d+$/.test(obj[k])) obj[k] += "px";
      }

      return obj;
    });
  }

  function unParseBoxShadow(s) {
    return (
      (s.inset ? "inset" : "") +
      " " +
      s.offsetX +
      " " +
      s.offsetY +
      " " +
      s.blurRadius +
      " " +
      s.spreadRadius +
      " " +
      s.color
    );
  }

  function normalizeHex(hex) {
    hex = hex.replace("#", "");
    if (hex.length === 3) {
      hex = hex
        .split("")
        .map(function (c) {
          return c + c;
        })
        .join("");
    }
    if (hex.length === 4) {
      hex = hex
        .split("")
        .map(function (c) {
          return c + c;
        })
        .join("");
    }
    return "#" + hex.toUpperCase();
  }

  function rgbToHex(r, g, b, a) {
    if (a === undefined) a = 1;
    var toHex = function (n) {
      var h = Math.max(0, Math.min(255, Math.round(n))).toString(16);
      return h.length === 1 ? "0" + h : h;
    };
    var hex = "#" + toHex(r) + toHex(g) + toHex(b);
    if (a < 1) hex += toHex(Math.round(a * 255));
    return hex.toUpperCase();
  }

  function hslToHex(h, s, l, a) {
    if (a === undefined) a = 1;
    h = h / 360;
    s = s / 100;
    l = l / 100;
    var r, g, b;
    if (s === 0) {
      r = g = b = l;
    } else {
      var hue2rgb = function (p, q, t) {
        if (t < 0) t += 1;
        if (t > 1) t -= 1;
        if (t < 1 / 6) return p + (q - p) * 6 * t;
        if (t < 1 / 2) return q;
        if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
        return p;
      };
      var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
      var p = 2 * l - q;
      r = hue2rgb(p, q, h + 1 / 3);
      g = hue2rgb(p, q, h);
      b = hue2rgb(p, q, h - 1 / 3);
    }
    return rgbToHex(
      Math.round(r * 255),
      Math.round(g * 255),
      Math.round(b * 255),
      a
    );
  }

  function namedColorToHex(color) {
    var canvas = document.createElement("canvas");
    canvas.width = canvas.height = 1;
    var ctx = canvas.getContext("2d");
    ctx.fillStyle = color;
    return convertColorToHex(ctx.fillStyle);
  }

  function convertColorToHex(color) {
    if (!color) return null;
    var trimmed = color.trim();
    if (trimmed.charAt(0) === "#") return normalizeHex(trimmed);
    var rgbaMatch = trimmed.match(
      /rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+)\s*)?\)/
    );
    if (rgbaMatch) {
      return rgbToHex(
        parseInt(rgbaMatch[1]),
        parseInt(rgbaMatch[2]),
        parseInt(rgbaMatch[3]),
        rgbaMatch[4] ? parseFloat(rgbaMatch[4]) : 1
      );
    }
    var hslaMatch = trimmed.match(
      /hsla?\(\s*([\d.]+)\s*,\s*([\d.]+)%\s*,\s*([\d.]+)%\s*(?:,\s*([\d.]+)\s*)?\)/
    );
    if (hslaMatch) {
      return hslToHex(
        parseFloat(hslaMatch[1]),
        parseFloat(hslaMatch[2]),
        parseFloat(hslaMatch[3]),
        hslaMatch[4] ? parseFloat(hslaMatch[4]) : 1
      );
    }
    return namedColorToHex(trimmed);
  }

  // ── block support detection ──────────────────────────────────────

  function isBlockSupportShadow(blockName) {
    return (
      hasBlockSupport(blockName, "shadow") ||
      [
        "core/avatar",
        "core/paragraph",
        "core/heading",
        "woocommerce/product-button",
      ].indexOf(blockName) !== -1
    );
  }

  // ── shadow presets (default + theme + custom + unset/none) ───────

  function useShadowPresets() {
    var defaultPresets = useSetting("shadow.presets.default") || [];
    var themePresets = useSetting("shadow.presets.theme") || [];
    var customPresets = useSetting("shadow.presets.custom") || [];

    var all = [
      {
        key: "unset",
        label: __("Unset", "brandy"),
        shadow: "unset",
        origin: "unset",
      },
      {
        key: "none",
        label: __("None", "brandy"),
        shadow: "none",
        origin: "none",
      },
    ];
    var addFrom = function (list, origin) {
      list.forEach(function (p) {
        all.push({ key: p.slug, label: p.name, shadow: p.shadow, origin: origin });
      });
    };
    addFrom(defaultPresets, "default");
    addFrom(themePresets, "theme");
    addFrom(customPresets, "custom");
    return all;
  }

  // ── UI components ────────────────────────────────────────────────

  function ShadowToggleIcon() {
    return el(
      "div",
      { style: { width: 24, height: 24 } },
      el(
        "svg",
        {
          viewBox: "0 0 24 24",
          xmlns: "http://www.w3.org/2000/svg",
          width: "24",
          height: "24",
          ariaHidden: "true",
          focusable: "false",
        },
        el("path", {
          d: "M12 8c-2.2 0-4 1.8-4 4s1.8 4 4 4 4-1.8 4-4-1.8-4-4-4zm0 6.5c-1.4 0-2.5-1.1-2.5-2.5s1.1-2.5 2.5-2.5 2.5 1.1 2.5 2.5-1.1 2.5-2.5 2.5zM12.8 3h-1.5v3h1.5V3zm-1.6 18h1.5v-3h-1.5v3zm6.8-9.8v1.5h3v-1.5h-3zm-12 0H3v1.5h3v-1.5zm9.7 5.6 2.1 2.1 1.1-1.1-2.1-2.1-1.1 1.1zM8.3 7.2 6.2 5.1 5.1 6.2l2.1 2.1 1.1-1.1zM5.1 17.8l1.1 1.1 2.1-2.1-1.1-1.1-2.1 2.1zM18.9 6.2l-1.1-1.1-2.1 2.1 1.1 1.1 2.1-2.1z",
        })
      )
    );
  }

  function renderShadowToggle(opts) {
    var label = opts && opts.label;
    return function (toggleArgs) {
      var toggleProps = {
        onClick: toggleArgs.onToggle,
        className: toggleArgs.isOpen ? "is-open" : "",
        "aria-expanded": toggleArgs.isOpen,
        style: { width: "100%" },
        __next40pxDefaultSize: true,
      };
      return el(
        Button,
        toggleProps,
        el(
          HStack,
          { justify: "flex-start" },
          el(ShadowToggleIcon, null),
          el(FlexItem, null, label || __("Drop shadow", "brandy"))
        )
      );
    };
  }

  function ShadowInputControl(props) {
    var onValueChange = function (next) {
      var isNumeric = next !== undefined && !isNaN(parseFloat(next));
      props.onChange(isNumeric ? next : "0px");
    };
    return el(UnitControl, {
      label: props.label,
      __next40pxDefaultSize: true,
      value: props.value,
      onChange: onValueChange,
    });
  }

  function ShadowPopover(props) {
    var shadow = props.shadow;
    var onChange = props.onChange;
    var presets = useShadowPresets();
    var isPreset = presets.some(function (p) {
      return p.shadow === shadow;
    });
    var tabState = useState(isPreset ? "presets" : "custom");
    var tabActive = tabState[0];
    var setTabActive = tabState[1];

    var shadowObj = useMemo(
      function () {
        return parseBoxShadow(shadow);
      },
      [shadow]
    );

    var hasShadow = shadow !== "unset" && shadow !== "" && shadowObj;
    var first = hasShadow ? shadowObj[0] : null;

    var onShadowChange = function (key, value) {
      var base = (shadowObj && shadowObj[0]) || {
        inset: false,
        color: "#0000001A",
        offsetX: "0px",
        offsetY: "2px",
        blurRadius: "3px",
        spreadRadius: "0px",
      };
      var next = Object.assign({}, base);
      next[key] = value;
      onChange(unParseBoxShadow(next));
    };

    var presetsTab = el(
      "div",
      {
        className: "brandy-editor-box-shadow-presets",
        style: {
          display: "flex",
          flexWrap: "wrap",
          gap: 15,
          justifyContent: "center",
        },
      },
      presets.map(function (preset) {
        return el(
          "div",
          {
            key: preset.key,
            className:
              "brandy-editor-box-shadow-presets-item" +
              (shadow === preset.shadow ? " selected" : ""),
            style: { boxShadow: "" + preset.shadow },
            onClick: function () {
              onChange(preset.shadow);
            },
          },
          el("span", { style: { fontSize: 10 } }, preset.label)
        );
      })
    );

    var customTab = el(
      Fragment,
      null,
      el(ColorPalette, {
        clearable: false,
        enableAlpha: true,
        __experimentalIsRenderedInSidebar: true,
        value: hasShadow ? first.color : "#0000001A",
        onChange: function (v) {
          onShadowChange("color", v);
        },
      }),
      el(
        ToggleGroupControl,
        {
          __nextHasNoMarginBottom: true,
          value: hasShadow ? (first.inset ? "inset" : "outset") : "outset",
          isBlock: true,
          onChange: function (v) {
            onShadowChange("inset", v === "inset");
          },
          hideLabelFromVision: true,
          __next40pxDefaultSize: true,
        },
        el(ToggleGroupControlOption, {
          value: "outset",
          label: __("Outset", "brandy"),
        }),
        el(ToggleGroupControlOption, {
          value: "inset",
          label: __("Inset", "brandy"),
        })
      ),
      el(
        Grid,
        { columns: 2, gap: 4 },
        el(ShadowInputControl, {
          label: __("X Position", "brandy"),
          value: hasShadow ? first.offsetX : "0px",
          onChange: function (v) {
            onShadowChange("offsetX", v);
          },
        }),
        el(ShadowInputControl, {
          label: __("Y Position", "brandy"),
          value: hasShadow ? first.offsetY : "0px",
          onChange: function (v) {
            onShadowChange("offsetY", v);
          },
        }),
        el(ShadowInputControl, {
          label: __("Blur", "brandy"),
          value: hasShadow ? first.blurRadius : "0px",
          onChange: function (v) {
            onShadowChange("blurRadius", v);
          },
        }),
        el(ShadowInputControl, {
          label: __("Spread", "brandy"),
          value: hasShadow ? first.spreadRadius : "0px",
          onChange: function (v) {
            onShadowChange("spreadRadius", v);
          },
        })
      )
    );

    return el(
      VStack,
      { spacing: 4 },
      el(
        ToggleGroupControl,
        {
          __nextHasNoMarginBottom: true,
          value: tabActive,
          isBlock: true,
          onChange: function (v) {
            setTabActive(v);
          },
          hideLabelFromVision: true,
          __next40pxDefaultSize: true,
        },
        el(ToggleGroupControlOption, {
          value: "presets",
          label: __("Presets", "brandy"),
        }),
        el(ToggleGroupControlOption, {
          value: "custom",
          label: __("Custom", "brandy"),
        })
      ),
      tabActive === "presets" ? presetsTab : customTab
    );
  }

  function ShadowPicker(props) {
    var popoverProps = { placement: "left-start", offset: 36, shift: true };
    return el(Dropdown, {
      popoverProps: popoverProps,
      className: "brandy-shadow-dropdown",
      style: {
        border: "1px solid rgba(0, 0, 0, 0.1)",
        width: "100%",
      },
      renderToggle: renderShadowToggle({ label: props.label }),
      renderContent: function () {
        return el(
          DropdownContentWrapper,
          { paddingSize: "medium", style: { width: 300 } },
          el(ShadowPopover, { shadow: props.shadow, onChange: props.onChange })
        );
      },
    });
  }

  // ── attribute registration ───────────────────────────────────────

  function registerShadowAttributes(settings) {
    if (typeof settings.attributes === "undefined") return settings;
    if (!isBlockSupportShadow(settings)) return settings;
    if (!settings.attributes.style) settings.attributes.style = {};
    settings.attributes.style = Object.assign(settings.attributes.style, {
      hoverShadow: { type: "string", default: "" },
    });
    return settings;
  }

  addFilter(
    "blocks.registerBlockType",
    "brandy/box-shadow-attributes",
    registerShadowAttributes
  );

  // ── inspector controls ───────────────────────────────────────────

  var addBoxShadowControls = createHigherOrderComponent(function (BlockEdit) {
    return function (props) {
      var attributes = props.attributes;
      var setAttributes = props.setAttributes;
      var blockName = props.name;
      var isSelected = props.isSelected;

      var shadow = (attributes.style && attributes.style.shadow) || "";
      var hoverShadow =
        (attributes.style && attributes.style.hoverShadow) || "";

      var canAddSettings = isBlockSupportShadow(blockName);

      var handleChangeShadow = function (v) {
        setAttributes({
          style: Object.assign({}, attributes.style, { shadow: v }),
        });
      };
      var handleChangeHoverShadow = function (v) {
        setAttributes({
          style: Object.assign({}, attributes.style, { hoverShadow: v }),
        });
      };

      return el(
        Fragment,
        null,
        el(BlockEdit, props),
        isSelected && canAddSettings
          ? el(
              InspectorControls,
              { group: "styles" },
              el(
                PanelBody,
                { title: __("Shadow", "brandy") },
                el(ShadowPicker, {
                  label: __("Drop shadow", "brandy"),
                  shadow: shadow,
                  onChange: handleChangeShadow,
                }),
                el(ShadowPicker, {
                  label: __("Hover drop shadow", "brandy"),
                  shadow: hoverShadow,
                  onChange: handleChangeHoverShadow,
                })
              )
            )
          : null
      );
    };
  }, "addBoxShadowControls");

  addFilter(
    "editor.BlockEdit",
    "brandy/custom-box-shadow-controls",
    addBoxShadowControls
  );

  // ── editor preview style injection ───────────────────────────────

  function getStyleFromAttributes(attributes) {
    var style = {};
    var hoverShadow =
      (attributes.style && attributes.style.hoverShadow) || "";
    if (hoverShadow !== "" && hoverShadow !== "unset") {
      style["--hover-box-shadow"] = hoverShadow;
    }
    return style;
  }

  var addBoxShadowStyleToBlock = createHigherOrderComponent(function (
    BlockListBlock
  ) {
    return function (props) {
      var attributes = props.attributes;
      var extraWrapperProps = props.wrapperProps || {};
      if (
        (attributes.style && attributes.style.shadow != null) ||
        (attributes.style && attributes.style.hoverShadow != null)
      ) {
        extraWrapperProps.style = Object.assign(
          {},
          extraWrapperProps.style,
          getStyleFromAttributes(attributes)
        );
      }
      return el(
        BlockListBlock,
        Object.assign({}, props, {
          wrapperProps: Object.assign({}, extraWrapperProps),
        })
      );
    };
  }, "addBoxShadowStyleToBlock");

  addFilter(
    "editor.BlockListBlock",
    "brandy/custom-box-shadow-style",
    addBoxShadowStyleToBlock
  );
})();
