package cn.ibizlab.util.dict;


import cn.ibizlab.util.annotation.DEField;
import cn.ibizlab.util.helper.DataObject;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.baomidou.mybatisplus.annotation.TableField;
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 Catalog
{
	private String code;
	private String name;

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

	public Option findCodeItem(Object value)
	{
		return findCodeItem(value,this.options);
	}

	public Option findCodeItem(Object value,List<Option> options){
		for(Option codeItem : options){
			if(value != null && codeItem.getValue() != null && value.equals(codeItem.getValue()))
				return codeItem;
			else if (!ObjectUtils.isEmpty(codeItem.getChildren()))
			{
				Option rt=findCodeItem(value,codeItem.getChildren());
				if(rt!=null)
					return rt;
			}
		}
		return null;
	}

	private Map<String,Object> advancedSettings;

	public Catalog 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 Catalog setNodes(List<Map> nodes)
	{
		return setNodes(nodes,null,null);
	}

	public Catalog setNodes(List<Map> nodes, String filter, String subCode)
	{
		Map<String,List<Option>> map = new LinkedHashMap<>();
		Option 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<Option> list=null;
			if(!map.containsKey(pid))
			{
				list=new ArrayList<>();
				map.put(pid,list);
			}
			else
				list=map.get(pid);
			Option option=new Option().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))
				list.add(option);
		}
		List<Option> codeItemTreeList = loop(map, (StringUtils.isEmpty(subCode))?"_root":subCode);
		if(subOption!=null)
		{
			subOption.setChildren(codeItemTreeList).setParent("");
			this.getOptions().add(subOption.setParent(null));
		}
		else
			this.setOptions(codeItemTreeList);
		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<Option> loop(Map<String,List<Option>> listCodeItem, Object parentValue) {
		List<Option> trees = new ArrayList<Option>();
		if(listCodeItem.containsKey(parentValue)) {
			for (Option codeItem : listCodeItem.get(parentValue)) {
				List<Option> childCodeItem = loop(listCodeItem, codeItem.getValue());
				if (childCodeItem.size() > 0)
					codeItem.setChildren(childCodeItem);
				trees.add(codeItem);
			}
		}
		return trees;
	}

}
