package com.engine.salary.service.auth;

import cn.hutool.core.collection.CollectionUtil;
import com.engine.common.util.ServiceUtil;
import com.engine.core.impl.Service;
import com.engine.hrmelog.entity.dto.LoggerContext;
import com.engine.salary.config.SalaryElogConfig;
import com.engine.salary.constant.SalaryDefaultTenantConstant;
import com.engine.salary.entity.auth.dto.AuthRoleDTO;
import com.engine.salary.entity.auth.dto.AuthRoleDataDTO;
import com.engine.salary.entity.auth.dto.AuthRoleEmpDTO;
import com.engine.salary.entity.auth.param.AuthDataQueryParam;
import com.engine.salary.entity.auth.param.AuthMemberQueryParam;
import com.engine.salary.entity.auth.param.AuthRoleListQueryParam;
import com.engine.salary.entity.auth.param.AuthRoleSaveParam;
import com.engine.salary.entity.auth.po.AuthOptPO;
import com.engine.salary.entity.auth.po.AuthResourcePO;
import com.engine.salary.entity.auth.po.AuthRolePO;
import com.engine.salary.entity.salarysob.po.SalarySobPO;
import com.engine.salary.entity.taxagent.po.TaxAgentPO;
import com.engine.salary.enums.OperateTypeEnum;
import com.engine.salary.enums.auth.ResourceTargetTypeEnum;
import com.engine.salary.exception.SalaryRunTimeException;
import com.engine.salary.mapper.auth.AuthResourceMapper;
import com.engine.salary.mapper.auth.AuthRoleMapper;
import com.engine.salary.util.SalaryI18nUtil;
import com.engine.salary.util.db.IdGenerator;
import com.engine.salary.util.db.MapperProxyFactory;
import com.engine.salary.util.page.PageInfo;
import com.engine.salary.util.page.SalaryPageUtil;
import weaver.hrm.User;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

public class AuthRoleServiceImpl extends Service implements AuthRoleService {

    private AuthRoleMapper getAuthRoleMapper() {
        return MapperProxyFactory.getProxy(AuthRoleMapper.class);
    }

    private AuthResourceMapper getAuthResourceMapper() {
        return MapperProxyFactory.getProxy(AuthResourceMapper.class);
    }

    private AuthMemberService getAuthMemberService(User user) {
        return ServiceUtil.getService(AuthMemberServiceImpl.class, user);
    }

    private AuthOptService getAuthOptService(User user) {
        return ServiceUtil.getService(AuthOptServiceImpl.class, user);
    }

    private AuthDataService getAuthDataService(User user) {
        return ServiceUtil.getService(AuthDataServiceImpl.class, user);
    }


    @Override
    public PageInfo<AuthRoleDTO> roleList(AuthRoleListQueryParam param) {

        List<AuthRolePO> authRolePOS = getAuthRoleMapper().list(param);
        int total = authRolePOS.size();

        List<AuthRoleDTO> list = SalaryPageUtil.subList(param.getCurrent(), param.getPageSize(), authRolePOS)
                .stream().map(po -> {
                    Long roleId = po.getId();
                    AuthMemberQueryParam roleQueryParam = AuthMemberQueryParam.builder().roleId(roleId).build();
                    List<AuthRoleEmpDTO> authRoleEmpDTOS = getAuthMemberService(user).listRoleEmp(roleQueryParam);
                    List<AuthOptPO> authOptPOS = getAuthOptService(user).listOpts(roleId);
                    AuthDataQueryParam dataQueryParam = AuthDataQueryParam.builder().roleId(roleId).build();
                    List<AuthRoleDataDTO> authRoleDataDTOS = getAuthDataService(user).listRoleData(dataQueryParam);
                    List<AuthResourcePO> authResources = getAuthResourceMapper().listSome(AuthResourcePO.builder().roleId(roleId).build());

                    return AuthRoleDTO.builder().id(roleId)
                            .name(po.getName())
                            .description(po.getDescription())
                            .members(authRoleEmpDTOS.size())
                            .opts(authOptPOS.size())
                            .datas(authRoleDataDTOS.size())
                            .resources(authResources.size())
                            .build();
                }).collect(Collectors.toList());
        PageInfo<AuthRoleDTO> pageInfo = SalaryPageUtil.buildPage(param.getCurrent(), param.getPageSize(), AuthRoleDTO.class);
        pageInfo.setList(list);
        pageInfo.setTotal(total);
        return pageInfo;
    }

    @Override
    public AuthRoleDTO getRole(Long id) {
        AuthRolePO po = getAuthRoleMapper().getById(id);
        if (po == null) {
            throw new SalaryRunTimeException("业务线不存在");
        }
        Long roleId = po.getId();
        List<AuthResourcePO> authResources = getAuthResourceMapper().listSome(AuthResourcePO.builder().roleId(roleId).build());

        List<TaxAgentPO> taxAgentIds = new ArrayList<>();
        List<SalarySobPO> sobIds = new ArrayList<>();
        authResources.forEach(resource -> {
            if (ResourceTargetTypeEnum.TAX_AGENT.getValue().equals(resource.getTargetType())) {
                taxAgentIds.add(TaxAgentPO.builder().id(resource.getTarget()).name(resource.getTargetName()).build());
            } else if (ResourceTargetTypeEnum.SOB.getValue().equals(resource.getTargetType())) {
                sobIds.add(SalarySobPO.builder().id(resource.getTarget()).name(resource.getTargetName()).build());
            }
        });

        return AuthRoleDTO.builder()
                .id(roleId)
                .name(po.getName())
                .description(po.getDescription())
                .taxAgentIds(taxAgentIds)
                .sobIds(sobIds)
                .build();
    }

    @Override
    public Long saveRole(AuthRoleSaveParam param) {
        Date now = new Date();
        Long id = param.getId();
        String name = param.getName();
        String description = param.getDescription();

        AuthRolePO po;
        if (id == null) {
            po = AuthRolePO.builder()
                    .id(IdGenerator.generate())
                    .name(name)
                    .description(description)
                    .creator((long) user.getUID())
                    .createTime(now)
                    .updateTime(now)
                    .deleteType(0)
                    .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                    .build();
            getAuthRoleMapper().insertIgnoreNull(po);

            LoggerContext<AuthRolePO> loggerContext = new LoggerContext<>();
            loggerContext.setUser(user);
            loggerContext.setTargetId(po.getId() + "");
            loggerContext.setTargetName("业务线：" + name);
            loggerContext.setOperateType(OperateTypeEnum.ADD.getValue());
            loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "新增业务线"));
            loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "新增业务线"));
            loggerContext.setNewValues(po);
            SalaryElogConfig.authLinkLoggerTemplate.write(loggerContext);

        } else {
            po = getAuthRoleMapper().getById(id);
            if (po == null) {
                throw new SalaryRunTimeException("业务线不存在！");
            }
            AuthRolePO newPo = AuthRolePO.builder()
                    .id(id)
                    .name(name)
                    .description(description)
                    .updateTime(now)
                    .build();
            getAuthRoleMapper().updateIgnoreNull(newPo);

            LoggerContext<AuthRolePO> loggerContext = new LoggerContext<>();
            loggerContext.setUser(user);
            loggerContext.setTargetId(po.getId() + "");
            loggerContext.setTargetName("业务线：" + name);
            loggerContext.setOperateType(OperateTypeEnum.UPDATE.getValue());
            loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "更新业务线"));
            loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "更新业务线"));
            loggerContext.setOldValues(po);
            loggerContext.setNewValues(newPo);
            SalaryElogConfig.authLinkLoggerTemplate.write(loggerContext);
        }

        getAuthResourceMapper().deleteByRoleId(po.getId());

        List<TaxAgentPO> taxAgents = param.getTaxAgentIds();
        List<SalarySobPO> sobs = param.getSobIds();
        if (CollectionUtil.isNotEmpty(taxAgents)) {
            taxAgents.forEach(tax -> {
                AuthResourcePO resourcePO = AuthResourcePO.builder()
                        .id(IdGenerator.generate())
                        .roleId(po.getId())
                        .target(tax.getId())
                        .targetType(ResourceTargetTypeEnum.TAX_AGENT.getValue())
                        .targetName(tax.getName())
                        .creator((long) user.getUID())
                        .createTime(now)
                        .updateTime(now)
                        .deleteType(0)
                        .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                        .build();
                getAuthResourceMapper().insertIgnoreNull(resourcePO);
            });
        }
        if (CollectionUtil.isNotEmpty(sobs)) {
            sobs.forEach(sob -> {
                AuthResourcePO resourcePO = AuthResourcePO.builder()
                        .id(IdGenerator.generate())
                        .roleId(po.getId())
                        .target(sob.getId())
                        .targetType(ResourceTargetTypeEnum.SOB.getValue())
                        .targetName(sob.getName())
                        .creator((long) user.getUID())
                        .createTime(now)
                        .updateTime(now)
                        .deleteType(0)
                        .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                        .build();
                getAuthResourceMapper().insertIgnoreNull(resourcePO);
            });
        }

        return po.getId();
    }

    @Override
    public void deleteRole(List<Long> ids) {
        ids.forEach(roleId -> {
            AuthRolePO po = getAuthRoleMapper().getById(roleId);
            if (po == null) {
                throw new SalaryRunTimeException("业务线不存在！");
            }

            getAuthResourceMapper().deleteByRoleId(roleId);
            getAuthMemberService(user).deleteByRoleId(roleId);
            getAuthOptService(user).deleteByRoleId(roleId);
            getAuthDataService(user).deleteByRoleId(roleId);
            getAuthRoleMapper().deleteByIds(Collections.singleton(roleId));


            LoggerContext<AuthRolePO> loggerContext = new LoggerContext<>();
            loggerContext.setUser(user);
            loggerContext.setTargetId(po.getId() + "");
            loggerContext.setTargetName("业务线：" + po.getName());
            loggerContext.setOperateType(OperateTypeEnum.DELETE.getValue());
            loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "删除业务线"));
            loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "删除业务线"));
            loggerContext.setNewValues(po);
            SalaryElogConfig.authLinkLoggerTemplate.write(loggerContext);
        });
    }

    @Override
    public List<AuthRolePO> listAll() {
        return getAuthRoleMapper().listAll();
    }
}
