package com.lantone.security.facade;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.lantone.common.enums.DataAuthDataTypeEnum;
import com.lantone.common.enums.DataAuthDetailTypeEnum;
import com.lantone.common.enums.IsDeleteEnum;
import com.lantone.common.exception.Asserts;
import com.lantone.common.service.RedisService;
import com.lantone.common.util.DateUtil;
import com.lantone.common.util.EntityUtil;
import com.lantone.common.util.ListUtil;
import com.lantone.common.util.SysUserUtils;
import com.lantone.security.dto.DataAuthDetailDTO;
import com.lantone.security.dto.GetDataAuthByIdDTO;
import com.lantone.security.dto.GetDataAuthPageDTO;
import com.lantone.security.dto.GetDataAuthRoleDTO;
import com.lantone.security.dto.GetDataAuthSoftwareDTO;
import com.lantone.security.dto.GetDoctorPageDTO;
import com.lantone.security.dto.SoftwareDataAuthDetail;
import com.lantone.security.entity.DataAuth;
import com.lantone.security.entity.DataAuthDetail;
import com.lantone.security.entity.Role;
import com.lantone.security.entity.RoleSoftwareDataAuth;
import com.lantone.security.entity.SoftwareDataAuth;
import com.lantone.security.enums.SoftwareEnum;
import com.lantone.security.facade.base.DataAuthDetailFacade;
import com.lantone.security.facade.base.DataAuthFacade;
import com.lantone.security.facade.base.DeptFacade;
import com.lantone.security.facade.base.DeptUserFacade;
import com.lantone.security.facade.base.DoctorFacade;
import com.lantone.security.facade.base.HospitalFacade;
import com.lantone.security.facade.base.HospitalUserFacade;
import com.lantone.security.facade.base.MedoupDoctorFacade;
import com.lantone.security.facade.base.RoleFacade;
import com.lantone.security.facade.base.RoleSoftwareDataAuthFacade;
import com.lantone.security.facade.base.SoftwareDataAuthFacade;
import com.lantone.security.facade.base.UserFacade;
import com.lantone.security.service.impl.DataAuthDetailServiceImpl;
import com.lantone.security.service.impl.RoleSoftwareDataAuthServiceImpl;
import com.lantone.security.vo.AddAuthSoftwareVO;
import com.lantone.security.vo.AddAuthVO;
import com.lantone.security.vo.GetDataAuthPageVO;
import com.lantone.security.vo.GetDoctorPageVO;
import com.lantone.security.vo.UpdateAuthVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;


/**
 * @Description:数据权限操作facade
 * @Author songxl
 * @Date 2021/7/21
 */
@Component
public class DataAuthManagementFacade {
    @Autowired
    private DataAuthFacade dataAuthFacade;
    @Autowired
    private SoftwareDataAuthFacade softwareDataAuthFacade;
    @Autowired
    private RoleSoftwareDataAuthFacade roleSoftwareDataAuthFacade;
    @Autowired
    private DataAuthDetailFacade dataAuthDetailFacade;
    @Autowired
    private HospitalFacade hospitalFacade;
    @Autowired
    private DeptFacade deptFacade;
    @Autowired
    private DoctorFacade doctorFacade;
    @Autowired
    private HospitalUserFacade hospitalUserFacade;
    @Autowired
    private RedisService redisService;
    @Autowired
    private DeptUserFacade deptUserFacade;
    @Autowired
    private UserFacade userFacade;
    @Autowired
    private RoleFacade roleFacade;
    @Autowired
    private MedoupDoctorFacade medoupDoctorFacade;


    /**
     * @param Id
     * @param status
     * @Description禁用启用数据权限
     * @Return boolean
     */
    public boolean disableDataAuth(Long Id, String status) {
        return dataAuthFacade.update(new UpdateWrapper<DataAuth>()
                .set("status", status)
                .eq("id", Id)
                .eq("is_deleted", IsDeleteEnum.N.getKey()));
    }

    /**
     * @Description修改数据权限
     * @Param [softwareDataAuthVO]
     * @Return boolean
     */
    public boolean updateDataAuth(UpdateAuthVO updateAuthVO) {
        //校验
        check(updateAuthVO.getUpdateDataAuthVO().getId(), updateAuthVO.getUpdateDataAuthVO().getName(), updateAuthVO.getUpdateDataAuthVO().getSoftwareVOS());
        //1.修改数据权限
        boolean dataAuthUpdate = dataAuthFacade.update(new UpdateWrapper<DataAuth>()
                .set("name", updateAuthVO.getUpdateDataAuthVO().getName())
                .eq("id", updateAuthVO.getUpdateDataAuthVO().getId())
                .eq("is_deleted", IsDeleteEnum.N.getKey()));
        if (dataAuthUpdate) {
            //2.获取该权限 系统与数据权限信息关联表（sys_service_data_auth）的关联id
            List<Long> serviceDataAuthIDS = softwareDataAuthFacade.list(new QueryWrapper<SoftwareDataAuth>()
                    .eq("data_auth_id", updateAuthVO.getUpdateDataAuthVO().getId())
                    .eq("is_deleted", IsDeleteEnum.N.getKey())).stream().map(SoftwareDataAuth::getId).collect(Collectors.toList());
            //3.通过serviceDataAuthIDS 删除sys_role_service_data_auth和sys_service_data_auth和sys_data_auth_detail 对应关系
            if (ListUtil.isNotEmpty(serviceDataAuthIDS)) {
                if (!deleteServiceDataAuth(serviceDataAuthIDS)) {
                    Asserts.fail("数据权限与系统关系删除失败");
                }
            }
            //4.插入新建数据权限与系统的关系
            return saveServiceDataAuth(updateAuthVO.getUpdateDataAuthVO().getSoftwareVOS(), updateAuthVO.getUpdateDataAuthVO().getId());
        } else {
            Asserts.fail("数据权限修改失败");
        }
        return false;
    }

    /**
     * @Description通过serviceDataAuthIDS删除sys_role_service_data_auth和sys_service_data_auth和sys_data_auth_detail对应关系
     * @Param [serviceDataAuthIDS]
     * @Return void
     */
    public boolean deleteServiceDataAuth(List<Long> serviceDataAuthIDS) {
        if (dataAuthDetailFacade.remove(new UpdateWrapper<DataAuthDetail>()
                .in("software_data_auth_id", serviceDataAuthIDS)
                .eq("is_deleted", IsDeleteEnum.N.getKey()))) {
            if (roleSoftwareDataAuthFacade.remove(new UpdateWrapper<RoleSoftwareDataAuth>()
                    .in("software_data_auth_id", serviceDataAuthIDS)
                    .eq("is_deleted", IsDeleteEnum.N.getKey()))) {
                return softwareDataAuthFacade.remove(new UpdateWrapper<SoftwareDataAuth>()
                        .in("id", serviceDataAuthIDS)
                        .eq("is_deleted", IsDeleteEnum.N.getKey()));
            } else {
                Asserts.fail("数据权限与系统、角色关联关系删除失败");
            }
        } else {
            Asserts.fail("系统数据权限与数据权限明细关联关系删除失败");
        }
        return false;
    }

    /**
     * @param Id
     * @Description删除数据权限
     * @Return boolean
     */
    public boolean deleteDataAuth(Long Id) {
        //1.删除数据权限
        boolean dataAuthdelete = dataAuthFacade.update(new UpdateWrapper<DataAuth>()
                .set("is_deleted", IsDeleteEnum.Y.getKey())
                .eq("id", Id));
        if (dataAuthdelete) {
            //2.获取该权限 系统与数据权限信息关联表（sys_service_data_auth）的关联id
            List<Long> serviceDataAuthIDS = softwareDataAuthFacade.list(new QueryWrapper<SoftwareDataAuth>()
                    .eq("data_auth_id", Id)
                    .eq("is_deleted", IsDeleteEnum.N.getKey())).stream().map(SoftwareDataAuth::getId).collect(Collectors.toList());
            //3.通过serviceDataAuthIDS 删除sys_role_service_data_auth和sys_service_data_auth和sys_data_auth_detail 对应关系
            if (ListUtil.isNotEmpty(serviceDataAuthIDS)) {
                if (dataAuthDetailFacade.update(new UpdateWrapper<DataAuthDetail>()
                        .set("is_deleted", IsDeleteEnum.Y.getKey())
                        .in("software_data_auth_id", serviceDataAuthIDS)
                        .eq("is_deleted", IsDeleteEnum.N.getKey()))) {
                    if (roleSoftwareDataAuthFacade.update(new UpdateWrapper<RoleSoftwareDataAuth>()
                            .set("is_deleted", IsDeleteEnum.Y.getKey())
                            .in("software_data_auth_id", serviceDataAuthIDS)
                            .eq("is_deleted", IsDeleteEnum.N.getKey()))) {
                        return softwareDataAuthFacade.update(new UpdateWrapper<SoftwareDataAuth>()
                                .set("is_deleted", IsDeleteEnum.Y.getKey())
                                .in("id", serviceDataAuthIDS)
                                .eq("is_deleted", IsDeleteEnum.N.getKey()));
                    } else {
                        Asserts.fail("数据权限与系统、角色关联关系删除失败");
                    }
                } else {
                    Asserts.fail("系统数据权限与数据权限明细关联关系删除失败");
                }
            }
            return true;
        } else {
            Asserts.fail("数据权限删除失败");
        }
        return false;
    }

    /**
     * @param addAuthVO
     * @Description添加数据权限
     * @Return boolean
     */
    public boolean addDataAuth(AddAuthVO addAuthVO) {
        //校验
        check(null, addAuthVO.getAddDataAuthVO().getName(), addAuthVO.getAddDataAuthVO().getSoftwareVOS());
        //1.插入新建数据权限
        DataAuth dataAuth = new DataAuth();
        BeanUtils.copyProperties(addAuthVO.getAddDataAuthVO(), dataAuth);
        dataAuth.setGmtCreate(DateUtil.now());
        dataAuth.setCreator(SysUserUtils.getCurrentPrincipleId() + "");
        if (dataAuthFacade.save(dataAuth)) {
            //2.插入新建数据权限与系统的关系 sys_software_data_auth
            return saveServiceDataAuth(addAuthVO.getAddDataAuthVO().getSoftwareVOS(), dataAuth.getId());
        } else {
            Asserts.fail("数据权限插入失败");
        }
        return false;

    }

    /**
     * @param id
     * @param name
     * @param softwareVOS
     * @Description数据权限添加、修改时校验
     * @Return void
     */
    private void check(Long id, String name, List<AddAuthSoftwareVO> softwareVOS) {
        List<DataAuth> dataAuths = dataAuthFacade.list(new QueryWrapper<DataAuth>()
                .eq("name", name)
                .eq("is_deleted", IsDeleteEnum.N.getKey()));
        //数据权限名称校验
        if (id == null) {
            if (dataAuths.size() > 0) {
                Asserts.fail("该数据权限已存在，请重新输入");
            }
        } else {
            if (ListUtil.isNotEmpty(dataAuths)) {
                dataAuths.stream().forEach(dataAuth -> {
                    if (!id.equals(dataAuth.getId())) {
                        Asserts.fail("该数据权限已存在，请重新输入");
                    }
                });
            }
        }
        //绑定角色校验
        softwareVOS.stream().forEach(addAuthSoftwareVO -> {
            if (roleFacade.list(new QueryWrapper<Role>()
                    .in("id", addAuthSoftwareVO.getRoles())
                    .eq("is_deleted", IsDeleteEnum.N.getKey())).size() != addAuthSoftwareVO.getRoles().size()) {
                Asserts.fail("绑定角色存在变更，请刷新重试~");
            }
        });

    }

    /**
     * @param softwareVOS
     * @param dataAuthId
     * @Description插入新建数据权限与系统的关系
     * @Return void
     */
    private boolean saveServiceDataAuth(List<AddAuthSoftwareVO> softwareVOS, Long dataAuthId) {
        AtomicBoolean out = new AtomicBoolean(false);
        softwareVOS.stream().forEach(softwareVO -> {
            SoftwareDataAuth softwareDataAuth = new SoftwareDataAuth();
            softwareDataAuth.setSoftwareId(softwareVO.getId());
            softwareDataAuth.setDataAuthId(dataAuthId);
            softwareDataAuth.setGmtCreate(DateUtil.now());
            softwareDataAuth.setCreator(SysUserUtils.getCurrentPrincipleId() + "");
            if (softwareDataAuthFacade.save(softwareDataAuth)) {
                //2.插入数据权限系统关联表与角色管理sys_role_service_data_auth
                List<RoleSoftwareDataAuth> roleSoftwareDataAuths = new ArrayList<>();
                for (Long roleId : softwareVO.getRoles()) {
                    RoleSoftwareDataAuth roleServiceDataAuth = new RoleSoftwareDataAuth();
                    roleServiceDataAuth.setRoleId(roleId);
                    roleServiceDataAuth.setSoftwareDataAuthId(softwareDataAuth.getId());
                    roleServiceDataAuth.setGmtCreate(DateUtil.now());
                    roleServiceDataAuth.setCreator(SysUserUtils.getCurrentPrincipleId() + "");
                    roleSoftwareDataAuths.add(roleServiceDataAuth);
                }
                if (new RoleSoftwareDataAuthServiceImpl().saveBatch(roleSoftwareDataAuths)) {
                    //3.插入数据权限详细信息。sys_data_auth_detail
                    //自定义时
                    List<DataAuthDetail> dataAuthDetails = new ArrayList<>();
                    if (ListUtil.isNotEmpty(softwareVO.getDataAuthDetails())) {
                        softwareVO.getDataAuthDetails().stream().forEach(dataAuthDetailVO -> {
                            DataAuthDetail dataAuthDetail = new DataAuthDetail();
                            BeanUtils.copyProperties(dataAuthDetailVO, dataAuthDetail);
                            dataAuthDetail.setGmtCreate(DateUtil.now());
                            dataAuthDetail.setCreator(SysUserUtils.getCurrentPrincipleId() + "");
                            dataAuthDetail.setSoftwareDataAuthId(softwareDataAuth.getId());
                            dataAuthDetails.add(dataAuthDetail);
                        });
                    }
                    if (new DataAuthDetailServiceImpl().saveBatch(dataAuthDetails)) {
                        out.set(true);
                    } else {
                        Asserts.fail("数据权限详情插入失败");
                    }
                } else {
                    Asserts.fail("角色对应服务数据权限关系插入失败");
                }

            } else {
                Asserts.fail("服务对应数据权限关系插入失败");
            }
        });
        return out.get();
    }

    /**
     * @Description通过数据权限id获取数据权限详情
     * @Param [serviceDataAuthVO]
     * @Return com.lantone.security.dto.DataAuthDTO
     */
    public GetDataAuthByIdDTO getDataAuthById(Long Id) {
        GetDataAuthByIdDTO dataAuthDTO = new GetDataAuthByIdDTO();
        //1.获取数据权限基本信息
        DataAuth dataAuth = dataAuthFacade.getById(Id);
        if (dataAuth == null) {
            Asserts.fail("该数据权限不存在,请重试");
        }
        BeanUtils.copyProperties(dataAuth, dataAuthDTO);
        List<SoftwareDataAuth> softwareDataAuths = softwareDataAuthFacade.list(new QueryWrapper<SoftwareDataAuth>()
                .eq("data_auth_id", Id)
                .eq("is_deleted", IsDeleteEnum.N.getKey()));
        if (ListUtil.isEmpty(softwareDataAuths)) {
            Asserts.fail("该数据权限无系统信息，请联系管理员");
        }
        //2.系统-(角色、数据权限详情）信息组装
        List<GetDataAuthSoftwareDTO> softwares = new ArrayList<>();
        softwareDataAuths.stream().forEach(softwareDataAuth -> {
            //2.1获取系统信息
            GetDataAuthSoftwareDTO software = new GetDataAuthSoftwareDTO();
            software.setId(softwareDataAuth.getSoftwareId());
            software.setName(SoftwareEnum.getName(softwareDataAuth.getSoftwareId().intValue()));

            //2.2获取角色信息
            List<GetDataAuthRoleDTO> roles = roleSoftwareDataAuthFacade.getBaseMapper().getRole(softwareDataAuth.getId());
            software.setRoles(roles);
            //2.3数据权限详情
            List<SoftwareDataAuthDetail> softwareDataAuthDetails = softwareDataAuthFacade.getBaseMapper().getDataAuthDetail(softwareDataAuth.getId());
            if(ListUtil.isEmpty(softwareDataAuthDetails)){
                Asserts.fail("该数据权限有误，请联系管理员");
            }
            software.setDataType(softwareDataAuthDetails.get(0).getDataType());
            //--非自定义处理
                //--自定义处理
            if (softwareDataAuthDetails.get(0).getDataType() == DataAuthDataTypeEnum.CUSTOMIZE.getKey()) {
                //按自定义类型分类
                Map<Integer, List<SoftwareDataAuthDetail>> softwareDataAuthDetailMap = EntityUtil.makeEntityListMap(softwareDataAuthDetails, "detailType");
                //自定义数据
                DataAuthDetailDTO dataAuthDetail = new DataAuthDetailDTO();
                softwareDataAuthDetailMap.keySet().stream().forEach(detailType -> {
                    List<Long> ids = softwareDataAuthDetailMap
                            .get(detailType).stream().map(SoftwareDataAuthDetail::getDetailId).collect(Collectors.toList());
                    //医院
                    if (DataAuthDetailTypeEnum.HOSPITAL.getKey() == detailType) {
                        dataAuthDetail.setHospitals(hospitalFacade.getBaseMapper().getHospitals(ids));
                    }
                    //科室
                    if (DataAuthDetailTypeEnum.DEPT.getKey() == detailType) {
                        dataAuthDetail.setDepts(deptFacade.getBaseMapper().getDepts(ids));
                    }
                    //医生
                    if (DataAuthDetailTypeEnum.DOCTOR.getKey() == detailType) {
                        dataAuthDetail.setDoctors(deptFacade.getBaseMapper().getDoctors(ids));
                    }
                });
                software.setDataAuthDetail(dataAuthDetail);
            }
            softwares.add(software);
        });
        dataAuthDTO.setSoftwares(softwares);
        return dataAuthDTO;
    }


    /**
     * @param getDoctorPageVO
     * @Description通过医院id或科室id获取医生列表
     * @Return com.baomidou.mybatisplus.core.metadata.IPage<com.lantone.common.dto.DoctorDTO>
     */
    public IPage<GetDoctorPageDTO> getDoctorPage(GetDoctorPageVO getDoctorPageVO) {
        return doctorFacade.getBaseMapper().getDoctorPage(getDoctorPageVO);
    }

    /**
     * @param getDataAuthPageVO
     * @Description获取数据权限列表
     * @Return com.baomidou.mybatisplus.core.metadata.IPage<com.lantone.common.dto.DataAuthDTO>
     */
    public IPage<GetDataAuthPageDTO> getDataAuthPage(GetDataAuthPageVO getDataAuthPageVO) {
        //数据权限的创建者不一定是当前登录用户，创建者应为当前登录用户所在医院所有用户
        getDataAuthPageVO.setCreator(SysUserUtils.getCurrentPrincipleId());
        return dataAuthFacade.getBaseMapper().getDataAuthPage(getDataAuthPageVO);
    }

    public boolean initUserDataAuth(){
        dataAuthFacade.initUserDataAuth();
        return true;
    }

}