package com.neusoft.smart.pos.member.core;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.JsonObject;
import com.neusoft.smart.pos.dto.promotion.bean.CalculateBean;
import com.neusoft.smart.pos.framework.exception.BusinessCommonException;
import com.neusoft.smart.pos.member.constants.BonusCalculatorType;
import com.neusoft.smart.pos.member.constants.MemberErrorCode;
import com.neusoft.smart.pos.member.dto.BonusCalculatorTypeResponse;

import java.util.*;

public abstract class BonusCalculator {

    private static Map<Integer, BonusCalculator.ConditionCreator> _calculatorTypeMap;

    public static Map<Integer, BonusCalculator.ConditionCreator> getPolicyClassesMap() {
        if (_calculatorTypeMap == null || _calculatorTypeMap.size() == 0) {
            _calculatorTypeMap = new HashMap<>();
            _calculatorTypeMap.put(BonusCalculatorType.ORDER_AMOUNT_DISCOUNT.getCode(), OrderAmountDiscountCalculator.getConditionCreator());
        }
        return _calculatorTypeMap;
    }

    public static BonusCalculator createBonusCalculator(String jsonPara) {
        JSONObject para = JSONObject.parseObject(jsonPara);
        return getPolicyClassesMap().get(para.getInteger("type")).createInstance(para);
    }

    public static Map<Integer,BonusCalculator> createBonusCalculatorTable(String jsonTableString) {
        JSONObject jsonTable = JSONObject.parseObject(jsonTableString);
        Integer size = jsonTable.size();
        Hashtable<Integer, BonusCalculator> table = new Hashtable<>(size);
        for (Integer i=0;i<size;i++
             ) {
            if(jsonTable.containsKey(i.toString()))
            {
                table.put(i, createBonusCalculator(jsonTable.getString(i.toString())));
            }
        }
        return table;
    }

    public static BonusCalculator createDefaultBonusCalculator(BonusCalculatorType type) {
        return getPolicyClassesMap().get(type.getCode()).createDefaultInstance();
    }

    public static void validateJsonTable(String jsonString) {
        JSONObject table = JSONObject.parseObject(jsonString);
        Integer i = 0;
        while (table.containsKey(i.toString())) {
            validateJsonObject(table.getJSONObject((i++).toString()));
        }
        if (i != table.size()) {
            throw new BusinessCommonException(MemberErrorCode.INVALID_DATA);
        }
    }

    public static void validateJsonString(String jsonString) {
        JSONObject jsonObject = JSONObject.parseObject(jsonString);
        validateJsonObject(jsonObject);
    }

    public static void validateJsonObject(JSONObject jsonObject) {
        if (jsonObject.containsKey("type") && jsonObject.containsKey("para"))
            getPolicyClassesMap().get(jsonObject.getInteger("type")).validateJsonObject(jsonObject.getJSONObject("para"));
        else throw new BusinessCommonException(MemberErrorCode.INVALID_DATA);
    }

    public JSONObject toJSONObject() {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("type", getType().getCode());
        jsonObject.put("para", getPara());
        return jsonObject;
    }

    public String toJsonString()
    {
        return toJSONObject().toJSONString();
    }

    protected abstract JSONObject getPara();

    protected abstract BonusCalculatorType getType();

    protected static BonusCalculator.ConditionCreator getConditionCreator() throws InstantiationException {
        throw new InstantiationException();
    }

    public abstract CalculateBean calculate(CalculateBean bean);

    public abstract static class ConditionCreator {
        abstract BonusCalculator createInstance(JSONObject jsonPara);

        abstract BonusCalculatorType getBonusCalculatorType();

        public BonusCalculatorTypeResponse getBonusCalculatorTag() {
            BonusCalculatorTypeResponse response = new BonusCalculatorTypeResponse();
            response.setTypeCode(this.getBonusCalculatorType().getCode());
            response.setTypeName(this.getBonusCalculatorType().getValue());
            response.setDemo(this.createDefaultInstance().toJsonString());
            return response;
        }

        abstract BonusCalculator createDefaultInstance();

        abstract void validateJsonObject(JSONObject jsonObject);
    }


}
