/**
 * Automation2 Flow Editor - Data flow context for Data Picker and DynamicValueField.
 * Extended with portTypeCatalog and systemVariables for the Typed Port System.
 */

import React, { createContext, useContext, useMemo } from 'react';
import type { CanvasNode, CanvasConnection } from '../editor/FlowCanvas';
import { getAvailableSources } from '../nodes/shared/dataFlowGraph';
import type { ApiRequestFunction, ConditionOperatorDef, FormFieldType, NodeType, PortField, PortSchema, SystemVariable } from '../../../api/workflowApi';

export interface Automation2DataFlowContextValue {
  currentNodeId: string;
  nodes: CanvasNode[];
  connections: CanvasConnection[];
  nodeOutputsPreview: Record<string, unknown>;
  nodeTypes: NodeType[];
  language: string;
  portTypeCatalog: Record<string, PortSchema>;
  systemVariables: Record<string, SystemVariable>;
  /** Canonical form field types from the API — maps UI type id to portType primitive. */
  formFieldTypes: FormFieldType[];
  /** Backend-driven condition operators per valueKind (flow.ifElse). */
  conditionOperatorCatalog: Record<string, ConditionOperatorDef[]>;
  getNodeLabel: (node: { id: string; title?: string; label?: string; type?: string }) => string;
  getAvailableSourceIds: () => string[];
  /** Present when rendered inside the flow editor (ConnectionPicker / tools). */
  instanceId?: string;
  request?: ApiRequestFunction;
  /** Build FormPayload-like schema from ``parameters[parameterKey]`` (fieldBuilder JSON). */
  parseGraphDefinedSchema: (parameterKey: string) => PortSchema | null;
}

const Automation2DataFlowContext = createContext<Automation2DataFlowContextValue | null>(null);

export function useAutomation2DataFlow(): Automation2DataFlowContextValue | null {
  return useContext(Automation2DataFlowContext);
}

interface Automation2DataFlowProviderProps {
  node: CanvasNode | null;
  nodes: CanvasNode[];
  connections: CanvasConnection[];
  nodeOutputsPreview: Record<string, unknown>;
  nodeTypes: NodeType[];
  language: string;
  portTypeCatalog?: Record<string, PortSchema>;
  systemVariables?: Record<string, SystemVariable>;
  formFieldTypes?: FormFieldType[];
  conditionOperatorCatalog?: Record<string, ConditionOperatorDef[]>;
  instanceId?: string;
  request?: ApiRequestFunction;
  children: React.ReactNode;
}

export const Automation2DataFlowProvider: React.FC<Automation2DataFlowProviderProps> = ({
  node,
  nodes,
  connections,
  nodeOutputsPreview,
  nodeTypes,
  language,
  portTypeCatalog = {},
  systemVariables = {},
  formFieldTypes = [],
  conditionOperatorCatalog = {},
  instanceId,
  request,
  children,
}) => {
  const value = useMemo((): Automation2DataFlowContextValue | null => {
    if (!node) return null;
    const formTypeToPort: Record<string, string> = Object.fromEntries(
      formFieldTypes.map((f) => [f.id, f.portType])
    );
    const resolvePortType = (rawType: string): string => formTypeToPort[rawType] ?? rawType;

    const parseGraphDefinedSchema = (parameterKey: string): PortSchema | null => {
      const raw = node.parameters?.[parameterKey];
      if (!Array.isArray(raw)) return null;
      const fields: PortField[] = [];
      for (const item of raw) {
        if (typeof item !== 'object' || item === null) continue;
        const rec = item as Record<string, unknown>;
        if (typeof rec.name !== 'string') continue;
        const lab = rec.label;
        const desc =
          typeof lab === 'string' ? lab : typeof lab === 'object' && lab !== null ? String((lab as Record<string, string>).de ?? '') : '';
        const rawType = typeof rec.type === 'string' ? rec.type : 'str';
        if (rawType === 'group' && Array.isArray(rec.fields)) {
          for (const sub of rec.fields as Record<string, unknown>[]) {
            if (!sub || typeof sub.name !== 'string') continue;
            const sl = sub.label;
            const sdesc =
              typeof sl === 'string'
                ? sl
                : typeof sl === 'object' && sl !== null
                  ? String((sl as Record<string, string>).de ?? '')
                  : '';
            fields.push({
              name: `${rec.name}.${sub.name}`,
              type: resolvePortType(typeof sub.type === 'string' ? sub.type : 'str'),
              description: (sdesc && sdesc.trim()) || `${rec.name}.${sub.name}`,
              required: Boolean(sub.required),
            });
          }
          continue;
        }
        fields.push({
          name: rec.name,
          type: resolvePortType(rawType),
          description: (desc && desc.trim()) || rec.name,
          required: Boolean(rec.required),
        });
      }
      return fields.length ? { name: 'FormPayload_dynamic', fields } : null;
    };
    return {
      currentNodeId: node.id,
      nodes,
      connections,
      nodeOutputsPreview,
      nodeTypes,
      language,
      portTypeCatalog,
      systemVariables,
      formFieldTypes,
      conditionOperatorCatalog,
      getNodeLabel: (n: { id: string; title?: string; label?: string; type?: string }) =>
        n.title ?? n.label ?? n.type ?? n.id,
      getAvailableSourceIds: () => getAvailableSources(node.id, nodes, connections),
      instanceId,
      request,
      parseGraphDefinedSchema,
    };
  }, [node, nodes, connections, nodeOutputsPreview, nodeTypes, language, portTypeCatalog, systemVariables, formFieldTypes, conditionOperatorCatalog, instanceId, request]);

  return (
    <Automation2DataFlowContext.Provider value={value}>
      {children}
    </Automation2DataFlowContext.Provider>
  );
};
