"use client";
import { Fragment, jsx } from "react/jsx-runtime";
import * as React from "react";
import {
  getInjectionRegistryVersion,
  loadInjectionWidgetsForSpot,
  subscribeToInjectionRegistryChanges
} from "@open-mercato/shared/modules/widgets/injection-loader";
import { getWidgetSharedState } from "./WidgetSharedState.js";
const TRANSFORMER_EVENTS = /* @__PURE__ */ new Set([
  "transformFormData",
  "transformDisplayData",
  "transformValidation"
]);
function injectSharedStateIntoContext(context, moduleId) {
  const sharedState = getWidgetSharedState(moduleId);
  if (typeof context === "object" && context !== null && !Array.isArray(context)) {
    return {
      ...context,
      sharedState
    };
  }
  return {
    value: context,
    sharedState
  };
}
function useInjectionWidgets(spotId, options) {
  const [widgets, setWidgets] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState(null);
  const [registryVersion, setRegistryVersion] = React.useState(() => getInjectionRegistryVersion());
  const loadedRef = React.useRef(false);
  React.useEffect(() => {
    return subscribeToInjectionRegistryChanges(() => {
      setRegistryVersion(getInjectionRegistryVersion());
    });
  }, []);
  React.useEffect(() => {
    if (!spotId) {
      setWidgets([]);
      setLoading(false);
      setError(null);
      return;
    }
    let mounted = true;
    const load = async () => {
      try {
        setLoading(true);
        setError(null);
        const loaded = await loadInjectionWidgetsForSpot(spotId);
        if (!mounted) return;
        const widgetList = loaded.map((w) => ({
          widgetId: w.metadata.id,
          module: w,
          moduleId: w.moduleId,
          key: w.key,
          placement: w.placement
        }));
        setWidgets(widgetList);
        if (!loadedRef.current && options?.triggerOnLoad) {
          loadedRef.current = true;
          for (const widget of widgetList) {
            if (widget.module.eventHandlers?.onLoad) {
              try {
                const widgetContext = injectSharedStateIntoContext(options.context, widget.moduleId);
                await widget.module.eventHandlers.onLoad(widgetContext);
                options.onEvent?.("onLoad", widget.widgetId);
              } catch (err) {
                console.error(`[InjectionSpot] Error in onLoad for widget ${widget.widgetId}:`, err);
              }
            }
          }
        }
      } catch (err) {
        if (!mounted) return;
        console.error(`[InjectionSpot] Failed to load widgets for spot ${spotId}:`, err);
        setError(err instanceof Error ? err.message : String(err));
      } finally {
        if (mounted) setLoading(false);
      }
    };
    load();
    return () => {
      mounted = false;
    };
  }, [spotId, options?.context, options?.triggerOnLoad, options?.onEvent, registryVersion]);
  return { widgets, loading, error };
}
function InjectionSpot({
  spotId,
  context,
  data,
  onDataChange,
  disabled,
  onEvent,
  widgetsOverride
}) {
  const useSpotId = widgetsOverride ? null : spotId;
  const { widgets, loading, error } = useInjectionWidgets(useSpotId, {
    context,
    triggerOnLoad: !widgetsOverride,
    onEvent: onEvent ? (event, id) => onEvent(event, id) : void 0
  });
  const effectiveWidgets = widgetsOverride ?? widgets;
  const effectiveLoading = widgetsOverride ? false : loading;
  const effectiveError = widgetsOverride ? null : error;
  if (effectiveLoading) {
    return null;
  }
  if (effectiveError) {
    console.error(`[InjectionSpot] Error loading widgets for spot ${spotId}:`, effectiveError);
    return null;
  }
  if (effectiveWidgets.length === 0) {
    return null;
  }
  return /* @__PURE__ */ jsx(Fragment, { children: effectiveWidgets.map((widget) => {
    const { Widget } = widget.module;
    return /* @__PURE__ */ jsx(
      Widget,
      {
        context: injectSharedStateIntoContext(context, widget.moduleId),
        data,
        onDataChange,
        disabled
      },
      widget.widgetId
    );
  }) });
}
function useInjectionSpotEvents(spotId, prefetchedWidgets) {
  const [widgets, setWidgets] = React.useState([]);
  const [registryVersion, setRegistryVersion] = React.useState(() => getInjectionRegistryVersion());
  React.useEffect(() => {
    return subscribeToInjectionRegistryChanges(() => {
      setRegistryVersion(getInjectionRegistryVersion());
    });
  }, []);
  React.useEffect(() => {
    if (prefetchedWidgets && prefetchedWidgets.length) {
      setWidgets(prefetchedWidgets);
      return;
    }
    let mounted = true;
    const load = async () => {
      try {
        const loaded = await loadInjectionWidgetsForSpot(spotId);
        if (!mounted) return;
        setWidgets(
          loaded.map((w) => ({
            widgetId: w.metadata.id,
            module: w,
            moduleId: w.moduleId,
            key: w.key,
            placement: w.placement
          }))
        );
      } catch (err) {
        console.error(`[useInjectionSpotEvents] Failed to load widgets for spot ${spotId}:`, err);
      }
    };
    load();
    return () => {
      mounted = false;
    };
  }, [spotId, prefetchedWidgets, registryVersion]);
  const triggerEvent = React.useCallback(
    async (event, data, context, meta) => {
      const normalizeBeforeSave = (result) => {
        if (result === false) return { ok: false };
        if (result === true || typeof result === "undefined") return { ok: true };
        if (result && typeof result === "object") {
          const ok = typeof result.ok === "boolean" ? result.ok : true;
          const message = typeof result.message === "string" ? result.message : void 0;
          const fieldErrors = result.fieldErrors && typeof result.fieldErrors === "object" ? Object.fromEntries(
            Object.entries(result.fieldErrors).map(([key, value]) => [key, String(value)])
          ) : void 0;
          const requestHeaders = result.requestHeaders && typeof result.requestHeaders === "object" ? Object.fromEntries(
            Object.entries(result.requestHeaders).map(([key, value]) => [key, String(value)])
          ) : void 0;
          return { ok, message, fieldErrors, requestHeaders, details: result.details };
        }
        return { ok: true };
      };
      const normalizeBeforeDelete = (result) => {
        if (result === false) return { ok: false };
        if (result === true || typeof result === "undefined") return { ok: true };
        if (result && typeof result === "object") {
          const ok = typeof result.ok === "boolean" ? result.ok : true;
          const message = typeof result.message === "string" ? result.message : void 0;
          const fieldErrors = result.fieldErrors && typeof result.fieldErrors === "object" ? Object.fromEntries(
            Object.entries(result.fieldErrors).map(([key, value]) => [key, String(value)])
          ) : void 0;
          const requestHeaders = result.requestHeaders && typeof result.requestHeaders === "object" ? Object.fromEntries(
            Object.entries(result.requestHeaders).map(([key, value]) => [key, String(value)])
          ) : void 0;
          return { ok, message, fieldErrors, requestHeaders, details: result.details };
        }
        return { ok: true };
      };
      if (TRANSFORMER_EVENTS.has(event)) {
        let pipelineData = data;
        let applyToForm = false;
        for (const widget of widgets) {
          const handler = widget.module.eventHandlers?.[event];
          if (!handler) continue;
          try {
            const widgetContext = injectSharedStateIntoContext(context, widget.moduleId);
            let handlerResult;
            if (event === "transformValidation") {
              handlerResult = await handler(pipelineData, meta?.originalData ?? data, widgetContext);
            } else {
              handlerResult = await handler(pipelineData, widgetContext);
            }
            if (event === "transformFormData" && handlerResult !== null && typeof handlerResult === "object" && "applyToForm" in handlerResult && handlerResult.applyToForm === true && "data" in handlerResult) {
              pipelineData = handlerResult.data;
              applyToForm = true;
            } else {
              pipelineData = handlerResult;
            }
          } catch (err) {
            console.error(`[useInjectionSpotEvents] Error in ${event} for widget ${widget.widgetId}:`, err);
          }
        }
        return { ok: true, data: pipelineData, applyToForm };
      }
      const mergedRequestHeaders = {};
      let hasRequestHeaders = false;
      let fieldValue = meta?.fieldValue;
      let fieldSideEffects;
      let fieldMessages;
      for (const widget of widgets) {
        const eventHandlers = widget.module.eventHandlers;
        const operationFilter = eventHandlers?.filter?.operations;
        if (operationFilter) {
          const currentOperation = context?.operation;
          if (currentOperation && !operationFilter.includes(currentOperation)) {
            continue;
          }
        }
        let handler = eventHandlers?.[event];
        if (!handler && event === "onBeforeDelete") handler = eventHandlers?.onBeforeSave;
        if (!handler && event === "onDelete") handler = eventHandlers?.onSave;
        if (!handler && event === "onAfterDelete") handler = eventHandlers?.onAfterSave;
        if (handler) {
          try {
            const widgetContext = injectSharedStateIntoContext(context, widget.moduleId);
            const result = event === "onDeleteError" ? await handler(data, widgetContext, meta?.error) : event === "onFieldChange" ? await handler(meta?.fieldId, fieldValue, data, widgetContext) : event === "onBeforeNavigate" ? await handler(meta?.target, widgetContext) : event === "onVisibilityChange" ? await handler(meta?.visible, widgetContext) : event === "onAppEvent" ? await handler(meta?.appEvent, widgetContext) : await handler(data, widgetContext);
            if (event === "onBeforeSave") {
              const normalized = normalizeBeforeSave(result);
              if (!normalized.ok) {
                console.log(`[useInjectionSpotEvents] Widget ${widget.widgetId} prevented ${event}`);
                return normalized;
              }
              if (normalized.requestHeaders && Object.keys(normalized.requestHeaders).length > 0) {
                Object.assign(mergedRequestHeaders, normalized.requestHeaders);
                hasRequestHeaders = true;
              }
            }
            if (event === "onBeforeDelete") {
              const normalized = normalizeBeforeDelete(result);
              if (!normalized.ok) {
                console.log(`[useInjectionSpotEvents] Widget ${widget.widgetId} prevented ${event}`);
                return normalized;
              }
              if (normalized.requestHeaders && Object.keys(normalized.requestHeaders).length > 0) {
                Object.assign(mergedRequestHeaders, normalized.requestHeaders);
                hasRequestHeaders = true;
              }
            }
            if (event === "onBeforeNavigate") {
              const navResult = result;
              if (navResult && navResult.ok === false) {
                return { ok: false, message: navResult.message };
              }
            }
            if (event === "onFieldChange") {
              const changeResult = result;
              if (changeResult?.value !== void 0) {
                fieldValue = changeResult.value;
              }
              if (changeResult?.sideEffects && typeof changeResult.sideEffects === "object") {
                fieldSideEffects = { ...fieldSideEffects ?? {}, ...changeResult.sideEffects };
              }
              if (changeResult?.message?.text) {
                fieldMessages = [...fieldMessages ?? [], changeResult.message];
              }
            }
          } catch (err) {
            console.error(`[useInjectionSpotEvents] Error in ${event} for widget ${widget.widgetId}:`, err);
            if (event === "onBeforeSave" || event === "onBeforeDelete" || event === "onBeforeNavigate") {
              const message = err instanceof Error ? err.message || "Validation blocked" : typeof err === "string" ? err : void 0;
              return { ok: false, message };
            }
          }
        }
      }
      if ((event === "onBeforeSave" || event === "onBeforeDelete") && hasRequestHeaders) {
        return { ok: true, requestHeaders: mergedRequestHeaders };
      }
      if (event === "onFieldChange") {
        return {
          ok: true,
          fieldChange: {
            value: fieldValue,
            sideEffects: fieldSideEffects,
            messages: fieldMessages
          }
        };
      }
      return { ok: true };
    },
    [widgets]
  );
  return { triggerEvent, widgets };
}
export {
  InjectionSpot,
  useInjectionSpotEvents,
  useInjectionWidgets
};
//# sourceMappingURL=InjectionSpot.js.map
