package com.engine.salary.service.impl;

import com.cloudstore.eccom.result.WeaResultMsg;
import com.engine.common.util.ServiceUtil;
import com.engine.core.impl.Service;
import com.engine.salary.biz.AttendQuoteFieldBiz;
import com.engine.salary.component.SalaryWeaTable;
import com.engine.salary.config.SalaryElogConfig;
import com.engine.hrmelog.entity.dto.LoggerContext;
import com.engine.salary.entity.datacollection.dto.AttendQuoteFieldListDTO;
import com.engine.salary.entity.datacollection.param.AttendQuoteFieldQueryParam;
import com.engine.salary.entity.datacollection.param.AttendQuoteFieldSaveParam;
import com.engine.salary.entity.datacollection.po.AttendQuoteFieldPO;
import com.engine.salary.enums.OperateTypeEnum;
import com.engine.salary.enums.datacollection.AttendQuoteFieldSourceTypeEnum;
import com.engine.salary.enums.datacollection.AttendQuoteFieldTypeEnum;
import com.engine.salary.exception.SalaryRunTimeException;
import com.engine.salary.mapper.datacollection.AttendQuoteFieldMapper;
import com.engine.salary.remote.attend.service.RemoteAttend4SalaryService;
import com.engine.salary.remote.attend.service.impl.RemoteAttend4SalaryServiceImpl;
import com.engine.salary.service.AttendQuoteFieldService;
import com.engine.salary.util.SalaryI18nUtil;
import com.engine.salary.util.db.MapperProxyFactory;
import com.engine.salary.util.page.PageInfo;
import com.engine.salary.util.page.SalaryPageUtil;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import weaver.hrm.User;

import java.util.*;
import java.util.stream.Collectors;

import static com.engine.salary.constant.SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY;

/**
 * 数据采集-考勤引用字段
 * <p>Copyright: Copyright (c) 2022</p>
 * <p>Company: 泛微软件</p>
 *
 * @author qiantao
 * @version 1.0
 **/
@Slf4j
public class AttendQuoteFieldServiceImpl extends Service implements AttendQuoteFieldService {

    AttendQuoteFieldBiz biz = new AttendQuoteFieldBiz();

    private AttendQuoteFieldMapper getAttendQuoteFieldMapper() {
        return MapperProxyFactory.getProxy(AttendQuoteFieldMapper.class);
    }

    private RemoteAttend4SalaryService getRemoteAttend4SalaryService(User user) {
        return (RemoteAttend4SalaryService) ServiceUtil.getService(RemoteAttend4SalaryServiceImpl.class, user);
    }


//    
//    private RemoteAttendInitVacationService remoteAttendInitVacationService;
//    
//    private LoggerTemplate attendQuoteFieldLoggerTemplate;


    @Override
    public List<AttendQuoteFieldPO> getAllAttendQuoteFields() {
        return getAttendQuoteFieldMapper().listAll();
    }

    @Override
    public PageInfo<AttendQuoteFieldListDTO> listPage(AttendQuoteFieldQueryParam queryParam) {
        List<AttendQuoteFieldListDTO> list = getAttendQuoteFieldMapper().list(queryParam);
        return SalaryPageUtil.buildPage(queryParam.getCurrent(), queryParam.getPageSize(), list, AttendQuoteFieldListDTO.class);
    }


    @Override
    public AttendQuoteFieldPO getById(Long id) {
        return getAttendQuoteFieldMapper().getById(id);
    }


    @Override
    public Map<String, Object> list(AttendQuoteFieldQueryParam queryParam) {
        syncAttendFields();

        String fields = "    t1.id," +
                "        t1.field_name as fieldName," +
                "        t1.source_type as sourceType," +
                "        t1.field_type as fieldType," +
                "        t1.enable_status as enableStatus," +
                "        t1.description";

        String fromSql = "  FROM" +
                "        hrsa_attend_quote_field t1 ";

        SalaryWeaTable<AttendQuoteFieldListDTO> table = new SalaryWeaTable<AttendQuoteFieldListDTO>(user, AttendQuoteFieldListDTO.class);
        table.setBackfields(fields);
        table.setSqlform(fromSql);
        table.setSqlwhere(AttendQuoteFieldQueryParam.genWhereSql(queryParam));
        table.setSqlorderby("t1.source_type,t1.id DESC");
        table.setSqlprimarykey("t1.id");
        table.setSqlisdistinct("false");

        WeaResultMsg result = new WeaResultMsg(false);
        result.putAll(table.makeDataResult());
        result.success();
        return result.getResultMap();
    }


    @Override
    public AttendQuoteFieldPO getFrom(Long id) {
        if (id != null) {
            AttendQuoteFieldPO po = biz.getById(id);
            if (po == null) {
                throw new SalaryRunTimeException(String.format("字段不存在[id:%s]", id));
            }
            return po;
        }
        return null;
    }

    @Override
    public String save(AttendQuoteFieldSaveParam saveParam) {
        //参数校验
        AttendQuoteFieldSaveParam.checkParam(saveParam);

        List<AttendQuoteFieldPO> attendQuoteFields = biz.listSome(AttendQuoteFieldPO.builder().fieldName(saveParam.getFieldName()).build());
        if (CollectionUtils.isNotEmpty(attendQuoteFields)) {
            throw new SalaryRunTimeException("字段名称不允许重复");
        }

        Date now = new Date();
        AttendQuoteFieldPO attendQuoteField = AttendQuoteFieldPO.builder()
                .fieldName(saveParam.getFieldName())
                .sourceType(AttendQuoteFieldSourceTypeEnum.DEFAULT.getValue())
                .fieldType(saveParam.getFieldType().getValue())
                .enableStatus(saveParam.getEnableStatus() ? 1 : 0)
                .description(saveParam.getDescription())
                .createTime(now)
                .updateTime(now)
                .creator((long) user.getUID())
                .tenantKey(DEFAULT_TENANT_KEY)
                .build();
        // 保存
        biz.save(attendQuoteField);

        // 记录日志
        LoggerContext loggerContext = new LoggerContext();
        loggerContext.setUser(user);
        loggerContext.setTargetId(String.valueOf(attendQuoteField.getId()));
        loggerContext.setTargetName(attendQuoteField.getFieldName());
        loggerContext.setOperateType(OperateTypeEnum.ADD.getValue());
        loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "新建自定义字段"));
        loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "新建自定义字段"));
        loggerContext.setNewValues(attendQuoteField);
        SalaryElogConfig.attendQuoteFieldLoggerTemplate.write(loggerContext);

        return null;
    }

    @Override
    public String update(AttendQuoteFieldSaveParam saveParam) {
        // 校验是否可以编辑
        AttendQuoteFieldSaveParam.checkParam(saveParam);
        if (saveParam.getId() == null) {
            throw new SalaryRunTimeException("id为空");
        }
        AttendQuoteFieldPO attendQuoteField = biz.getById(saveParam.getId());
        if (attendQuoteField == null) {
            throw new SalaryRunTimeException("该字段不存在");
        }
        if (!attendQuoteField.getSourceType().equals(AttendQuoteFieldSourceTypeEnum.DEFAULT.getValue())) {
            throw new SalaryRunTimeException("来源只能为自定义");
        }
        List<AttendQuoteFieldPO> attendQuoteFields = biz.listSome(AttendQuoteFieldPO.builder().fieldName(saveParam.getFieldName()).build());
        if (CollectionUtils.isNotEmpty(attendQuoteFields)) {
            boolean fieldNameExist = attendQuoteFields.stream().anyMatch(e -> !Objects.equals(e.getId(), saveParam.getId()));
            if (fieldNameExist) {
                throw new SalaryRunTimeException("字段名称不允许重复");
            }
        }

        AttendQuoteFieldPO newAttendQuoteField = new AttendQuoteFieldPO();
        BeanUtils.copyProperties(attendQuoteField, newAttendQuoteField);
        newAttendQuoteField.setFieldName(saveParam.getFieldName());
        newAttendQuoteField.setFieldType(saveParam.getFieldType().getValue());
        newAttendQuoteField.setEnableStatus(saveParam.getEnableStatus() ? 1 : 0);
        newAttendQuoteField.setDescription(saveParam.getDescription());
        newAttendQuoteField.setUpdateTime(new Date());
        // 更新
        biz.update(newAttendQuoteField);

        return null;
    }

    @Override
    public String delete(Collection<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            throw new SalaryRunTimeException("参数错误");
        }
        List<AttendQuoteFieldListDTO> attendQuoteFields = biz.list(AttendQuoteFieldQueryParam.builder().ids(ids).build());
        if (CollectionUtils.isEmpty(attendQuoteFields)) {
            throw new SalaryRunTimeException("要删除的数据在不存在或已删除");
        }

        List<AttendQuoteFieldListDTO> attendQuoteAttendFields = attendQuoteFields.stream().filter(e -> e.getSourceType().equals(String.valueOf(AttendQuoteFieldSourceTypeEnum.ATTEND.getValue()))).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(attendQuoteAttendFields)) {
            throw new SalaryRunTimeException("考勤模块的字段不能删除");
        }

        // TODO 正在使用的记录不允许删除
        biz.deleteByIds(ids);
        return null;
    }

    @Override
    public String updateEnableStatus(AttendQuoteFieldSaveParam param) {
        // 校验是否可以编辑
        Long id = param.getId();
        Boolean enableStatus = param.getEnableStatus();
        if (id == null || enableStatus == null) {
            throw new SalaryRunTimeException("参数错误");
        }
        AttendQuoteFieldPO attendQuoteField = biz.getById(id);
        if (attendQuoteField == null) {
            throw new SalaryRunTimeException("该字段不存在");
        }
        if (!attendQuoteField.getSourceType().equals(AttendQuoteFieldSourceTypeEnum.DEFAULT.getValue())) {
            throw new SalaryRunTimeException("来源只能为自定义");
        }

        AttendQuoteFieldPO newAttendQuoteField = new AttendQuoteFieldPO();
        BeanUtils.copyProperties(attendQuoteField, newAttendQuoteField);
        newAttendQuoteField.setEnableStatus(enableStatus ? 1 : 0);
        newAttendQuoteField.setUpdateTime(new Date());
        // 更新
        biz.update(newAttendQuoteField);

        // 记录日志
        LoggerContext loggerContext = new LoggerContext();
        loggerContext.setUser(user);
        loggerContext.setTargetId(String.valueOf(attendQuoteField.getId()));
        loggerContext.setTargetName(attendQuoteField.getFieldName());
        loggerContext.setOperateType(OperateTypeEnum.UPDATE.getValue());
        loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "启用/停用自定义字段"));
        loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "启用/停用自定义字段"));
        loggerContext.setOldValues(attendQuoteField);
        loggerContext.setNewValues(newAttendQuoteField);
        SalaryElogConfig.attendQuoteFieldLoggerTemplate.write(loggerContext);
        return null;
    }

    @Override
    public String syncAttendFields() {
        // 所有字段管理的考勤模块引用字段
        List<AttendQuoteFieldPO> attendQuoteFields = biz.listSome(AttendQuoteFieldPO.builder().sourceType(AttendQuoteFieldSourceTypeEnum.ATTEND.getValue()).build());
        // 1.本地字段
        List<String> localFieldCodes = attendQuoteFields.stream().map(AttendQuoteFieldPO::getCode).collect(Collectors.toList());

        // 2.考勤模块字段
        List<Map<String, String>> columns = new ArrayList<>();
        try {
            columns = getRemoteAttend4SalaryService(user).getColumns();
        } catch (Exception e) {
            log.error("同步考勤字段失败,RemoteAttend4SalaryService.getColumns:{}", e.getMessage());
        }
        List<String> attendFieldCodes = columns.stream().map(m -> m.get("code")).collect(Collectors.toList());
//        List<String> attendLeaveFieldCodes = Lists.newArrayList();
//        attendLeaveFieldCodes.addAll(attendLeaveHourFieldCodes);
        // 所有考勤模块字段编码
//        List<String> attendFieldCodes = Lists.newArrayList();
//        attendFieldCodes.addAll(attendLeaveFieldCodes);
        // 考勤模块固定字段
//        List<Map<String, String>> attendFixedFieldCodes = AttendQuoteFieldBO.buildAttendFixedFields();
//        attendFieldCodes.addAll(attendFixedFieldCodes.stream().map(m -> m.get("code")).collect(Collectors.toList()));

        // 本地已存在则更新【交集】
        List<String> updateCodes = localFieldCodes.stream().filter(item -> attendFieldCodes.contains(item)).collect(Collectors.toList());
        // 本地比attend多，则删除【差集(local - attend)】
        Collection<String> deleteCodes = localFieldCodes.stream().filter(item -> !attendFieldCodes.contains(item)).collect(Collectors.toList());
        // attend比本地多，则新增【差集(attend - local)】
        List<String> saveCodes = attendFieldCodes.stream().filter(item -> !localFieldCodes.contains(item)).collect(Collectors.toList());

        // 1.更新 == 目前除了请假类型其余都是固定，故只需更新请假类型部分
        List<AttendQuoteFieldPO> updates = Lists.newArrayList();
        Date now = new Date();
        for (String code : updateCodes) {
            Optional<Map<String, String>> columnsOptional = columns.stream().filter(column -> code.equals(column.get("code"))).findFirst();
            if (columnsOptional.isPresent()) {
                Map<String, String> column = columnsOptional.get();
                updates.add(AttendQuoteFieldPO.builder()
                        .code(column.get("code"))
                        .fieldName(column.get("name"))
                        .updateTime(now)
                        .build());
            }
        }

        if (CollectionUtils.isNotEmpty(updates)) {
            getAttendQuoteFieldMapper().updateNameByCode(updates);
        }
        // 2.删除
//        if (CollectionUtils.isNotEmpty(deleteCodes)) {
//            //根据考勤字段编码删除考勤模块字段
//            biz.deleteAttendByCode(AttendQuoteFieldQueryParam.builder().codes(deleteCodes).sourceType(AttendQuoteFieldSourceTypeEnum.ATTEND.getValue()).build());
//        }
        // 3.新增
        List<AttendQuoteFieldPO> saves = new ArrayList<>();
        for (String code : saveCodes) {
            Optional<Map<String, String>> columnsOptional = columns.stream().filter(column -> code.equals(column.get("code"))).findFirst();
            if (columnsOptional.isPresent()) {
                Map<String, String> column = columnsOptional.get();
                saves.add(buildAttendQuoteField(column.get("code"), column.get("name")));
            }
        }
        if (CollectionUtils.isNotEmpty(saves)) {
            biz.saveBatch(saves);
        }

        //假期余额



        return null;
    }

    /**
     * 构建考勤字段
     *
     * @param code
     * @param name
     * @return
     */
    private AttendQuoteFieldPO buildAttendQuoteField(String code, String name) {
        Date now = new Date();
        return AttendQuoteFieldPO.builder()
                .code(code)
                .fieldName(name)
                .sourceType(AttendQuoteFieldSourceTypeEnum.ATTEND.getValue())
                .fieldType(AttendQuoteFieldTypeEnum.NUMBER.getValue())
                .enableStatus(1)
                .description("")
                .createTime(now)
                .updateTime(now)
                .creator((long)user.getUID())
                .tenantKey(DEFAULT_TENANT_KEY)
                .build();
    }

    @Override
    public List<AttendQuoteFieldListDTO> listAll() {
        return biz.list(AttendQuoteFieldQueryParam.builder().build());
    }
}
