import { useCollectionManager, useCompile } from "@nocobase/client";

import { instructions, useAvailableUpstreams, useNodeContext } from "./nodes";
import { useFlowContext } from "./FlowContext";
import { triggers } from "./triggers";
import { NAMESPACE } from "./locale";

export type VariableOption = { key: string, value: string; label: string; children?: VariableOption[] };

const VariableTypes = [
  {
    title: `{{t("Node result", { ns: "${NAMESPACE}" })}}`,
    value: '$jobsMapByNodeId',
    options(types) {
      const current = useNodeContext();
      const upstreams = useAvailableUpstreams(current);
      const options: VariableOption[] = [];
      upstreams.forEach((node) => {
        const instruction = instructions.get(node.type);
        const subOptions = instruction.getOptions?.(node.config, types);
        if (subOptions) {
          options.push({
            key: node.id.toString(),
            value: node.id.toString(),
            label: node.title ?? `#${node.id}`,
            children: subOptions,
          });
        }
      });
      return options;
    },
  },
  {
    title: `{{t("Trigger variables", { ns: "${NAMESPACE}" })}}`,
    value: '$context',
    options(types) {
      const { workflow } = useFlowContext();
      const trigger = triggers.get(workflow.type);
      return trigger?.getOptions?.(workflow.config, types) ?? null;
    },
  },
  {
    title: `{{t("System variables", { ns: "${NAMESPACE}" })}}`,
    value: '$system',
    options: [
      {
        key: 'now',
        value: 'now',
        label: `{{t("Current time", { ns: "${NAMESPACE}" })}}`,
      }
    ]
  }
];

export const TypeSets = {
  boolean: new Set(['boolean']),
  number: new Set(['integer', 'bigInt', 'float', 'double', 'real', 'decimal']),
  string: new Set(['string', 'text', 'password']),
  date: new Set(['date', 'time'])
}

function matchFieldType(field, type): Boolean {
  if (typeof type === 'string') {
    return Boolean(TypeSets[type]?.has(field.type));
  }

  if (typeof type === 'object' && type.type === 'reference') {
    return (field.collectionName === type.options?.collection && field.name === 'id')
      || (field.type === 'belongsTo' && field.target === type.options?.collection);
  }

  return false;
}

export function filterTypedFields(fields, types) {
  return types
    ? fields.filter(field => types.some(type => matchFieldType(field, type)))
    : fields;
}

export function useWorkflowVariableOptions() {
  const compile = useCompile();
  const options = VariableTypes.map((item: any) => {
    const options = typeof item.options === 'function' ? item.options().filter(Boolean) : item.options;
    return {
      label: compile(item.title),
      value: item.value,
      key: item.value,
      children: compile(options),
      disabled: options && !options.length
    };
  });
  return options;
}

export function useCollectionFieldOptions(props) {
  const { fields, collection, types } = props;
  const compile = useCompile();
  const { getCollectionFields } = useCollectionManager();
  return filterTypedFields((fields ?? getCollectionFields(collection)), types)
    .filter(field => field.interface && (!field.target || field.type === 'belongsTo'))
    .map(field => field.type === 'belongsTo'
      ? {
        label: `${compile(field.uiSchema?.title || field.name)} ID`,
        key: field.foreignKey,
        value: field.foreignKey,
      }
      : {
        label: compile(field.uiSchema?.title || field.name),
        key: field.name,
        value: field.name,
      });
}
