/**
 * Responsive Typography — CSS-hide native panel + custom controls
 *
 * On non-desktop preview: hides native Typography panel via CSS,
 * renders custom controls that write to style.responsiveTypography[device].
 * Desktop typography (style.typography) is never mutated.
 */

const RT_SUPPORTED_BLOCKS = ["core/paragraph", "core/heading", "core/list"];
const RT_PRIORITY = 9;

const RT_TYPOGRAPHY_KEYS = [
  "fontSize",
  "lineHeight",
  "fontWeight",
  "letterSpacing",
  "textTransform",
  "textDecoration",
  "fontStyle",
];

/**
 * Get responsive fallback data for a device (mobile inherits tablet).
 */
function rtGetDeviceFallback(responsive, device) {
  const deviceData = responsive[device] ?? {};
  if (device === "mobile") {
    return { ...(responsive.tablet ?? {}), ...deviceData };
  }
  return { ...deviceData };
}

/* Native Typography panel stays visible on all devices — users may want to adjust desktop values */

/* ─── Hook 1: BlockEdit HOC — custom responsive typography controls ─── */

const ResponsiveTypographyHOC = wp.compose.createHigherOrderComponent(
  (BlockEdit) => {
    return (props) => {
      const { attributes, setAttributes, name } = props;
      const { Fragment } = wp.element;
      const { useSelect } = wp.data;
      const { InspectorControls } = wp.blockEditor;
      const {
        FontSizePicker,
        CustomSelectControl,
        __experimentalToolsPanel: ToolsPanel,
        __experimentalToolsPanelItem: ToolsPanelItem,
        __experimentalNumberControl: NumberControl,
      } = wp.components;
      // Fallback for newer WP versions where ToolsPanel is no longer experimental
      const ResolvedToolsPanel = ToolsPanel ?? wp.components.ToolsPanel;
      const ResolvedToolsPanelItem = ToolsPanelItem ?? wp.components.ToolsPanelItem;
      const ResolvedNumberControl = NumberControl ?? wp.components.NumberControl;

      // All hooks MUST be called unconditionally (React rules of hooks)
      const previewDevice = useSelect((select) =>
        (
          (
            select("core/edit-post") ?? select("core/edit-site")
          )?.__experimentalGetPreviewDeviceType() ?? ""
        ).toLowerCase()
      );

      const fontSizes = useSelect((select) =>
        select("core/block-editor").getSettings().fontSizes ?? []
      );

      // Early returns AFTER all hooks
      if (!RT_SUPPORTED_BLOCKS.includes(name)) {
        return React.createElement(BlockEdit, props);
      }

      const isNonDesktop = previewDevice && previewDevice !== "desktop";

      if (!isNonDesktop) {
        return React.createElement(BlockEdit, props);
      }

      const responsive = attributes.style?.responsiveTypography ?? {};
      const deviceData = responsive[previewDevice] ?? {};
      const fallbackData = rtGetDeviceFallback(responsive, previewDevice);

      const deviceLabel =
        previewDevice.charAt(0).toUpperCase() + previewDevice.slice(1);

      /**
       * Update a single typography property for the current device.
       */
      const updateDeviceTypo = (key, value, extra) => {
        const current = { ...(responsive[previewDevice] ?? {}) };

        if (value !== undefined && value !== "" && value !== null) {
          current[key] = value;
          if (extra) Object.assign(current, extra);
        } else {
          delete current[key];
          if (key === "fontSize") {
            delete current.fontSizeType;
          }
        }

        const updatedResponsive = { ...responsive };
        if (Object.keys(current).length > 0) {
          updatedResponsive[previewDevice] = current;
        } else {
          delete updatedResponsive[previewDevice];
        }

        setAttributes({
          style: {
            ...(attributes.style ?? {}),
            responsiveTypography: updatedResponsive,
          },
        });
      };

      // Resolve current font size display value
      const currentFontSizeValue = (() => {
        if (fallbackData.fontSizeType === "preset" && fallbackData.fontSize) {
          const preset = fontSizes.find((s) => s.slug === fallbackData.fontSize);
          return preset?.size;
        }
        return fallbackData.fontSize;
      })();

      const onFontSizeChange = (value) => {
        if (!value) {
          updateDeviceTypo("fontSize", undefined);
          return;
        }

        // Check if value matches a preset
        const preset = fontSizes.find((s) => s.size === value);
        if (preset) {
          updateDeviceTypo("fontSize", preset.slug, { fontSizeType: "preset" });
        } else {
          updateDeviceTypo("fontSize", value, { fontSizeType: "custom" });
        }
      };

      /**
       * Reset all responsive typography for current device.
       */
      const resetAll = () => {
        const updatedResponsive = { ...responsive };
        delete updatedResponsive[previewDevice];

        setAttributes({
          style: {
            ...(attributes.style ?? {}),
            responsiveTypography: Object.keys(updatedResponsive).length > 0
              ? updatedResponsive
              : undefined,
          },
        });
      };

      const typographyPanel = React.createElement(
        InspectorControls,
        null,
        React.createElement(
          ResolvedToolsPanel,
          {
            label: "Typography (" + deviceLabel + ")",
            resetAll: resetAll,
            className: "brandy-responsive-typography-panel",
          },

          // Font Size
          React.createElement(
            ResolvedToolsPanelItem,
            {
              label: "Font size",
              hasValue: () => !!deviceData.fontSize,
              onDeselect: () => updateDeviceTypo("fontSize", undefined),
              isShownByDefault: true
            },
            React.createElement(FontSizePicker, {
              fontSizes: fontSizes,
              value: currentFontSizeValue,
              onChange: onFontSizeChange,
              __nextHasNoMarginBottom: true,
              __next40pxDefaultSize: true,
            })
          ),

          // Appearance + Line Height (single row)
          (() => {
            // Encode current weight+style into a single dropdown value
            const currentAppearance = (() => {
              const w = fallbackData.fontWeight;
              if (!w) return "";
              return fallbackData.fontStyle === "italic" ? w + "-italic" : w;
            })();

            const onAppearanceChange = (val) => {
              const cur = { ...(responsive[previewDevice] ?? {}) };
              if (!val) {
                delete cur.fontWeight;
                delete cur.fontStyle;
              } else {
                const isItalic = val.endsWith("-italic");
                cur.fontWeight = isItalic ? val.replace("-italic", "") : val;
                if (isItalic) { cur.fontStyle = "italic"; }
                else { delete cur.fontStyle; }
              }
              const updated = { ...responsive };
              if (Object.keys(cur).length > 0) { updated[previewDevice] = cur; }
              else { delete updated[previewDevice]; }
              setAttributes({
                style: { ...(attributes.style ?? {}), responsiveTypography: updated },
              });
            };

            const onResetRow = () => {
              const cur = { ...(responsive[previewDevice] ?? {}) };
              delete cur.fontWeight;
              delete cur.fontStyle;
              delete cur.lineHeight;
              const updated = { ...responsive };
              if (Object.keys(cur).length > 0) { updated[previewDevice] = cur; }
              else { delete updated[previewDevice]; }
              setAttributes({
                style: { ...(attributes.style ?? {}), responsiveTypography: updated },
              });
            };

            return React.createElement(
              ResolvedToolsPanelItem,
              {
                label: "Appearance & Line height",
                hasValue: () =>
                  !!deviceData.fontWeight ||
                  !!deviceData.fontStyle ||
                  !!deviceData.lineHeight,
                onDeselect: onResetRow,
                isShownByDefault: true,
              },
              React.createElement(
                "div",
                { style: { display: "flex", gap: "8px" } },
                (() => {
                  const appearanceOptions = [
                    { key: "", name: "Default", style: {} },
                    { key: "100", name: "Thin", style: { fontWeight: "100" } },
                    { key: "100-italic", name: "Thin Italic", style: { fontWeight: "100", fontStyle: "italic" } },
                    { key: "200", name: "Extra Light", style: { fontWeight: "200" } },
                    { key: "200-italic", name: "Extra Light Italic", style: { fontWeight: "200", fontStyle: "italic" } },
                    { key: "300", name: "Light", style: { fontWeight: "300" } },
                    { key: "300-italic", name: "Light Italic", style: { fontWeight: "300", fontStyle: "italic" } },
                    { key: "400", name: "Regular", style: { fontWeight: "400" } },
                    { key: "400-italic", name: "Italic", style: { fontWeight: "400", fontStyle: "italic" } },
                    { key: "500", name: "Medium", style: { fontWeight: "500" } },
                    { key: "500-italic", name: "Medium Italic", style: { fontWeight: "500", fontStyle: "italic" } },
                    { key: "600", name: "Semi Bold", style: { fontWeight: "600" } },
                    { key: "600-italic", name: "Semi Bold Italic", style: { fontWeight: "600", fontStyle: "italic" } },
                    { key: "700", name: "Bold", style: { fontWeight: "700" } },
                    { key: "700-italic", name: "Bold Italic", style: { fontWeight: "700", fontStyle: "italic" } },
                    { key: "800", name: "Extra Bold", style: { fontWeight: "800" } },
                    { key: "800-italic", name: "Extra Bold Italic", style: { fontWeight: "800", fontStyle: "italic" } },
                    { key: "900", name: "Black", style: { fontWeight: "900" } },
                    { key: "900-italic", name: "Black Italic", style: { fontWeight: "900", fontStyle: "italic" } },
                  ];
                  const selectedOption =
                    appearanceOptions.find((o) => o.key === currentAppearance) ??
                    appearanceOptions[0];

                  return React.createElement(
                    "div",
                    { style: { flex: 1 } },
                    React.createElement(CustomSelectControl, {
                      label: "Appearance",
                      value: selectedOption,
                      options: appearanceOptions,
                      onChange: ({ selectedItem }) =>
                        onAppearanceChange(selectedItem.key),
                      __next40pxDefaultSize: true,
                    })
                  );
                })(),
                React.createElement(
                  "div",
                  {
                    className: "block-editor-line-height-control",
                    style: { flex: 1 },
                  },
                  React.createElement(ResolvedNumberControl, {
                    label: "Line height",
                    value: fallbackData.lineHeight ?? "",
                    onChange: (val) => updateDeviceTypo("lineHeight", val),
                    placeholder: "1.5",
                    min: 0,
                    step: 0.01,
                    __nextHasNoMarginBottom: true,
                    spinControls: "custom",
                    __next40pxDefaultSize: true,
                  })
                )
              )
            );
          })()
        )
      );

      return React.createElement(
        Fragment,
        null,
        React.createElement(BlockEdit, props),
        typographyPanel
      );
    };
  },
  "ResponsiveTypographyHOC"
);

wp.hooks.addFilter(
  "editor.BlockEdit",
  "brandy/responsive-typography",
  ResponsiveTypographyHOC,
  RT_PRIORITY
);

/* ─── Hook 2: BlockListBlock HOC — editor preview styles ─── */

/**
 * CSS property map: JS typography keys to CSS property names.
 */
const RT_CSS_PROP_MAP = {
  fontSize: "font-size",
  lineHeight: "line-height",
  fontWeight: "font-weight",
  letterSpacing: "letter-spacing",
  textTransform: "text-transform",
  textDecoration: "text-decoration",
  fontStyle: "font-style",
};

const AddResponsiveTypographyPreview = wp.compose.createHigherOrderComponent(
  (BlockListBlock) => {
    return (props) => {
      const { block } = props;
      const blockName = block?.name;
      const { Fragment } = wp.element;
      const { useSelect } = wp.data;

      // Read attributes from store for real-time reactivity
      const { previewDevice, storeAttributes } = useSelect((select) => {
        const device = (
          (
            select("core/edit-post") ?? select("core/edit-site")
          )?.__experimentalGetPreviewDeviceType() ?? ""
        ).toLowerCase();

        const blockAttrs = block?.clientId
          ? select("core/block-editor").getBlockAttributes(block.clientId)
          : null;

        return { previewDevice: device, storeAttributes: blockAttrs };
      });

      if (!RT_SUPPORTED_BLOCKS.includes(blockName)) {
        return React.createElement(BlockListBlock, props);
      }

      // Desktop: no preview CSS
      if (previewDevice === "desktop" || !previewDevice) {
        return React.createElement(BlockListBlock, props);
      }

      const responsive = storeAttributes?.style?.responsiveTypography ?? {};
      const fallbackData = rtGetDeviceFallback(responsive, previewDevice);

      if (Object.keys(fallbackData).length === 0) {
        return React.createElement(BlockListBlock, props);
      }

      // Build CSS declarations with !important to override WP inline styles
      const declarations = [];

      RT_TYPOGRAPHY_KEYS.forEach((key) => {
        if (fallbackData[key] !== undefined && fallbackData[key] !== "") {
          let value = fallbackData[key];
          if (key === "fontSize" && fallbackData.fontSizeType === "preset") {
            value = "var(--wp--preset--font-size--" + value + ")";
          }
          declarations.push(RT_CSS_PROP_MAP[key] + ":" + value + "!important");
        }
      });

      if (declarations.length === 0) {
        return React.createElement(BlockListBlock, props);
      }

      // Use block's clientId as a scoped CSS class
      const scopeClass = "brandy-rt-preview-" + block.clientId.substring(0, 8);

      const cssRule =
        ".wp-block[data-block=\"" + block.clientId + "\"]." + scopeClass +
        "{" + declarations.join(";") + "}";

      // Add scoped class to block wrapper
      const existingWrapperProps = props.wrapperProps ?? {};
      const existingClassName = existingWrapperProps.className ?? "";

      return React.createElement(
        Fragment,
        null,
        React.createElement("style", null, cssRule),
        React.createElement(BlockListBlock, {
          ...props,
          wrapperProps: {
            ...existingWrapperProps,
            className: (existingClassName + " " + scopeClass).trim(),
          },
        })
      );
    };
  },
  "AddResponsiveTypographyPreview"
);

wp.hooks.addFilter(
  "editor.BlockListBlock",
  "brandy/responsive-typography-preview",
  AddResponsiveTypographyPreview,
  RT_PRIORITY
);
