/**
 * Copyright (c) 2025-2026, Michael Yang 杨福海 (fuhai999@gmail.com).
 * <p>
 * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.gnu.org/licenses/lgpl-3.0.txt
 * <p>
 * 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.easyagents.flow.core.chain.repository;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 进程内循环累计结果仓储，适用于单机运行和测试。
 */
public class InMemoryLoopResultRepository implements LoopResultRepository {

    private final Map<String, Map<String, List<Object>>> results = new ConcurrentHashMap<>();
    private final Map<String, List<Object>> inputs = new ConcurrentHashMap<>();

    /**
     * {@inheritDoc}
     */
    @Override
    public int storeInput(String resultId, Iterable<?> items) {
        List<Object> stored = new ArrayList<>();
        for (Object item : items) {
            stored.add(item);
        }
        List<Object> existing = inputs.putIfAbsent(resultId, stored);
        return existing == null ? stored.size() : existing.size();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Object loadInputItem(String resultId, int index) {
        List<Object> stored = inputs.get(resultId);
        if (stored == null) {
            throw new IllegalStateException("Loop input not found: " + resultId);
        }
        return stored.get(index);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void removeInput(String resultId) {
        inputs.remove(resultId);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void append(String resultId, int iterationIndex, Map<String, Object> outputValues) {
        if (outputValues == null || outputValues.isEmpty()) {
            return;
        }
        Map<String, List<Object>> result = results.computeIfAbsent(
                resultId, ignored -> Collections.synchronizedMap(new LinkedHashMap<>()));
        synchronized (result) {
            for (Map.Entry<String, Object> entry : outputValues.entrySet()) {
                List<Object> values = result.computeIfAbsent(entry.getKey(), ignored -> new ArrayList<>());
                if (values.size() != iterationIndex) {
                    throw new IllegalStateException("Unexpected loop result index: " + iterationIndex);
                }
                values.add(entry.getValue());
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Map<String, Object> load(String resultId, int iterationCount, List<String> outputNames) {
        Map<String, List<Object>> result = results.get(resultId);
        Map<String, Object> snapshot = new LinkedHashMap<>();
        if (iterationCount == 0 || outputNames == null || outputNames.isEmpty()) {
            return snapshot;
        }
        if (result == null) {
            throw new IllegalStateException("Loop result not found: " + resultId);
        }
        synchronized (result) {
            for (String outputName : outputNames) {
                List<Object> values = result.get(outputName);
                if (values == null || values.size() != iterationCount) {
                    throw new IllegalStateException("Incomplete loop result: " + outputName);
                }
                snapshot.put(outputName, new ArrayList<>(values));
            }
        }
        return snapshot;
    }
}
