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

export class _WSDL implements INodeType {
    description: INodeTypeDescription = {
        displayName: 'WSDL',
        name: 'wsdl',
        group: ['transform'],
        version: 1,
        description: 'Call a WSDL SOAP function and return the result',
        defaults: {
            name: 'WSDL',
        },
        inputs: [NodeConnectionType.Main],
        outputs: [NodeConnectionType.Main],
        properties: [
            {
                displayName: 'WSDL URI',
                name: 'uri',
                type: 'string',
                default: '',
                placeholder: 'https://example.com/service?wsdl',
                description: 'WSDL endpoint URI',
            },
            {
                displayName: 'Function',
                name: 'function',
                type: 'string',
                default: '',
                description: 'SOAP function to call (e.g., CarList, StatusToString)',
            },
            {
                displayName: 'Parameter field in METADATA (optional)',
                name: 'paramField',
                type: 'string',
                default: 'WSDLparam',
                description: 'Имя поля в METADATA, которое передается как параметр функции',
            },
        ],
    };

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

        const json = items[0].json as IDataObject;

        const uri = this.getNodeParameter('uri', 0) as string;
        const func = this.getNodeParameter('function', 0) as string;
        const paramField = this.getNodeParameter('paramField', 0) as string;

        // Берём параметр из старого METADATA (если был)
        let paramValue = '';
        if (json.METADATA && typeof json.METADATA === 'object' && (json.METADATA as IDataObject)[paramField]) {
            paramValue = String((json.METADATA as IDataObject)[paramField]);
        }

        // SOAP-заготовки
        const req1 = `<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:scales_controllerserver_hostIntf-Iscales_controllerserver_host">
   <soapenv:Header/>
   <soapenv:Body>`;
        const req2 = `</soapenv:Body></soapenv:Envelope>`;

        // Формируем тело запроса
        let requestBody = '';
        if (func === 'CarList') {
            if (!paramValue) throw new Error('METADATA.' + paramField + ' is required for CarList');
            requestBody = `${req1}<urn:CarList><Index>${paramValue}</Index></urn:CarList>${req2}`;
        } else if (func === 'StatusToString') {
            if (!paramValue) throw new Error('METADATA.' + paramField + ' is required for StatusToString');
            requestBody = `${req1}<urn:StatusToString><CodeError>${paramValue}</CodeError></urn:StatusToString>${req2}`;
        } else {
            requestBody = `${req1}<urn:${func}/>${req2}`;
        }

        // Выполняем POST
        const resp = await fetch(uri, {
            method: 'POST',
            body: requestBody,
            headers: {
                'Content-Type': 'text/xml; charset=UTF-8',
            },
        });

        const respText = await resp.text();

        // Пробуем распарсить JSON, иначе строка
        let bodyData: any;
        try {
            bodyData = JSON.parse(respText);
        } catch {
            bodyData = respText;
        }

        // Заполняем DATA
        json.DATA = {
            WSDL: {
                status_code: resp.status,
                body: bodyData,
            },
        };

        // Полная перезапись METADATA в стиле BaseNodeTransform
        const workflowName = this.getWorkflow().name;
        const nodeInfo = this.getNode();
        const fromNodeFull = nodeInfo.type;
        const fromNode = fromNodeFull.includes('.') ? fromNodeFull.split('.').pop()! : fromNodeFull;
        const idField = nodeInfo.name;

        json.METADATA = {
            chain: workflowName,
            from: fromNode,
            id: idField,
            time: Date.now(),
            function: func,
        };

        return this.prepareOutputData([items[0]]);
    }
}
