/*
 * Copyright (C) 2015-present, Ant Financial Services Group
 *
 * 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.
 */
package com.alipay.hulu.replay;

import android.support.annotation.NonNull;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.hulu.bean.AdvanceCaseSetting;
import com.alipay.hulu.bean.CaseRunningParam;
import com.alipay.hulu.bean.ReplayResultBean;
import com.alipay.hulu.bean.ReplayStepInfoBean;
import com.alipay.hulu.common.application.LauncherApplication;
import com.alipay.hulu.common.utils.StringUtil;
import com.alipay.hulu.shared.io.bean.RecordCaseInfo;
import com.alipay.hulu.shared.node.OperationService;
import com.alipay.hulu.shared.node.action.OperationMethod;
import com.alipay.hulu.shared.node.action.PerformActionEnum;
import com.alipay.hulu.shared.node.tree.export.bean.OperationStep;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by qiaoruikai on 2019-08-20 19:26.
 */
public class MultiParamStepProvider extends AbstractStepProvider {
    private static final String TAG = "RepeatStepProvider";

    private OperationService operationService;

    private RecordCaseInfo recordCase;
    private OperationStep prepareStep;

    private int currentIdx;
    private List<Map<String, String>> repeatParams = new ArrayList<>();

    OperationStepProvider currentStepProvider;

    List<ReplayResultBean> resultBeans;

    @Override
    public void prepare() {
        loadStep();
    }

    public MultiParamStepProvider(@NonNull RecordCaseInfo recordCase) {
        this.recordCase = recordCase;
        currentIdx = 0;
        operationService = LauncherApplication.service(OperationService.class);

        parseParams();
        resultBeans = new ArrayList<>(repeatParams.size() + 1);
    }

    private void parseParams() {
        AdvanceCaseSetting setting = JSON.parseObject(recordCase.getAdvanceSettings(), AdvanceCaseSetting.class);
        CaseRunningParam runningParam = setting.getRunningParam();
        if (runningParam == null) {
            repeatParams.add(Collections.EMPTY_MAP);
            return;
        }

        if (runningParam.getMode() == CaseRunningParam.ParamMode.UNION) {
            List<JSONObject> paramUnion = runningParam.getParamList();
            for (JSONObject param: paramUnion) {
                Map<String, String> realParams = new HashMap<>(param.size() + 1);
                for (String key: param.keySet()) {
                    realParams.put(key, param.getString(key));
                }

                repeatParams.add(realParams);
            }
        } else {
            Map<String, List<String>> paramSet = new HashMap<>();
            List<JSONObject> paramUnion = runningParam.getParamList();
            for (JSONObject param: paramUnion) {
                for (String key: param.keySet()) {
                    paramSet.put(key, Arrays.asList(StringUtil.split(param.getString(key), ",")));
                }
            }

            List<String> keys = new ArrayList<>(paramSet.keySet());
            if (keys.size() == 0) {
                return;
            }

            List<Map<String, String>> stackParam = new ArrayList<>();
            String initKey = keys.get(0);
            for (String param: paramSet.get(initKey)) {
                HashMap<String, String> realParams = new HashMap<>(keys.size() + 1);
                realParams.put(initKey, param);
                stackParam.add(realParams);
            }

            // 全连接网络
            for (int i = 1; i < keys.size(); i++) {
                List<Map<String, String>> newStackParam = new ArrayList<>();
                String key = keys.get(i);
                for (Map<String, String> realParam: stackParam) {
                    for (String param: paramSet.get(key)) {
                        Map<String, String> newLevelParam = new HashMap<>(realParam);
                        newLevelParam.put(key, param);
                        newStackParam.add(newLevelParam);
                    }
                }
                stackParam = newStackParam;
            }

            repeatParams.addAll(stackParam);
        }
    }

    private void loadStep() {
        if (currentIdx <= repeatParams.size() - 1) {
            currentStepProvider = new OperationStepProvider(recordCase);
            currentStepProvider.putParams(repeatParams.get(currentIdx));
            currentIdx++;

            currentStepProvider.prepare();

            prepareStep = new OperationStep();
            prepareStep.setOperationMethod(new OperationMethod(PerformActionEnum.GOTO_INDEX));
        } else {
            currentStepProvider = null;
        }
    }

    @Override
    public OperationStep provideStep() {
        if (prepareStep != null) {
            OperationStep step = prepareStep;
            prepareStep = null;
            return step;
        }
        return currentStepProvider == null? null: currentStepProvider.provideStep();
    }

    @Override
    public boolean hasNext() {
        if (currentStepProvider != null && !currentStepProvider.hasNext()) {
            resultBeans.addAll(currentStepProvider.genReplayResult());
            loadStep();
        }

        return currentStepProvider != null && currentStepProvider.hasNext();
    }

    @Override
    public boolean reportErrorStep(OperationStep step, String reason, List<String> stack) {
        boolean errorResult = currentStepProvider.reportErrorStep(step, reason, stack);

        // 如果是关键性错误
        if (errorResult) {
            // 记录下之前的问题
            resultBeans.addAll(currentStepProvider.genReplayResult());

            // 加载下一步
            loadStep();
        }

        return false;
    }

    @Override
    public void onStepInfo(ReplayStepInfoBean bean) {
        currentStepProvider.onStepInfo(bean);
    }

    @Override
    public List<ReplayResultBean> genReplayResult() {
        if (currentStepProvider != null) {
            resultBeans.addAll(currentStepProvider.genReplayResult());
            currentStepProvider = null;
        }

        return resultBeans;
    }
}