// Copyright (C) 2026 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import type {QueryNode, NodeActions} from './query_node';

// Handler functions that NodeActions delegates to.
export interface NodeActionHandlers {
  onAddAndConnectTable: (
    tableName: string,
    node: QueryNode,
    portIndex: number,
  ) => void;
  onInsertNodeAtPort: (
    node: QueryNode,
    portIndex: number,
    descriptorKey: string,
  ) => void;
}

// Creates NodeActions for a node, delegating to the given handlers.
export function createNodeActions(
  node: QueryNode,
  handlers: NodeActionHandlers,
): NodeActions {
  return {
    onAddAndConnectTable: (tableName: string, portIndex: number) => {
      handlers.onAddAndConnectTable(tableName, node, portIndex);
    },
    onInsertModifyColumnsNode: (portIndex: number) => {
      handlers.onInsertNodeAtPort(node, portIndex, 'modify_columns');
    },
    onInsertCounterToIntervalsNode: (portIndex: number) => {
      handlers.onInsertNodeAtPort(node, portIndex, 'counter_to_intervals');
    },
  };
}

// Creates NodeActions using a deferred node reference. Used when the node
// hasn't been created yet (e.g., in handleAddOperationNode).
export function createDeferredNodeActions(
  nodeRef: {current?: QueryNode},
  handlers: NodeActionHandlers,
): NodeActions {
  return {
    onAddAndConnectTable: (tableName: string, portIndex: number) => {
      if (nodeRef.current !== undefined) {
        handlers.onAddAndConnectTable(tableName, nodeRef.current, portIndex);
      }
    },
    onInsertModifyColumnsNode: (portIndex: number) => {
      if (nodeRef.current !== undefined) {
        handlers.onInsertNodeAtPort(
          nodeRef.current,
          portIndex,
          'modify_columns',
        );
      }
    },
    onInsertCounterToIntervalsNode: (portIndex: number) => {
      if (nodeRef.current !== undefined) {
        handlers.onInsertNodeAtPort(
          nodeRef.current,
          portIndex,
          'counter_to_intervals',
        );
      }
    },
  };
}

// Ensures all nodes have their actions initialized. Skips nodes that have
// already been initialized (tracked by initializedNodes set).
export function ensureAllNodeActions(
  nodes: QueryNode[],
  initializedNodes: Set<string>,
  handlers: NodeActionHandlers,
): void {
  for (const node of nodes) {
    if (initializedNodes.has(node.nodeId)) {
      continue;
    }
    if (!node.context.actions) {
      node.context.actions = createNodeActions(node, handlers);
    }
    initializedNodes.add(node.nodeId);
  }
}
