package cn.ibizlab.util.dict;


import cn.ibizlab.util.helper.DataObject;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.*;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class CodeList
{
	@JSONField(name = "srfkey")
	@JsonProperty("srfkey")
	private String code;
	private String name;
	private String emptytext;

	public String getEmptytext()
	{
		return "";
	}

	@JSONField(name = "items")
	@JsonProperty("items")
	private List<CodeItem> options = new ArrayList<>();

	public CodeItem findCodeItem(Object value){
		for(CodeItem codeItem : options){
			if(value != null && codeItem.getValue() != null && value.equals(codeItem.getValue()))
				return codeItem;
		}
		return null;
	}

    public CodeItem findChildren(Object value){
        CodeItem resultCodeItem = this.findCodeItem(value);
        List<CodeItem> children = new ArrayList<>();
        for(CodeItem codeItem : options){
            if(value != null && resultCodeItem.getValue() != null && codeItem.getParent() != null && codeItem.getParent().equals(resultCodeItem.getValue()))
                children.add(codeItem);
        }
        resultCodeItem.setChildren(children);
        return resultCodeItem;
    }


	private Map<String,Object> advancedSettings;

	public CodeList putAdvancedSettings(String settings)
	{
		try
		{
			if(!StringUtils.isEmpty(settings))
				advancedSettings= JSON.parseObject(settings,Map.class);
		}catch (Exception ex){}
		return this;
	}

	@JsonIgnore
	@JSONField(serialize = false)
	public String getUrl() {
		return advancedSettings!=null&&advancedSettings.get("url")!=null?advancedSettings.get("url").toString():null;
	}

	@JsonIgnore
	@JSONField(serialize = false)
	public String getRequestMethod() {
		return advancedSettings!=null&&advancedSettings.get("requestMethod")!=null?advancedSettings.get("requestMethod").toString():"GET";
	}

	@JsonIgnore
	@JSONField(serialize = false)
	public String getRequestBody() {
		return advancedSettings!=null&&advancedSettings.get("requestBody")!=null?advancedSettings.get("requestBody").toString():"{}";
	}

	@JsonIgnore
	@JSONField(serialize = false)
	public String getNodeProp() {
		return advancedSettings!=null&&advancedSettings.get("nodeProp")!=null?advancedSettings.get("nodeProp").toString():"";
	}

	@JsonIgnore
	@JSONField(serialize = false)
	public String getValueProp() {
		return advancedSettings!=null&&advancedSettings.get("valueProp")!=null?advancedSettings.get("valueProp").toString():"value";
	}

	@JsonIgnore
	@JSONField(serialize = false)
	public String getLabelProp() {
		return advancedSettings!=null&&advancedSettings.get("labelProp")!=null?advancedSettings.get("labelProp").toString():"label";
	}

	@JsonIgnore
	@JSONField(serialize = false)
	public String getParentProp() {
		return advancedSettings!=null&&advancedSettings.get("parentProp")!=null?advancedSettings.get("parentProp").toString():"parent";
	}

	@JsonIgnore
	@JSONField(serialize = false)
	public String getChildrenProp() {
		return advancedSettings!=null&&advancedSettings.get("childrenProp")!=null?advancedSettings.get("childrenProp").toString():"children";
	}


	@JsonIgnore
	@JSONField(serialize = false)
	public String getDisabledProp() {
		return advancedSettings!=null&&advancedSettings.get("disabledProp")!=null?advancedSettings.get("disabledProp").toString():"disabled";
	}

	@JsonIgnore
	@JSONField(serialize = false)
	public String getFilterProp() {
		return advancedSettings!=null&&advancedSettings.get("filterProp")!=null?advancedSettings.get("filterProp").toString():"filter";
	}

	@JsonIgnore
	@JSONField(serialize = false)
	public String getExpiredProp() {
		return advancedSettings!=null&&advancedSettings.get("expiredProp")!=null?advancedSettings.get("expiredProp").toString():"expired";
	}

	@JsonIgnore
	@JSONField(serialize = false)
	public String getIconClassProp() {
		return advancedSettings!=null&&advancedSettings.get("iconClassProp")!=null?advancedSettings.get("iconClassProp").toString():"iconClass";
	}

	public CodeList setNodes(List<Map> nodes, String filter, String subCode)
	{
		Map<String,List<CodeItem>> map = new LinkedHashMap<>();
		List<CodeItem> alllist = new ArrayList<>();
		CodeItem subOption=null;
		for(Map item:unfoldList(nodes,null))
		{
			Map<String,Object> extension = new HashMap<>();
			if(!StringUtils.isEmpty(item.get("extension")))
				extension = JSONObject.parseObject(item.get("extension").toString(),Map.class);
			String pid= DataObject.getStringValue(item.get(this.getParentProp()),DataObject.getStringValue(item.get("pvalue"),"_root"));
			if(StringUtils.isEmpty(pid))pid="_root";
			List<CodeItem> list=null;
			if(!map.containsKey(pid))
			{
				list=new ArrayList<>();
				map.put(pid,list);
			}
			else
				list=map.get(pid);
			CodeItem option=new CodeItem().setValue(DataObject.getStringValue(item.get(this.getValueProp()),DataObject.getStringValue(item.get("id"),null)))
					.setId(DataObject.getStringValue(item.get(this.getValueProp()),DataObject.getStringValue(item.get("id"),null)))
					.setDisabled(DataObject.getBooleanValue(item.get(this.getDisabledProp()),false)||DataObject.getBooleanValue(item.get(this.getExpiredProp()),false))
					.setFilter(DataObject.getStringValue(item.get(this.getFilterProp()),null)).setIconClass(DataObject.getStringValue(item.get(this.getIconClassProp()),null))
					.setLabel(DataObject.getStringValue(item.get(this.getLabelProp()),DataObject.getStringValue(item.get("text"),"")))
					.setParent(DataObject.getStringValue(item.get(this.getParentProp()),DataObject.getStringValue(item.get("pvalue"),""))).setExtension(extension);
			if(option.getValue().equals(subCode))
				subOption=option;
			if(StringUtils.isEmpty(filter)||option.getFilterSet().contains(filter)) {
				alllist.add(option);
				list.add(option);
			}
		}
		if(subOption!=null)
		{
			List<CodeItem> codeItemTreeList = loop(map, (StringUtils.isEmpty(subCode))?"_root":subCode);
			codeItemTreeList.add(0,subOption.setParent(null));
			this.setOptions(codeItemTreeList);
		}
		else
			this.setOptions(alllist);
		return this;
	}

	public List<Map> unfoldList(List<Map> nodes,String parent)
	{
		List<Map> unfoldList = new ArrayList<>();
		for(Map item:nodes)
		{
			if((!StringUtils.isEmpty(parent))&&StringUtils.isEmpty(DataObject.getStringValue(item.get(this.getParentProp()),DataObject.getStringValue(item.get("pvalue"),null))))
				item.put(this.getParentProp(),parent);
			String value = DataObject.getStringValue(item.get(this.getValueProp()),DataObject.getStringValue(item.get("id"),null));
			unfoldList.add(item);
			Object child=item.get(this.getChildrenProp());
			if(!ObjectUtils.isEmpty(child))
			{
				if(child instanceof List && ((List) child).get(0) instanceof Map)
					unfoldList.addAll(unfoldList((List)child,value));
				item.remove(this.getChildrenProp());
			}
		}
		return unfoldList;
	}

	public List<CodeItem> loop(Map<String,List<CodeItem>> listCodeItem, Object parentValue) {
		List<CodeItem> trees = new ArrayList<CodeItem>();
		if(listCodeItem.containsKey(parentValue)) {
			for (CodeItem codeItem : listCodeItem.get(parentValue)) {
				trees.add(codeItem);
				List<CodeItem> childCodeItem = loop(listCodeItem, codeItem.getValue());
				if (childCodeItem.size() > 0)
					trees.addAll(childCodeItem);
			}
		}
		return trees;
	}
}
