/*
 * Copyright 2024-2026 the original author or authors.
 *
 * 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
 *
 *      https://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.
 */

package com.alibaba.cloud.ai.studio.admin.builder.generator.service.dsl.converter;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.alibaba.cloud.ai.studio.admin.builder.generator.model.Variable;
import com.alibaba.cloud.ai.studio.admin.builder.generator.model.VariableSelector;
import com.alibaba.cloud.ai.studio.admin.builder.generator.model.VariableType;
import com.alibaba.cloud.ai.studio.admin.builder.generator.model.workflow.NodeType;
import com.alibaba.cloud.ai.studio.admin.builder.generator.model.workflow.nodedata.ListOperatorNodeData;
import com.alibaba.cloud.ai.studio.admin.builder.generator.service.dsl.AbstractNodeDataConverter;
import com.alibaba.cloud.ai.studio.admin.builder.generator.service.dsl.DSLDialectType;

import org.springframework.stereotype.Component;

/**
 * Convert the ListOperatorNode configuration in the Dify DSL to and from the
 * ListOperatorNodeData object.
 */
@Component
public class ListOperatorNodeDataConverter extends AbstractNodeDataConverter<ListOperatorNodeData> {

	@Override
	public Boolean supportNodeType(NodeType nodeType) {
		return NodeType.LIST_OPERATOR.equals(nodeType);
	}

	@Override
	protected List<DialectConverter<ListOperatorNodeData>> getDialectConverters() {
		return Stream.of(ListOperatorNodeConverter.values())
			.map(ListOperatorNodeConverter::dialectConverter)
			.collect(Collectors.toList());
	}

	private enum ListOperatorNodeConverter {

		DIFY(new DialectConverter<>() {
			@SuppressWarnings("unchecked")
			@Override
			public ListOperatorNodeData parse(Map<String, Object> data) {
				ListOperatorNodeData nd = new ListOperatorNodeData();

				// inputs => variable
				List<String> sel = (List<String>) data.get("variable");
				if (sel != null && sel.size() == 2) {
					nd.setInputs(Collections.singletonList(new VariableSelector(sel.get(0), sel.get(1))));
				}

				// 过滤条件
				Object filterObj = data.get("filter_by");
				if (filterObj instanceof Map<?, ?>) {
					Map<String, Object> filterMap = (Map<String, Object>) filterObj;
					Boolean enabled = (Boolean) filterMap.getOrDefault("enabled", false);
					if (enabled) {
						Object conditionObj = filterMap.get("conditions");
						if (conditionObj instanceof List<?>) {
							List<Map<String, Object>> conditionList = (List<Map<String, Object>>) conditionObj;
							List<ListOperatorNodeData.FilterCondition> filterConditions = conditionList.stream()
								.map(mp -> ListOperatorNodeData.FilterCondition
									.ofDify(mp.get("comparison_operator").toString(), mp.get("value").toString()))
								.toList();
							nd.setFilters(filterConditions);
						}
					}
				}

				// 限制数量
				Object limitObj = data.get("limit");
				if (limitObj instanceof Map<?, ?>) {
					Map<String, Object> limitMap = (Map<String, Object>) limitObj;
					Boolean enabled = (Boolean) limitMap.getOrDefault("enabled", false);
					if (enabled) {
						Integer size = (Integer) limitMap.get("size");
						nd.setLimitNumber(size);
					}
				}

				// 排序规则
				Object orderObj = data.get("order_by");
				if (orderObj instanceof Map<?, ?>) {
					Map<String, Object> orderMap = (Map<String, Object>) orderObj;
					Boolean enabled = (Boolean) orderMap.getOrDefault("enabled", false);
					if (enabled) {
						String value = orderMap.get("value").toString();
						if (value.equalsIgnoreCase("asc")) {
							nd.setOrder(ListOperatorNodeData.Ordered.ASC);
						}
						else if (value.equalsIgnoreCase("desc")) {
							nd.setOrder(ListOperatorNodeData.Ordered.DESC);
						}
					}
				}

				// element_class_type
				nd.setElementClassType(
						VariableType.fromDifyValue((String) data.get("item_var_type")).orElse(VariableType.OBJECT));

				return nd;
			}

			@Override
			public Map<String, Object> dump(ListOperatorNodeData nd) {
				Map<String, Object> m = new LinkedHashMap<>();

				return m;
			}

			@Override
			public Boolean supportDialect(DSLDialectType dialect) {
				return DSLDialectType.DIFY.equals(dialect);
			}
		}), CUSTOM(defaultCustomDialectConverter(ListOperatorNodeData.class));

		private final DialectConverter<ListOperatorNodeData> converter;

		ListOperatorNodeConverter(DialectConverter<ListOperatorNodeData> converter) {
			this.converter = converter;
		}

		public DialectConverter<ListOperatorNodeData> dialectConverter() {
			return converter;
		}

	}

	@Override
	public String generateVarName(int count) {
		return "listOperatorNode" + count;
	}

	@Override
	public BiConsumer<ListOperatorNodeData, Map<String, String>> postProcessConsumer(DSLDialectType dialectType) {
		return switch (dialectType) {
			case DIFY -> emptyProcessConsumer().andThen((nodeData, idToVarName) -> {
				Variable output = ListOperatorNodeData.defaultOutputSchema();
				nodeData.setOutputKey(nodeData.getVarName() + "_" + output.getName());
				nodeData.setOutputs(List.of(output));
			})
				.andThen(super.postProcessConsumer(dialectType))
				.andThen((nodeData, idToVarName) -> nodeData.setInputKey(nodeData.getInputs().get(0).getNameInCode()));
			default -> super.postProcessConsumer(dialectType);
		};
	}

}
