package cn.ibizlab.core.data.service.impl;

import cn.ibizlab.core.data.domain.DOModel;
import cn.ibizlab.core.data.dto.BaseData;
import cn.ibizlab.core.data.dto.FilterData;
import cn.ibizlab.core.data.dto.RequestData;
import cn.ibizlab.core.data.dto.ResponseData;
import cn.ibizlab.core.data.model.DSLink;
import cn.ibizlab.core.data.model.POSchema;
import cn.ibizlab.core.data.repository.MongoDataRepository;
import cn.ibizlab.core.data.service.IDSSettingService;
import cn.ibizlab.core.data.service.IDataService;
import cn.ibizlab.core.data.service.ModelService;
import cn.ibizlab.util.errors.BadRequestAlertException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
 * 实体[业务实体] 无存储服务对象接口实现
 */
@Slf4j
@Service
public class MongoDataServiceImpl  implements IDataService
{


    @Autowired
    private MongoDataRepository mongoDataRepository;


    @Autowired
    private IDSSettingService dsSettingService;
    
    @Override
    public ResponseData call(DOModel model, String scope, String datasource, String method, RequestData requestData)
    {
        return null;
    }

    @Override
    public boolean create(DOModel model, String scope, String datasource, BaseData et)
    {
        Serializable key=model.getKeyValue(et,true);
        if(ObjectUtils.isEmpty(key))
            throw new BadRequestAlertException("未找到主键",model.getName(),null);

        if(StringUtils.isEmpty(datasource))datasource=model.getDefaultDataSource();
        DSLink link=dsSettingService.getDataSource(datasource);
        POSchema poSchema=model.getPOSchema(link.getType());

        if(mongoDataRepository.insertData(link.getName(),poSchema,poSchema.trans2PO(et))==1)
            et.setAll(get(model,scope,datasource,key));
        return true;
    }

    @Override
    public void createBatch(DOModel model, String scope, String datasource, List<BaseData> list)
    {
        List<BaseData> batch=new ArrayList<>();
        if(StringUtils.isEmpty(datasource))datasource=model.getDefaultDataSource();
        DSLink link=dsSettingService.getDataSource(datasource);
        POSchema poSchema=model.getPOSchema(link.getType());
        list.forEach(et->{
            Serializable key=model.getKeyValue(et,true);
            if(ObjectUtils.isEmpty(key))
                throw new BadRequestAlertException("未找到主键",model.getName(),null);
            batch.add(et);
        });
        if(batch.size()>=0)
        {
            poSchema.trans2PO(batch);
            mongoDataRepository.insertBathData(link.getName(),poSchema,batch);
            batch.clear();
        }
    }

    @Override
    public boolean update(DOModel model, String scope, String datasource, BaseData et)
    {
        Serializable key=model.getKeyValue(et,false);
        if(ObjectUtils.isEmpty(key))
            throw new BadRequestAlertException("未找到主键",model.getName(),null);
        if(StringUtils.isEmpty(datasource))datasource=model.getDefaultDataSource();
        DSLink link=dsSettingService.getDataSource(datasource);
        POSchema poSchema=model.getPOSchema(link.getType());
        mongoDataRepository.updateData(link.getName(),poSchema,poSchema.trans2PO(et));
        et.setAll(get(model,scope,datasource,(Serializable)key));
        return true;
    }

    @Override
    public void updateBatch(DOModel model, String scope, String datasource, List<BaseData> list)
    {
        List<BaseData> batch=new ArrayList<>();
        if(StringUtils.isEmpty(datasource))datasource=model.getDefaultDataSource();
        DSLink link=dsSettingService.getDataSource(datasource);
        POSchema poSchema=model.getPOSchema(link.getType());
        list.forEach(et->{
            Serializable key=model.getKeyValue(et,false);
            if(ObjectUtils.isEmpty(key))
                throw new BadRequestAlertException("未找到主键",model.getName(),null);
            batch.add(et);
        });
        if(batch.size()>=0)
        {
            poSchema.trans2PO(batch);
            mongoDataRepository.updateBathData(link.getName(),poSchema,batch);
            batch.clear();
        }
    }

    @Override
    public boolean remove(DOModel model, String scope, String datasource, Serializable key)
    {
        if(ObjectUtils.isEmpty(key))
            throw new BadRequestAlertException("未找到主键",model.getName(),null);
        BaseData et = model.newData(key);
        if(et==null)
            throw new BadRequestAlertException("未找到主键",model.getName(),null);
        if(StringUtils.isEmpty(datasource))datasource=model.getDefaultDataSource();
        DSLink link=dsSettingService.getDataSource(datasource);
        POSchema poSchema=model.getPOSchema(link.getType());
        mongoDataRepository.removeData(link.getName(),poSchema,poSchema.trans2PO(et));
        return true;
    }

    @Override
    public void removeBatch(DOModel model, String scope, String datasource, List<Serializable> idList)
    {
        List<BaseData> batch=new ArrayList<>();
        if(StringUtils.isEmpty(datasource))datasource=model.getDefaultDataSource();
        DSLink link=dsSettingService.getDataSource(datasource);
        POSchema poSchema=model.getPOSchema(link.getType());
        idList.forEach(key->{
            BaseData et = model.newData(key);
            if(et==null)
                throw new BadRequestAlertException("未找到主键",model.getName(),null);
            batch.add(et);

        });
        if(batch.size()>=0)
        {
            poSchema.trans2PO(batch);
            mongoDataRepository.removeBathData(link.getName(),poSchema,batch);
            batch.clear();
        }
    }

    @Override
    public boolean removeByMap(DOModel model, String scope, String datasource, BaseData et)
    {
        Serializable key=model.getKeyValue(et,false);
        if(ObjectUtils.isEmpty(key))
            throw new BadRequestAlertException("未找到主键",model.getName(),null);
        if(StringUtils.isEmpty(datasource))datasource=model.getDefaultDataSource();
        DSLink link=dsSettingService.getDataSource(datasource);
        POSchema poSchema=model.getPOSchema(link.getType());
        mongoDataRepository.removeData(link.getName(),poSchema,poSchema.trans2PO(et));
        return true;
    }

    @Override
    public BaseData get(DOModel model, String scope, String datasource, Serializable key)
    {
        if(ObjectUtils.isEmpty(key))
            throw new BadRequestAlertException("未找到主键",model.getName(),null);
        BaseData et = model.newData(key);
        if(et==null)
            throw new BadRequestAlertException("未找到主键",model.getName(),null);
        if(StringUtils.isEmpty(datasource))datasource=model.getDefaultDataSource();
        DSLink link=dsSettingService.getDataSource(datasource);
        POSchema poSchema=model.getPOSchema(link.getType());
        List<BaseData> list= mongoDataRepository.getData(link.getName(),poSchema,poSchema.trans2PO(et));
        if(ObjectUtils.isEmpty(list)||list.size()>1)
            throw new BadRequestAlertException("未找到数据",model.getName(),key.toString());
        return poSchema.trans(list.get(0));
    }

    @Override
    public List<BaseData> getBatch(DOModel model, String scope, String datasource, List<Serializable> idList)
    {
        List<BaseData> rt=new ArrayList<>();
        List<BaseData> batch=new ArrayList<>();
        if(StringUtils.isEmpty(datasource))datasource=model.getDefaultDataSource();
        DSLink link=dsSettingService.getDataSource(datasource);
        POSchema poSchema=model.getPOSchema(link.getType());
        idList.forEach(key->{
            BaseData et = model.newData(key);
            if(et==null)
                throw new BadRequestAlertException("未找到主键",model.getName(),null);
            batch.add(et);

        });
        if(batch.size()>=0)
        {
            poSchema.trans2PO(batch);
            rt.addAll(mongoDataRepository.getBatchData(link.getName(),poSchema,batch));
            batch.clear();
        }
        return poSchema.trans(rt);
    }

    @Override
    public BaseData getByMap(DOModel model, String scope, String datasource, BaseData et)
    {
        Serializable key=model.getKeyValue(et,false);
        if(ObjectUtils.isEmpty(key))
            throw new BadRequestAlertException("未找到主键",model.getName(),null);
        if(StringUtils.isEmpty(datasource))datasource=model.getDefaultDataSource();
        DSLink link=dsSettingService.getDataSource(datasource);
        POSchema poSchema=model.getPOSchema(link.getType());
        List<BaseData> list= mongoDataRepository.getData(link.getName(),poSchema,poSchema.trans2PO(et));
        if(ObjectUtils.isEmpty(list)||list.size()>1)
            throw new BadRequestAlertException("未找到数据",model.getName(),key.toString());
        return poSchema.trans(list.get(0));
    }

    @Override
    public BaseData getDraft(DOModel model, String scope, String datasource, BaseData et)
    {
        return et;
    }

    @Override
    public boolean checkKey(DOModel model, String scope, String datasource, BaseData et)
    {
        Serializable key=model.getKeyValue(et,false);
        if(ObjectUtils.isEmpty(key))
            return false;

        if(StringUtils.isEmpty(datasource))datasource=model.getDefaultDataSource();
        DSLink link=dsSettingService.getDataSource(datasource);
        POSchema poSchema=model.getPOSchema(link.getType());
        int cnt= mongoDataRepository.countData(link.getName(),poSchema,poSchema.trans2PO(et));
        return cnt==1;
    }

    @Override
    public boolean save(DOModel model, String scope, String datasource, BaseData et)
    {
        Serializable key=model.getKeyValue(et,true);
        if(ObjectUtils.isEmpty(key))
            throw new BadRequestAlertException("未找到主键",model.getName(),null);
        if(StringUtils.isEmpty(datasource))datasource=model.getDefaultDataSource();
        DSLink link=dsSettingService.getDataSource(datasource);
        POSchema poSchema=model.getPOSchema(link.getType());
        mongoDataRepository.saveData(link.getName(),poSchema,poSchema.trans2PO(et));
        et.setAll(get(model,scope,datasource,(Serializable)key));
        return true;
    }

    @Override
    public void saveBatch(DOModel model, String scope, String datasource, List<BaseData> list)
    {
        List<BaseData> batch=new ArrayList<>();
        if(StringUtils.isEmpty(datasource))datasource=model.getDefaultDataSource();
        DSLink link=dsSettingService.getDataSource(datasource);
        POSchema poSchema=model.getPOSchema(link.getType());
        list.forEach(et->{
            Serializable key=model.getKeyValue(et,false);
            if(ObjectUtils.isEmpty(key))
                throw new BadRequestAlertException("未找到主键",model.getName(),null);
            batch.add(et);
        });
        if(batch.size()>=0)
        {
            poSchema.trans2PO(batch);
            mongoDataRepository.saveBatchData(link.getName(),poSchema,batch);
            batch.clear();
        }

    }

    @Override
    public List<BaseData> select(DOModel model, String scope, String datasource, BaseData et)
    {
        if(StringUtils.isEmpty(datasource))datasource=model.getDefaultDataSource();
        DSLink link=dsSettingService.getDataSource(datasource);
        POSchema poSchema=model.getPOSchema(link.getType());
        return poSchema.trans(mongoDataRepository.selectData(link.getName(),poSchema,poSchema.trans2PO(et)));
    }

    @Override
    public Page<BaseData> select(DOModel model, String scope, String datasource, BaseData et, Pageable pageable)
    {
        if(StringUtils.isEmpty(datasource))datasource=model.getDefaultDataSource();
        DSLink link=dsSettingService.getDataSource(datasource);
        POSchema poSchema=model.getPOSchema(link.getType());
        Page<BaseData> pages= mongoDataRepository.selectData(link.getName(),poSchema,poSchema.trans2PO(et),pageable);
        poSchema.trans(pages.getContent());
        return pages;
    }

    @Override
    public List<BaseData> query(DOModel model, String scope, String datasource, String dataQuery, FilterData context)
    {
        if(StringUtils.isEmpty(datasource))datasource=model.getDefaultDataSource();
        DSLink link=dsSettingService.getDataSource(datasource);
        POSchema poSchema=model.getPOSchema(link.getType());
        model.fillParentFilter(context);
        context.setPOSchema(poSchema);
        return poSchema.trans(mongoDataRepository.queryData(link.getName(),poSchema,"",context));
    }

    @Override
    public Page<BaseData> query(DOModel model, String scope, String datasource, String dataQuery, FilterData context, Pageable pageable)
    {
        if(StringUtils.isEmpty(datasource))datasource=model.getDefaultDataSource();
        DSLink link=dsSettingService.getDataSource(datasource);
        POSchema poSchema=model.getPOSchema(link.getType());
        model.fillParentFilter(context);
        context.setPOSchema(poSchema);
        if(pageable!=null)
            context.setPageable(pageable);
        else
            pageable=context.getPageable();
        Page<BaseData> pages=
                mongoDataRepository.queryData(link.getName(),poSchema,"",context,pageable);
        poSchema.trans(pages.getContent());
        return pages;
    }

    @Override
    public List<BaseData> selectRaw(DOModel model, String scope, String datasource, String sql, FilterData context)
    {
        if(StringUtils.isEmpty(datasource))datasource=model.getDefaultDataSource();
        DSLink link=dsSettingService.getDataSource(datasource);
        POSchema poSchema=model.getPOSchema(link.getType());
        return mongoDataRepository.queryData(link.getName(),poSchema,sql,context);
    }

    @Override
    public boolean execRaw(DOModel model, String scope, String datasource, String sql, BaseData param)
    {
        throw new BadRequestAlertException("没有实现方法execRaw",model.getName(),sql);
    }

    @Override
    public List<BaseData> fetch(DOModel model, String scope, String datasource, String dataSet, FilterData context)
    {
        if(StringUtils.isEmpty(datasource))datasource=model.getDefaultDataSource();
        DSLink link=dsSettingService.getDataSource(datasource);
        POSchema poSchema=model.getPOSchema(link.getType());
        model.fillParentFilter(context);
        context.setPOSchema(poSchema);
        return poSchema.trans(mongoDataRepository.queryData(link.getName(),poSchema,"",context));
    }

    @Override
    public Page<BaseData> fetch(DOModel model, String scope, String datasource, String dataSet, FilterData context, Pageable pageable)
    {
        if(StringUtils.isEmpty(datasource))datasource=model.getDefaultDataSource();
        DSLink link=dsSettingService.getDataSource(datasource);
        POSchema poSchema=model.getPOSchema(link.getType());
        model.fillParentFilter(context);
        context.setPOSchema(poSchema);
        if(pageable!=null)
            context.setPageable(pageable);
        else
            pageable=context.getPageable();
        Page<BaseData> pages=
                mongoDataRepository.queryData(link.getName(),poSchema,"",context,pageable);
        poSchema.trans(pages.getContent());
        return pages;
    }

    @Override
    public DOModel getDOModel(String system, String entity)
    {
        return modelService.getDOModel(system,entity);
    }


    @Autowired
    private ModelService modelService;

}


