import {
  INodeType,
  INodeTypeDescription,
  IExecuteFunctions,
  INodeExecutionData,
  NodeConnectionType,
  IDataObject,
} from 'n8n-workflow';

interface SwitchCondition {
  field: string;
  operation: '==' | '!=' | '>' | '<' | '>=' | '<=';
  value: string;
  valueType: 'string' | 'number' | 'boolean';
}

export class _CustomSwitchNode implements INodeType {
  description: INodeTypeDescription = {
    displayName: 'Custom Switch',
    name: 'customSwitchNode',
    group: ['transform'],
    version: 1,
    description: 'Узел Switch с несколькими условиями для поля внутри DATA',
    defaults: { name: 'CustomSwitch' },
    inputs: [NodeConnectionType.Main],
    outputs: [NodeConnectionType.Main, NodeConnectionType.Main, NodeConnectionType.Main, NodeConnectionType.Main],
    properties: [
      {
        displayName: 'Условия',
        name: 'conditions',
        type: 'fixedCollection',
        placeholder: 'Добавить условие',
        typeOptions: { multipleValues: true },
        default: [],
        options: [
          {
            name: 'condition',
            displayName: 'Условие',
            values: [
              { displayName: 'Поле (внутри DATA)', name: 'field', type: 'string', default: '' },
              {
                displayName: 'Операция', name: 'operation', type: 'options', options: [
                  { name: '==', value: '==' },
                  { name: '!=', value: '!=' },
                  { name: '>', value: '>' },
                  { name: '<', value: '<' },
                  { name: '>=', value: '>=' },
                  { name: '<=', value: '<=' },
                ], default: '=='
              },
              { displayName: 'Значение', name: 'value', type: 'string', default: '' },
              {
                displayName: 'Тип значения', name: 'valueType', type: 'options', options: [
                  { name: 'Строка', value: 'string' },
                  { name: 'Число', value: 'number' },
                  { name: 'Булево', value: 'boolean' },
                ], default: 'string'
              },
            ],
          },
        ],
      },
    ],
  };

  async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
    const items = this.getInputData();
    if (!items || items.length === 0) return [[]];

    const item = items[0];
    const nodeInfo = this.getNode();
    const fromNodeFull = nodeInfo.type;
    const fromNode = fromNodeFull.includes('.') ? fromNodeFull.split('.').pop()! : fromNodeFull;
    const idField = nodeInfo.name;
    const workflowName = this.getWorkflow().name;

    // Перезаписываем METADATA
    item.json.METADATA = {
      chain: workflowName,
      from: fromNode,
      id: idField,
      time: Date.now(),
    } as IDataObject;

    const conditions: SwitchCondition[] = this.getNodeParameter('conditions.condition', 0, []) as SwitchCondition[];
    const returnData: INodeExecutionData[][] = [[], [], [], []]; // 4 выхода

    const dataObj = item.json.DATA || {};
    let routed = false;

    for (let j = 0; j < conditions.length; j++) {
      const { field, operation, value, valueType } = conditions[j];
      const dataObjSafe = item.json.DATA as Record<string, any>;
      let itemValue = dataObjSafe[field];

      let compareValue: any = value;
      if (valueType === 'number') compareValue = parseFloat(value);
      else if (valueType === 'boolean') compareValue = value === 'true';

      let match = false;
      switch (operation) {
        case '==': match = itemValue === compareValue; break;
        case '!=': match = itemValue !== compareValue; break;
        case '>': match = itemValue > compareValue; break;
        case '<': match = itemValue < compareValue; break;
        case '>=': match = itemValue >= compareValue; break;
        case '<=': match = itemValue <= compareValue; break;
      }

      if (match) {
        returnData[j].push(item);
        routed = true;
        break; // первый совпавший выход
      }
    }

    // Если ни одно условие не совпало — направляем на последний выход
    if (!routed && returnData.length > conditions.length) {
      returnData[conditions.length].push(item);
    }

    return returnData;
  }
}
