package cn.ibizlab.core.data.dto;

import cn.ibizlab.core.data.model.POSchema;
import cn.ibizlab.util.errors.BadRequestAlertException;
import cn.ibizlab.core.data.filter.QueryFilter;
import cn.ibizlab.core.data.filter.QueryWrapperContext;
import cn.ibizlab.util.helper.DataObject;
import cn.ibizlab.util.security.AuthenticationUser;
import com.alibaba.fastjson.annotation.JSONField;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.*;

public class FilterData<T> extends BaseData
{
	public FilterData set(String key, Object value)
	{
		this.put(key,value);
		return this;
	}

	public String getDataSource()
	{
		return this.getStringValue("datasource");
	}

	public String getQuery()
	{
		return this.getStringValue("query");
	}

	public FilterData setQuery(String query)
	{
		return this.set("query",query);
	}


	public int getPage()
	{
		return this.getIntegerValue("page",0);
	}

	public FilterData setPage(int page)
	{
		return this.set("page",page);
	}

	public int getSize()
	{
		return getIntegerValue("size",20);
	}

	public FilterData setSize(int size)
	{
		return this.set("size",size);
	}

	public String getSort()
	{
		return this.getStringValue("sort");
	}

	public FilterData setSort(String sort) {

		pageable=PageRequest.of(getPage(),getSize(),getPageSort());
		return this.set("sort",sort);
	}

	@JsonIgnore
	@JSONField(serialize = false)
	public Sort pageSort;
	@JsonIgnore
	@JSONField(serialize = false)
	public Sort getPageSort()
	{
		if(pageSort==null)
		{
			if(!StringUtils.isEmpty(getSort())){
				String sortArr[]=getSort().split(",");
				String sortField=sortArr[0];
				String sortDirection=sortArr.length>1?sortArr[1]:"asc";
				if(sortDirection.equalsIgnoreCase("desc"))
					this.pageSort=Sort.by(Sort.Direction.DESC,sortField);
				else
					this.pageSort=Sort.by(Sort.Direction.ASC,sortField);
			}
			else
				this.pageSort=Sort.unsorted();
		}
		return pageSort;
	}

	@JsonIgnore
	@JSONField(serialize = false)
	public Pageable pageable;
	@JsonIgnore
	@JSONField(serialize = false)
	public Pageable getPageable() {
		if(pageable==null)
			pageable=PageRequest.of(getPage(),getSize(),getPageSort());
		return pageable;
	}

	public FilterData setPageable(Pageable pageable)
	{
		this.pageable=pageable;
		return this;
	}

	public BaseData getParams()
	{
		BaseData param=null;
		Object obj=this.get("params");
		if(obj!=null)
		{
			if(obj instanceof BaseData)
				param=(BaseData)obj;
			else if(obj instanceof Map)
			{
				param=new BaseData().setAll((Map)obj);
				this.set("params",param);
			}
		}
		else
		{
			return this;
		}
		return param;
	}

	public FilterData setParams(BaseData params)
	{
		return this.set("params",params);
	}

	@JsonIgnore
	@JSONField(serialize = false)
	public BaseData getDatacontext() {
		return getParams();
	}


	@JsonIgnore
	@JSONField(serialize = false)
	public BaseData getWebcontext() {
		return getParams();
	}

	@JsonIgnore
	@JSONField(serialize = false)
	public BaseData sessioncontext;
	@JsonIgnore
	@JSONField(serialize = false)
	public BaseData getSessioncontext() {
		if(sessioncontext==null)
			sessioncontext=new BaseData().setAll(AuthenticationUser.getAuthenticationUser().getSessionParams());
		return sessioncontext;
	}

	@Override
	public Object get(Object key) {
		if(key==null)
			return null;
		if(key.toString().equalsIgnoreCase("datacontext"))
			return getDatacontext();
		else if(key.toString().equalsIgnoreCase("webcontext"))
			return getWebcontext();
		else if(key.toString().equalsIgnoreCase("sessioncontext"))
			return getSessioncontext();
		return super.get(key);
	}




	public String getUserTaskId() {
		return this.getStringValue("userTaskId",this.getParams().getStringValue("userTaskId"));
	}

	public FilterData setUserTaskId(String userTaskId)
	{
		return this.set("userTaskId",userTaskId);
	}

	public String getProcessDefinitionKey() {
		return this.getStringValue("processDefinitionKey",this.getParams().getStringValue("processDefinitionKey"));
	}

	public FilterData setProcessDefinitionKey(String processDefinitionKey)
	{
		return this.set("processDefinitionKey",processDefinitionKey);
	}

	private QueryFilter filter;

	public QueryFilter getFilter()
	{
		return filter;
	}

	public FilterData setFilter(QueryFilter filter)
	{
		this.filter=filter;
		return this;
	}




	@JsonIgnore
	@JSONField(serialize = false)
	public Page getPages()
	{
		return getPages(getPOSchema(),this.getPageable());
	}

	public static Page getPages(POSchema poSchema,Pageable pageable){
		Page page;

		int currentPage=pageable.getPageNumber();
		int pageSize=pageable.getPageSize();

		//构造mybatis-plus分页
		if(StringUtils.isEmpty(currentPage) || StringUtils.isEmpty(pageSize)) {
			page=new Page(1,Short.MAX_VALUE);
		}
		else {
			page=new Page(currentPage+1,pageSize);
		}

		//构造mybatis-plus排序
		Sort sort = pageable.getSort();
		Iterator<Sort.Order> it_sort = sort.iterator();

		if(ObjectUtils.isEmpty(it_sort)) {
			return page;
		}

		while (it_sort.hasNext()) {
			Sort.Order sort_order = it_sort.next();
			String colName=sort_order.getProperty();
			if(poSchema!=null&&poSchema.getColumn(colName)!=null)
				colName=poSchema.getColumn(colName).getName();
			page.addOrder(new OrderItem().setColumn(colName).setAsc(sort_order.getDirection()!= Sort.Direction.DESC));
		}

		return page;
	}

	@JsonIgnore
	@JSONField(serialize = false)
	private QueryWrapper<BaseData> searchCond=null;
	public QueryWrapper<BaseData> getSearchCond()
	{
		if(searchCond==null)
		{
			if(this.getFilter()!=null)
			{
				QueryWrapperContext<BaseData> context=new QueryWrapperContext<>();
				context.setFilter(this.getFilter());
				searchCond = context.getSelectCond();
			}
			else
			{
				searchCond=new QueryWrapper<>();
			}

			if(this.getPOSchema()!=null)
			{
				if(!StringUtils.isEmpty(this.getQuery()))
				{
					if(ObjectUtils.isEmpty(this.getPOSchema().getQuickSearch()))
					{
						searchCond.and(qw-> {
							int i=0;
							for(String column:this.getPOSchema().getQuickSearch().keySet())
							{
								if(i>0)
									qw.or();
								qw.like(column,this.getQuery());
								i++;
							}
						});
					}
				}

				if(!ObjectUtils.isEmpty(this.getPOSchema().getSearchMap()))
				{
					for(Map.Entry<String, POSchema.Column> search:this.getPOSchema().getSearchMap().entrySet())
					{
						String key=search.getKey().toLowerCase();
						String name=search.getValue().getName().toLowerCase();
						if(this.keySet().contains(key))
						{
							POSchema.Column column=search.getValue();
							Object obj=column.isDateTime()?this.getTimestampValue(key,null):this.get(key);
							if(!ObjectUtils.isEmpty(obj)) {
								if(key.endsWith("_like"))
									searchCond.like(name,obj);
								else if(key.endsWith("_leftlike"))
									searchCond.likeRight(name,obj);
								else if(key.endsWith("_rightlike"))
									searchCond.likeLeft(name,obj);
								else if(key.endsWith("_eq"))
									searchCond.eq(name,obj);
								else if(key.endsWith("_noteq"))
									searchCond.ne(name,obj);
								else if(key.endsWith("_gt"))
									searchCond.gt(name,obj);
								else if(key.endsWith("_gtandeq"))
									searchCond.ge(name,obj);
								else if(key.endsWith("_lt"))
									searchCond.lt(name,obj);
								else if(key.endsWith("_ltandeq"))
									searchCond.le(name,obj);
								else if(key.endsWith("_isnotnull")&& DataObject.getIntegerValue(obj,1)==1)
									searchCond.isNotNull(name);
								else if(key.endsWith("_isnull")&& DataObject.getIntegerValue(obj,1)==1)
									searchCond.isNull(name);
								else if(key.endsWith("_in"))
									searchCond.in(name,DataObject.getStringValue(obj,"").split(";|,"));
								else if(key.endsWith("_notin"))
									searchCond.notIn(name,DataObject.getStringValue(obj,"").split(";|,"));
							}
						}
					}

				}

			}
		}
		return searchCond;
	}

	public String getSql(String codename)
	{
		if(getPOSchema()==null)
			throw new BadRequestAlertException("未找到存储配置","FilterData",codename);
		POSchema.Segment segment=getPOSchema().getSegment(codename,"");
		if(segment==null)
			throw new BadRequestAlertException("未找到查询方法配置","FilterData",codename);
		String sql=segment.getBody();

		QueryWrapper qw=this.getSearchCond();
		if(qw!=null&&qw.getSqlSegment()!=null)
		{
			if(!qw.isEmptyOfWhere())
				sql=sql.concat(" where ");
			sql = sql.concat(qw.getSqlSegment());
		}

		if(!StringUtils.isEmpty(segment.getFormat()))
			return String.format(segment.getFormat(),sql);
		return sql;
	}

}
