package com.sptg.statistics.biz.service.impl;

import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.SqlLike;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sptg.common.core.constant.OperationConstant;
import com.sptg.statistics.api.dto.SysOperationLogDto;
import com.sptg.statistics.api.entity.SysOperationLog;
import com.sptg.statistics.biz.mapper.SysOperationLogMapper;
import com.sptg.statistics.biz.service.SysOperationServiceInterface;
import org.apache.commons.lang.StringUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * title: SysOperationServiceImpl
 * package: com.sptg.statistics.biz.security.impl
 * description: 系统操作日志-服务层
 *
 *                
 *                
 */
@Service
public class SysOperationServiceImpl  extends ServiceImpl<SysOperationLogMapper, SysOperationLog> implements SysOperationServiceInterface {

    @Override
    public Page<SysOperationLog> getSysOperationLogList(SysOperationLogDto solDto){
        Page<SysOperationLog> page=solDto.getPage();
        //条件
        EntityWrapper<SysOperationLog>   wrapper=new EntityWrapper<SysOperationLog>();
        //操作人名称
        String name=solDto.getOperatorAccountName();
        //操作菜单
        String menu=solDto.getMenu();
        //操作事件
        Integer operationEvent=solDto.getOperationEvent();
        //开始操作时间条件
        Date startOperationDate=solDto.getStartOperationDate();
        //结束操作时间条件
        Date endOperationDate=solDto.getEndOperationDate();
        //机构位置
        String orgPosition=solDto.getOrgPosition();
        //查询事件  1登陆,登出事件，2增,删,改事件
        Integer selectEvents=solDto.getSelectEvents();
        if(StringUtils.isNotBlank(name)){
            wrapper.like("s_operator_account_name",name);
        }
        if(StringUtils.isNotBlank(menu)){
            wrapper.like("s_menu",menu);
        }
        if(operationEvent != null && operationEvent >= 0){
            wrapper.eq("i_operation_event",operationEvent);
        }
        if(startOperationDate!=null){
            wrapper.ge("t_operation_date",startOperationDate);
        }
        if(endOperationDate!=null){
            wrapper.le("t_operation_date",endOperationDate);
        }
        if(selectEvents!=null){
           if(selectEvents==OperationConstant.ONE){
               //1登陆,登出事件
               wrapper.ge("i_operation_event",OperationConstant.THREE);
           }else if(selectEvents==OperationConstant.TWO){
               //2增,删,改事件
               wrapper.le("i_operation_event",OperationConstant.TWO);
           }
        }
        //根据机构
        if(StringUtils.isNotBlank(orgPosition)) {
            wrapper.like("s_org_position", orgPosition, SqlLike.RIGHT);
        }
        wrapper.eq("i_status", OperationConstant.ZERO);
        //排序
        wrapper.orderBy("t_operation_date",false);
        return this.selectPage(page,wrapper);
    }

    @Async
    @Override
    public  void info(List<SysOperationLog> sysOperationLogs)throws Exception{
        if(sysOperationLogs==null||sysOperationLogs.isEmpty()){
            return;
        }
        sysOperationLogs.forEach(sysOperationLog->{
            try {
                //数据转换类型
                Object obj=sysOperationLog.getOperationObject();
                if(obj!=null){
                    obj=convertValue(obj,sysOperationLog.getOperationObjectClass());
                    sysOperationLog.setOperationObject(obj);
                }
                this.autoGenerateContent(sysOperationLog);
            } catch (Exception e) {
               throw new RuntimeException(e);
            }
        });
        super.insertBatch(sysOperationLogs);
    }

    @Async
    @Override
    public void info(SysOperationLog sysOperationLog) throws Exception{
        //数据转换类型
        Object obj=sysOperationLog.getOperationObject();
        if(obj!=null){
            obj=convertValue(obj,sysOperationLog.getOperationObjectClass());
            sysOperationLog.setOperationObject(obj);
        }
        sysOperationLog=this.autoGenerateContent(sysOperationLog);
        if(sysOperationLog==null){
            return;
        }
        super.insert(sysOperationLog);
    }

    @Override
    public void updateOrgPosition(String oldPosition, String newPosition){
        this.baseMapper.updateOrgPosition(oldPosition,newPosition);
    }

    /* -------------------------------------------------- 内部方法 -------------------------------------------------- */
    /* -------------------------------------------------------------------------------------------------------------- */

    /**
     * 功能描述: 自动填充为空内容
     * @param: sysOperationLog
     * @return: SysOperationLog
     *                 
     *                       
     */
    private SysOperationLog autoGenerateContent(SysOperationLog sysOperationLog) throws Exception{
        if(sysOperationLog.getOperationDate()==null){
            sysOperationLog.setOperationDate(new Date());
        }
        //获取表名与值
        Object obj=sysOperationLog.getOperationObject();
        String tableName="";
        String tableId="";
        //批量操作时用到
        List<String> tableIds=null;
        if(obj!=null){
            tableName=getTableName(obj);
            sysOperationLog.setTableName(tableName);

            tableIds=getTableIds(obj);
            if(tableIds==null||tableIds.isEmpty()){
                tableId=getTableId(obj);
            }else{
                int i=0;
                for(String tableIdStr:tableIds){
                    if(i==0){
                        tableId=tableIdStr;
                    }else{
                        tableId+=","+tableIdStr;
                    }
                    i++;
                }
            }
            sysOperationLog.setTableId(tableId);
        }
      return sysOperationLog;
    }

    /**
     * 功能描述:获取实体关联表名
     * @param object
     * @return String
     *                
     *                     
     */
    private String getTableName(Object object){
        TableName tableName=getTableName(object.getClass());
        if(tableName==null){
            return null;
        }
        return tableName.value();
    }

    /**
     * 功能描述:递归获取表注解
     * @param clas
     * @return TableName
     *                
     *                     
     */
    private TableName getTableName(Class<?> clas){
        TableName tableName=clas.getAnnotation(TableName.class);
        if(tableName!=null){
            return tableName;
        }
        Class superClass=clas.getSuperclass();
        if(superClass==null){
            return null;
        }
        return getTableName(superClass);
    }

    /**
     * 功能描述:获取实体id属性值
     * @param object
     * @return String
     *                
     *                     
     */
    private String getTableId(Object object) throws Exception{
        String id=null;
        Field field =getTableIdField(object.getClass(),"id");
        if(field!=null) {
            field.setAccessible(true);
            Object objId=field.get(object);
            id = objId==null?"":String.valueOf(objId);
        }
        return id;
    }

    /**
     * 功能描述:获取实体ids属性值
     * @param object
     * @return List<String>
     *                
     *                     
     */
    private List<String> getTableIds(Object object) throws Exception{
        List<String> ids=null;
        Field field =getTableIdField(object.getClass(),"ids");
        if(field!=null) {
            field.setAccessible(true);
            Object objId=field.get(object);
            ids = (List<String>)objId;
        }
        return ids;
    }

    /**
     * 功能描述:递归获取实体属性
     * @param cls
     * @param fieldName
     * @return Field
     *                
     *                     
     */
    private Field getTableIdField(Class<?> cls,String fieldName)throws Exception{
        if(StringUtils.isBlank(fieldName)){
            return null;
        }
        List<Field> list=Arrays.asList(cls.getDeclaredFields());
        if(list!=null){
           for(Field field:list){
                if(fieldName.equals(field.getName())){
                    field.setAccessible(true);
                    return field;
                }
            }
        }
       Class superClass=cls.getSuperclass();
        if(superClass==null){
            return null;
        }
        return  getTableIdField(superClass,fieldName);
    }

    /**
     * 功能描述:将数据转换到相应的容器
     * @param bean
     * @param tClass
     * @return T
     *                
     *                     
     */
    private static <T> T convertValue(Object bean, Class<T> tClass) throws Exception{
            ObjectMapper mapper = new ObjectMapper();
            return mapper.convertValue(bean, tClass);
    }
}
