import {
  ShapeV2Definition
} from "@makeswift/controls";
import {
  CheckboxDefinition,
  ColorDefinition,
  ComboboxDefinition,
  FontDefinition,
  GroupDefinition,
  IconRadioGroupDefinition,
  ImageDefinition,
  LinkDefinition,
  ListDefinition,
  NumberDefinition,
  RichTextV1Definition,
  RichTextV2Definition,
  SelectDefinition,
  ShapeDefinition,
  SlotDefinition,
  StyleDefinition,
  StyleV2Definition,
  TextAreaDefinition,
  TextInputDefinition,
  unstable_TypographyDefinition
} from "../../controls";
import {
  DELETED_PROP_CONTROLLER_TYPES
} from "../../prop-controllers/deleted";
import {
  deserializeFunction,
  isSerializedFunction,
  serializeFunction
} from "./function-serialization";
import {
  Types as PropControllerTypes
} from "@makeswift/prop-controllers";
import { isLegacyDescriptor } from "../../prop-controllers/descriptors";
import { deserializeRecord } from "@makeswift/controls";
import {
  ClientMessagePortSerializationVisitor,
  functionDeserializationPlugin
} from "../../controls/visitors/message-port-serializer";
function serializeShapeControl(control) {
  const { type } = control.options;
  const transferables = [];
  const serializedType = {};
  Object.entries(type).forEach(([key, control2]) => {
    const [serializedControl, serializedControlTransferables] = serializeControl(control2);
    serializedType[key] = serializedControl;
    transferables.push(...serializedControlTransferables);
  });
  return [{ ...control, options: { ...control.options, type: serializedType } }, transferables];
}
function deserializeShapeControl(control) {
  const { type } = control.options;
  const deserializedType = {};
  Object.entries(type).forEach(([key, control2]) => {
    deserializedType[key] = deserializeControl(
      control2
    );
  });
  return { ...control, options: { ...control.options, type: deserializedType } };
}
function serializeListControl(control) {
  const { type, getItemLabel } = control.options;
  const transferables = [];
  const [serializedType, serializedTypeTransferables] = serializeControl(type);
  const serializedGetItemLabel = getItemLabel && serializeFunction(getItemLabel);
  transferables.push(...serializedTypeTransferables);
  if (serializedGetItemLabel != null)
    transferables.push(serializedGetItemLabel);
  return [
    {
      ...control,
      options: {
        ...control.options,
        type: serializedType,
        getItemLabel: serializedGetItemLabel
      }
    },
    transferables
  ];
}
function deserializeListControl(serializedControl) {
  const { type, getItemLabel } = serializedControl.options;
  const deserializedType = deserializeControl(type);
  const deserializedGetItemLabel = getItemLabel && deserializeFunction(getItemLabel);
  return {
    ...serializedControl,
    options: {
      ...serializedControl.options,
      type: deserializedType,
      getItemLabel: deserializedGetItemLabel
    }
  };
}
function serializeTypeaheadControl(control) {
  const { getItems } = control.options;
  const serializedGetItems = getItems && serializeFunction(getItems);
  return [
    { ...control, options: { ...control.options, getItems: serializedGetItems } },
    serializedGetItems == null ? [] : [serializedGetItems]
  ];
}
function deserializeTypeaheadControl(serializedControl) {
  const { getItems } = serializedControl.options;
  const deserializedGetItems = getItems && deserializeFunction(getItems);
  return {
    ...serializedControl,
    options: { ...serializedControl.options, getItems: deserializedGetItems }
  };
}
function serializeControlDef(control) {
  const { options } = control;
  if (typeof options !== "function")
    return [{ ...control, options }, []];
  const serializedOptions = serializeFunction(options);
  return [{ ...control, options: serializedOptions }, [serializedOptions]];
}
function deserializeControlDef(serializedControl) {
  const { options } = serializedControl;
  if (!isSerializedFunction(options))
    return { ...serializedControl, options };
  const deserializedOptions = deserializeFunction(options);
  return { ...serializedControl, options: deserializedOptions };
}
function serializeGapYControl(control) {
  const { options } = control;
  if (typeof options !== "function")
    return [{ ...control, options }, []];
  const serializedOptions = serializeFunction(options);
  return [{ ...control, options: serializedOptions }, [serializedOptions]];
}
function deserializeGapYControl(serializedControl) {
  const { options } = serializedControl;
  if (!isSerializedFunction(options))
    return { ...serializedControl, options };
  const deserializedOptions = deserializeFunction(options);
  return { ...serializedControl, options: deserializedOptions };
}
function serializeCheckboxControl(control) {
  const { options } = control;
  if (typeof options !== "function")
    return [{ ...control, options }, []];
  const serializedOptions = serializeFunction(options);
  return [{ ...control, options: serializedOptions }, [serializedOptions]];
}
function deserializeCheckboxControl(serializedControl) {
  const { options } = serializedControl;
  if (!isSerializedFunction(options))
    return { ...serializedControl, options };
  const deserializedOptions = deserializeFunction(options);
  return { ...serializedControl, options: deserializedOptions };
}
function serializeResponsiveColorControl(control) {
  const { options } = control;
  if (typeof options !== "function")
    return [{ ...control, options }, []];
  const serializedOptions = serializeFunction(options);
  return [{ ...control, options: serializedOptions }, [serializedOptions]];
}
function deserializeResponsiveColorControl(serializedControl) {
  const { options } = serializedControl;
  if (!isSerializedFunction(options))
    return { ...serializedControl, options };
  const deserializedOptions = deserializeFunction(options);
  return { ...serializedControl, options: deserializedOptions };
}
function serializeNumberControl(control) {
  const { options } = control;
  if (typeof options !== "function")
    return [{ ...control, options }, []];
  const serializedOptions = serializeFunction(options);
  return [{ ...control, options: serializedOptions }, [serializedOptions]];
}
function deserializeNumberControl(serializedControl) {
  const { options } = serializedControl;
  if (!isSerializedFunction(options))
    return { ...serializedControl, options };
  const deserializedOptions = deserializeFunction(options);
  return { ...serializedControl, options: deserializedOptions };
}
function serializeDateControl(control) {
  const { options } = control;
  if (typeof options !== "function")
    return [{ ...control, options }, []];
  const serializedOptions = serializeFunction(options);
  return [{ ...control, options: serializedOptions }, [serializedOptions]];
}
function deserializeDateControl(serializedControl) {
  const { options } = serializedControl;
  if (!isSerializedFunction(options))
    return { ...serializedControl, options };
  const deserializedOptions = deserializeFunction(options);
  return { ...serializedControl, options: deserializedOptions };
}
function serializeLinkControl(control) {
  const { options } = control;
  if (typeof options !== "function")
    return [{ ...control, options }, []];
  const serializedOptions = serializeFunction(options);
  return [{ ...control, options: serializedOptions }, [serializedOptions]];
}
function deserializeLinkControl(serializedControl) {
  const { options } = serializedControl;
  if (!isSerializedFunction(options))
    return { ...serializedControl, options };
  const deserializedOptions = deserializeFunction(options);
  return { ...serializedControl, options: deserializedOptions };
}
function serializeTextInputControl(control) {
  const { options } = control;
  if (typeof options !== "function")
    return [{ ...control, options }, []];
  const serializedOptions = serializeFunction(options);
  return [{ ...control, options: serializedOptions }, [serializedOptions]];
}
function deserializeTextInputControl(serializedControl) {
  const { options } = serializedControl;
  if (!isSerializedFunction(options))
    return { ...serializedControl, options };
  const deserializedOptions = deserializeFunction(options);
  return { ...serializedControl, options: deserializedOptions };
}
function serializeResponsiveLengthControl(control) {
  const { options } = control;
  if (typeof options !== "function")
    return [{ ...control, options }, []];
  const serializedOptions = serializeFunction(options);
  return [{ ...control, options: serializedOptions }, [serializedOptions]];
}
function deserializeResponsiveLengthControl(serializedControl) {
  const { options } = serializedControl;
  if (!isSerializedFunction(options))
    return { ...serializedControl, options };
  const deserializedOptions = deserializeFunction(options);
  return { ...serializedControl, options: deserializedOptions };
}
function serializeTextStyleControl(control) {
  const { options } = control;
  if (typeof options !== "function")
    return [{ ...control, options }, []];
  const serializedOptions = serializeFunction(options);
  return [{ ...control, options: serializedOptions }, [serializedOptions]];
}
function deserializeTextStyleControl(serializedControl) {
  const { options } = serializedControl;
  if (!isSerializedFunction(options))
    return { ...serializedControl, options };
  const deserializedOptions = deserializeFunction(options);
  return { ...serializedControl, options: deserializedOptions };
}
function serializeImageControl(control) {
  const { options } = control;
  if (typeof options !== "function")
    return [{ ...control, options }, []];
  const serializedOptions = serializeFunction(options);
  return [{ ...control, options: serializedOptions }, [serializedOptions]];
}
function deserializeImageControl(serializedControl) {
  const { options } = serializedControl;
  if (!isSerializedFunction(options))
    return { ...serializedControl, options };
  const deserializedOptions = deserializeFunction(options);
  return { ...serializedControl, options: deserializedOptions };
}
function serializeRichTextControl(control) {
  const { options } = control;
  if (typeof options !== "function")
    return [{ ...control, options }, []];
  const serializedOptions = serializeFunction(options);
  return [{ ...control, options: serializedOptions }, [serializedOptions]];
}
function deserializeRichTextControl(serializedControl) {
  const { options } = serializedControl;
  if (!isSerializedFunction(options))
    return { ...serializedControl, options };
  const deserializedOptions = deserializeFunction(options);
  return { ...serializedControl, options: deserializedOptions };
}
function serializeControl(control) {
  if (isLegacyDescriptor(control)) {
    return serializeLegacyControl(control);
  }
  const messagePortVisitor = new ClientMessagePortSerializationVisitor();
  const serializedControl = control.accept(messagePortVisitor);
  return [serializedControl, messagePortVisitor.getTransferables()];
}
function isSerializedControl(control) {
  return control != null && typeof control === "object" && "type" in control && typeof control.type === "string";
}
function serializeLegacyControl(control) {
  switch (control.type) {
    case PropControllerTypes.Checkbox:
      return serializeCheckboxControl(control);
    case DELETED_PROP_CONTROLLER_TYPES.List:
      return serializeListControl(control);
    case DELETED_PROP_CONTROLLER_TYPES.Shape:
      return serializeShapeControl(control);
    case DELETED_PROP_CONTROLLER_TYPES.Typeahead:
      return serializeTypeaheadControl(control);
    case PropControllerTypes.GapX:
      return serializeControlDef(control);
    case PropControllerTypes.GapY:
      return serializeGapYControl(control);
    case PropControllerTypes.ResponsiveColor:
      return serializeResponsiveColorControl(control);
    case PropControllerTypes.ResponsiveNumber:
      return serializeControlDef(control);
    case PropControllerTypes.Number:
      return serializeNumberControl(control);
    case PropControllerTypes.ResponsiveIconRadioGroup:
      return serializeControlDef(control);
    case PropControllerTypes.ResponsiveSelect:
      return serializeControlDef(control);
    case PropControllerTypes.ResponsiveLength:
      return serializeResponsiveLengthControl(control);
    case PropControllerTypes.Date:
      return serializeDateControl(control);
    case PropControllerTypes.Link:
      return serializeLinkControl(control);
    case PropControllerTypes.TextInput:
      return serializeTextInputControl(control);
    case PropControllerTypes.TextStyle:
      return serializeTextStyleControl(control);
    case PropControllerTypes.Image:
      return serializeImageControl(control);
    case DELETED_PROP_CONTROLLER_TYPES.RichText:
      return serializeRichTextControl(control);
    default:
      return [control, []];
  }
}
function isSerializedLegacyControl(control) {
  return "options" in control;
}
function deserializeLegacyControl(serializedControl) {
  switch (serializedControl.type) {
    case PropControllerTypes.Checkbox:
      return deserializeCheckboxControl(serializedControl);
    case DELETED_PROP_CONTROLLER_TYPES.List:
      return deserializeListControl(serializedControl);
    case DELETED_PROP_CONTROLLER_TYPES.Shape:
      return deserializeShapeControl(serializedControl);
    case DELETED_PROP_CONTROLLER_TYPES.Typeahead:
      return deserializeTypeaheadControl(serializedControl);
    case PropControllerTypes.GapX:
      return deserializeControlDef(serializedControl);
    case PropControllerTypes.GapY:
      return deserializeGapYControl(serializedControl);
    case PropControllerTypes.ResponsiveColor:
      return deserializeResponsiveColorControl(serializedControl);
    case PropControllerTypes.ResponsiveNumber:
      return deserializeControlDef(serializedControl);
    case PropControllerTypes.Number:
      return deserializeNumberControl(serializedControl);
    case PropControllerTypes.ResponsiveIconRadioGroup:
      return deserializeControlDef(serializedControl);
    case PropControllerTypes.ResponsiveSelect:
      return deserializeControlDef(serializedControl);
    case PropControllerTypes.ResponsiveLength:
      return deserializeResponsiveLengthControl(serializedControl);
    case PropControllerTypes.Date:
      return deserializeDateControl(serializedControl);
    case PropControllerTypes.Link:
      return deserializeLinkControl(serializedControl);
    case PropControllerTypes.TextInput:
      return deserializeTextInputControl(serializedControl);
    case PropControllerTypes.TextStyle:
      return deserializeTextStyleControl(serializedControl);
    case PropControllerTypes.Image:
      return deserializeImageControl(serializedControl);
    case DELETED_PROP_CONTROLLER_TYPES.RichText:
      return deserializeRichTextControl(serializedControl);
    default:
      return serializedControl;
  }
}
function deserializeControl(serializedControl) {
  if (isSerializedLegacyControl(serializedControl)) {
    return deserializeLegacyControl(serializedControl);
  }
  return deserializeUnifiedControlDef(
    deserializeRecord(serializedControl, [functionDeserializationPlugin])
  );
}
function deserializeUnifiedControlDef(record) {
  const deserializeMethod = {
    [CheckboxDefinition.type]: CheckboxDefinition.deserialize,
    [ColorDefinition.type]: ColorDefinition.deserialize,
    [ComboboxDefinition.type]: ComboboxDefinition.deserialize,
    [FontDefinition.type]: FontDefinition.deserialize,
    [GroupDefinition.type]: (record2) => GroupDefinition.deserialize(record2, deserializeUnifiedControlDef),
    [IconRadioGroupDefinition.type]: IconRadioGroupDefinition.deserialize,
    [ImageDefinition.type]: ImageDefinition.deserialize,
    [LinkDefinition.type]: LinkDefinition.deserialize,
    [ListDefinition.type]: (record2) => ListDefinition.deserialize(record2, deserializeUnifiedControlDef),
    [NumberDefinition.type]: NumberDefinition.deserialize,
    [RichTextV1Definition.type]: RichTextV1Definition.deserialize,
    [RichTextV2Definition.type]: (record2) => RichTextV2Definition.deserialize(record2, deserializeUnifiedControlDef),
    [SelectDefinition.type]: SelectDefinition.deserialize,
    [ShapeDefinition.type]: (record2) => ShapeDefinition.deserialize(record2, deserializeUnifiedControlDef),
    [ShapeV2Definition.type]: (record2) => ShapeV2Definition.deserialize(record2, deserializeUnifiedControlDef),
    [SlotDefinition.type]: SlotDefinition.deserialize,
    [StyleDefinition.type]: StyleDefinition.deserialize,
    [StyleV2Definition.type]: (record2) => StyleV2Definition.deserialize(record2, deserializeUnifiedControlDef),
    [TextAreaDefinition.type]: TextAreaDefinition.deserialize,
    [TextInputDefinition.type]: TextInputDefinition.deserialize,
    [unstable_TypographyDefinition.type]: unstable_TypographyDefinition.deserialize
  };
  const deserialize = deserializeMethod[record.type] ?? null;
  if (deserialize == null) {
    throw new Error(`Unknown control type: ${record.type}`);
  }
  return deserialize(record);
}
function serializeControls(controls) {
  return Object.entries(controls).reduce(
    ([accControls, accTransferables], [key, control]) => {
      const [serializedControl, transferables] = serializeControl(control);
      return [{ ...accControls, [key]: serializedControl }, [...accTransferables, ...transferables]];
    },
    [{}, []]
  );
}
function deserializeControls(serializedControls, {
  onError
} = {}) {
  return Object.entries(serializedControls).reduce(
    (deserializedControls, [key, serializedControl]) => {
      try {
        if (!isSerializedControl(serializedControl)) {
          throw new Error(
            `Expected serialized control data, got ${JSON.stringify(serializedControl)}`
          );
        }
        const deserializedControl = deserializeControl(serializedControl);
        return { ...deserializedControls, [key]: deserializedControl };
      } catch (err) {
        const error = err instanceof Error ? new Error(`Could not deserialize control for "${key}": ${err.message}`, {
          cause: err
        }) : new Error(`Could not deserialize control for "${key}", unknown error: ${err}`);
        onError?.(error, { key, serializedControl });
        return deserializedControls;
      }
    },
    {}
  );
}
export {
  deserializeControl,
  deserializeControls,
  deserializeLegacyControl,
  deserializeUnifiedControlDef,
  isSerializedControl,
  serializeControl,
  serializeControls
};
//# sourceMappingURL=control-serialization.js.map