import type {Snippet} from 'svelte';
import type {Node, useSvelteFlow} from '@xyflow/svelte';

export type TinyflowData = Partial<
  ReturnType<ReturnType<typeof useSvelteFlow>['toObject']>
>;
export type TinyflowNodeData = Record<string, any>;
export type TinyflowTheme = 'light' | 'dark';

export type SelectItem = {
  value: number | string;
  label: string | Snippet;
  description?: string;
  selectable?: boolean;
  icon?: string;
  nodeType?: string;
  dataType?: string;
  displayLabel?: string;
  pathLabel?: string;
  itemTypeLabel?: string;
  isCollection?: boolean;
  tags?: string[];
  children?: SelectItem[];
};

export type CustomNodeForm = {
  type:
    | 'input'
    | 'textarea'
    | 'select'
    | 'chosen'
    // | 'checkbox'
    // | 'radio'
    // | 'switch'
    | 'slider'
    // | 'number'
    // | 'date'
    // | 'time'
    // | 'datetime'
    // | 'color'
    // | 'file'
    // | 'range'
    // | 'image'
    // | 'password'
    | 'heading';
  label: string;
  description?: string;
  name: string;
  placeholder?: string;
  defaultValue?: string | number | boolean;
  attrs?: Record<string, any>;
  options?: SelectItem[];
  resolveValue?: (
    data: Record<string, any>,
  ) => string | number | boolean | undefined;
  resolveOptions?: (data: Record<string, any>) => SelectItem[];
  onValueChange?: (
    value: string | number | boolean | undefined,
    data: Record<string, any>,
  ) => Record<string, any> | void;
  templateSupport?: boolean;
  chosen?: {
    labelDataKey: string;
    valueDataKey: string;
    buttonText?: string;
    onChosen?: (
      updateNodeData: (data: Record<string, any>) => void,
      value?: string,
      label?: string,
      event?: Event,
    ) => void;
  };
};

export type CustomNode = {
  title: string;
  description?: string;
  icon?: string;
  sortNo?: number;
  group?: 'base' | 'tools';
  presentation?: 'default' | 'plain';
  renderFirst?: boolean;
  rootClass?: string;
  rootStyle?: string;
  parameters?: Parameter[];
  parametersEnable?: boolean;
  parametersAddEnable?: boolean;
  outputDefs?: Parameter[];
  outputDefsEnable?: boolean;
  outputDefsAddEnable?: boolean;
  render?: (
    parent: HTMLElement,
    node: Node,
    flowInstance: ReturnType<typeof useSvelteFlow>,
  ) => void;
  onUpdate?: (parent: HTMLElement, node: Node) => void;
  forms?: CustomNodeForm[];
};

export type TinyflowOptions = {
  element: string | Element;
  theme?: TinyflowTheme;
  data?: TinyflowData | string;
  readonly?: boolean;
  hideBottomDock?: boolean;
  hideEdgePanel?: boolean;
  hideMiniMap?: boolean;
  hideNodeHandles?: boolean;
  hideNodeToolbar?: boolean;
  hideNodePicker?: boolean;
  hideNodeSetting?: boolean;
  hideEdgeMarkers?: boolean;
  edgeAnimated?: boolean;
  edgeInteractionWidth?: number;
  nodesDraggable?: boolean;
  nodesConnectable?: boolean;
  elementsSelectable?: boolean;
  dropEnabled?: boolean;
  provider?: {
    llm?: () => SelectItem[] | Promise<SelectItem[]>;
    knowledge?: () => SelectItem[] | Promise<SelectItem[]>;
    searchEngine?: () => SelectItem[] | Promise<SelectItem[]>;
    codeEngine?: () => SelectItem[] | Promise<SelectItem[]>;
  } & Record<string, () => SelectItem[] | Promise<SelectItem[]>>;
  //type : node
  customNodes?: Record<string, CustomNode>;
  onNodeExecute?: (node: Node) => void;
  onRunTest?: () => void | Promise<void>;
  hiddenNodes?: string[] | (() => string[]);
  onDataChange?: (data: TinyflowData) => void;
};

export type Parameter = {
  id?: string;
  name?: string;
  nameDisabled?: boolean;
  displayName?: string;
  pathLabel?: string;
  itemTypeLabel?: string;
  isCollection?: boolean;
  dataType?: string;
  dataTypeItems?: SelectItem[];
  dataTypeDisabled?: boolean;
  contentType?: string; //数据内容类型
  ref?: string;
  refType?: string;
  value?: string;
  description?: string;
  required?: boolean;
  defaultValue?: string;
  deleteDisabled?: boolean;
  addChildDisabled?: boolean;
  children?: Parameter[];
  enums?: string[];
  formType?: string;
  formLabel?: string;
  formDescription?: string;
  formPlaceholder?: string;
  formAttrs?: string;
  requiredDisabled?: boolean;
  systemReserved?: boolean;
  autoManaged?: boolean;
};
