package cn.iocoder.yudao.module.smartfactory.service.factoryinfo;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.DeptTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.ip.core.Area;
import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.smartfactory.controller.admin.factoryinfo.vo.*;
import cn.iocoder.yudao.module.smartfactory.controller.admin.screendata.factory.vo.FactoryRollDataRespVO;
import cn.iocoder.yudao.module.smartfactory.controller.admin.screendata.factory.vo.ProvincesDataRespVO;
import cn.iocoder.yudao.module.smartfactory.dal.dataobject.factoryinfo.FactoryInfoDO;
import cn.iocoder.yudao.module.smartfactory.dal.mysql.factoryinfo.FactoryInfoMapper;
import cn.iocoder.yudao.module.system.api.customersettlement.SettlementApi;
import cn.iocoder.yudao.module.system.api.customersettlement.dto.SettlementItemDTO;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.smartfactory.enums.ErrorCodeConstants.FACTORY_INFO_NOT_EXISTS;
import static cn.iocoder.yudao.module.smartfactory.enums.ErrorCodeConstants.FACTOYRY_EXISTS_STAFF;

/**
 * 工厂信息 Service 实现类
 *
 * @author 姚君
 */
@Service
@Validated
public class FactoryInfoServiceImpl implements FactoryInfoService {

    @Resource
    private FactoryInfoMapper factoryInfoMapper;

    @Resource
    private DeptApi deptApi;

    @Resource
    private AdminUserApi userApi;

    @Resource
    private PermissionApi permissionApi;

    @Resource
    private SettlementApi settlementApi;

    @Override
    public Long createFactoryInfo(FactoryInfoSaveReqVO createReqVO) {
        // 插入
        FactoryInfoDO factoryInfo = BeanUtils.toBean(createReqVO, FactoryInfoDO.class);
        factoryInfoMapper.insert(factoryInfo);

        // 新增的为工厂类型时
        if ("3".equals(createReqVO.getType())) {

            //同步插入对应 生产部的下级部门
            DeptRespDTO deptRespDTO = new DeptRespDTO();
            deptRespDTO.setFactoryId(factoryInfo.getId());
            deptRespDTO.setName(createReqVO.getShortName());
            deptRespDTO.setParentId(169L);  //这里设置上级部门为 生产部
            deptRespDTO.setLeaderUserId(createReqVO.getLeaderUserId());
            deptRespDTO.setStatus(CommonStatusEnum.ENABLE.getStatus());
            deptRespDTO.setType(DeptTypeEnum.PRODUCTION_DEPT.getValue());
            deptRespDTO.setVirtuallyStatus(0);
            deptApi.createDept(deptRespDTO);
        }

        // 返回
        return factoryInfo.getId();
    }

    @Override
    public void updateFactoryInfo(FactoryInfoSaveReqVO updateReqVO) {
        // 校验存在
        validateFactoryInfoExists(updateReqVO.getId());
        // 更新
        FactoryInfoDO updateObj = BeanUtils.toBean(updateReqVO, FactoryInfoDO.class);
        factoryInfoMapper.updateById(updateObj);

        //同步更新 部门信息
        DeptRespDTO deptRespDTO = new DeptRespDTO();
        deptRespDTO.setName(updateReqVO.getShortName());
        deptRespDTO.setLeaderUserId(updateReqVO.getLeaderUserId());
        deptRespDTO.setFactoryId(updateReqVO.getId());
        deptApi.updateFactoryDept(deptRespDTO);
    }

    @Override
    public void deleteFactoryInfo(Long id) {
        // 校验存在
        validateFactoryInfoExists(id);

        //校验工厂下是否存在 员工
        DeptRespDTO deptRespDTO = deptApi.getDeptByFactoryId(id).getCheckedData();
        if (deptRespDTO != null) {
            List<AdminUserRespDTO> userRespDTOS = userApi.getUserByDeptIdAll(deptRespDTO.getId()).getCheckedData();

            if (userRespDTOS != null && !userRespDTOS.isEmpty()) {
                throw exception(FACTOYRY_EXISTS_STAFF);
            }

            //同步删除部门
            deptApi.deleteDept(id);
        }

        // 删除
        factoryInfoMapper.deleteById(id);
    }

    private void validateFactoryInfoExists(Long id) {
        if (factoryInfoMapper.selectById(id) == null) {
            throw exception(FACTORY_INFO_NOT_EXISTS);
        }
    }

    @Override
    public FactoryInfoDO getFactoryInfo(Long id) {

        return factoryInfoMapper.selectById(id);
    }

    @Override
    public List<FactoryInfoDO> getFactoryList() {

        return factoryInfoMapper.selectList();
    }

    @Override
    public List<FactoryInfoDO> getFactoryList(Collection<Long> ids) {
        if (CollectionUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        ids = ids.stream().filter(Objects::nonNull).collect(Collectors.toList());
        return factoryInfoMapper.selectList(new LambdaQueryWrapper<FactoryInfoDO>()
                .in(CollectionUtil.isNotEmpty(ids), FactoryInfoDO::getId, ids));
    }


    @Override
    public List<FactoryInfoDO> getFactoryByIds(Collection<Long> ids) {
        ids = ids.stream().filter(Objects::nonNull).collect(Collectors.toList());
        return factoryInfoMapper.selectList(new LambdaQueryWrapper<FactoryInfoDO>()
                .in(CollectionUtil.isNotEmpty(ids), FactoryInfoDO::getId, ids));
    }

    @Override
    public List<FactoryInfoDO> getFactoryList(Long factoryId, String name) {

        return factoryInfoMapper.selectList(new LambdaQueryWrapperX<FactoryInfoDO>()
                .eqIfPresent(FactoryInfoDO::getId, factoryId)
                .likeIfPresent(FactoryInfoDO::getName, name));
    }

    @Override
    public List<FactoryInfoDO> getFactoryListByType() {

        return factoryInfoMapper.selectListByType(null);
    }

    @Override
    public PageResult<FactoryInfoDO> getFactoryInfoPage(FactoryInfoPageReqVO pageReqVO) {
        return factoryInfoMapper.selectPage(pageReqVO);
    }

    @Override
    public List<ProvincesDataRespVO> getProvincesData(String code) {
        // -- 获取当前的地区
        Area area = AreaUtils.getArea(Integer.valueOf(code));
        List<ProvincesDataRespVO> vos = new ArrayList<>();
        LambdaQueryWrapperX<FactoryInfoDO> lambdaQueryWrapperX = new LambdaQueryWrapperX<FactoryInfoDO>();
        // 只查询 type为工厂类型的 工厂信息
        lambdaQueryWrapperX.eq(FactoryInfoDO::getType, 3L);
        //去除关闭状态工厂
        lambdaQueryWrapperX.eq(FactoryInfoDO::getStatus, CommonStatusEnum.ENABLE.getStatus());

        Integer type = area.getType() - 1;
        if (!type.equals(FactoryInfoDO.ADDRESS_TYPE_NATIONWIDE)) {
            lambdaQueryWrapperX.eq(FactoryInfoDO.ADDRESS_TYPE_PROVINCE.equals(type), FactoryInfoDO::getProvinceId, code)
                    .eq(FactoryInfoDO.ADDRESS_TYPE_CITY.equals(type), FactoryInfoDO::getCityId, code)
                    .eq(FactoryInfoDO.ADDRESS_TYPE_DISTRICT_NAME.equals(type), FactoryInfoDO::getAdCode, code);
        }
        List<FactoryInfoDO> dos = factoryInfoMapper.selectList(
                lambdaQueryWrapperX
        );
        Map<Long, List<FactoryInfoDO>> map = new HashMap<>();
        if (FactoryInfoDO.ADDRESS_TYPE_NATIONWIDE.equals(type)) {
            map = dos.stream().collect(Collectors.groupingBy(FactoryInfoDO::getProvinceId));
        }
        if (FactoryInfoDO.ADDRESS_TYPE_PROVINCE.equals(type)) {
            map = dos.stream().collect(Collectors.groupingBy(FactoryInfoDO::getCityId));
        }
        if (FactoryInfoDO.ADDRESS_TYPE_CITY.equals(type)) {
            map = dos.stream().collect(Collectors.groupingBy(FactoryInfoDO::getAdCode));
        }
        if (FactoryInfoDO.ADDRESS_TYPE_DISTRICT_NAME.equals(type)) {
            map = dos.stream().collect(Collectors.groupingBy(FactoryInfoDO::getId));
        }
        for (Map.Entry<Long, List<FactoryInfoDO>> entry : map.entrySet()) {
            ProvincesDataRespVO vo = new ProvincesDataRespVO();
            vo.setAdCode(entry.getKey());
            vo.setValue(entry.getValue().size());
            vo.setVos(entry.getValue());
            vos.add(vo);
        }
        return vos;
    }

    @Override
    public List<FactoryRollDataRespVO> getFactoryRollData() {
        return factoryInfoMapper.getFactoryRollData();
    }

    @Override
    public List<FactoryInfoDO> list() {
        return factoryInfoMapper.selectList();
    }

    @Override
    public String getWeatherCodeByFactoryId(Long factoryId, String areaCode) {
        return factoryInfoMapper.getWeatherCodeByFactoryId(factoryId, areaCode);
    }

    @Override
    public List<FactoryInfoDO> getFactoryListByAuthority() {

        List<Long> factoryIds = new ArrayList<>();
        DeptDataPermissionRespDTO deptDataPermission = permissionApi.getDeptDataPermission(getLoginUserId()).getCheckedData();
        // 如果当前登录用户数据权限 不是查看全部数据
        if (!deptDataPermission.getAll()) {

            // 获取自己所在工厂
            DeptRespDTO respDTO = deptApi.getDept(userApi.getUser(getLoginUserId()).getCheckedData().getDeptId()).getCheckedData();
            if (respDTO != null && respDTO.getFactoryId() != null) {
                factoryIds.add(respDTO.getFactoryId());
            }

            // 查找担任负责人的工厂信息
            List<DeptRespDTO> deptRespDTO = deptApi.getDeptByLeaderId(getLoginUserId()).getCheckedData();

            if (deptRespDTO != null) {

                factoryIds.addAll(convertList(deptRespDTO, DeptRespDTO::getFactoryId));
            }
        }

        return factoryInfoMapper.selectListByType(factoryIds);
    }

    @Override
    public FactoryInfoDO getFactoryByName(String factoryName) {

        return factoryInfoMapper.selectOne(FactoryInfoDO::getShortName, factoryName);
    }

    @Override
    public void updateFactoryStatus(FactoryUpdateStatusReqVO updateReqVO) {
        // 校验存在
        validateFactoryInfoExists(updateReqVO.getId());

        // 更新
        FactoryInfoDO updateObj = BeanUtils.toBean(updateReqVO, FactoryInfoDO.class);
        factoryInfoMapper.updateById(updateObj);

        //同步更新 工厂部门状态
        DeptRespDTO deptRespDTO = new DeptRespDTO();
        deptRespDTO.setFactoryId(updateReqVO.getId());
        deptRespDTO.setStatus(updateReqVO.getStatus());
        deptApi.updateFactoryDept(deptRespDTO);
    }

    @Override
    public List<FactoryProfitVO> getProfit(Long factoryId, String month) {

        List<FactoryProfitVO> result = factoryInfoMapper.selectProfit(factoryId, month);

        // 获取结算扣款明细
        List<SettlementItemDTO> itemList = settlementApi.getDeductionItems(factoryId, month).getCheckedData();
        Map<Long, List<SettlementItemDTO>> itemMap = convertMultiMap(itemList, SettlementItemDTO::getFactoryId);

        if (CollUtil.isNotEmpty(result)) {
            // 设置叉车毛利、打包毛利、搬运毛利 = 收入 - 扣款 - 人员工资 - 支出
            result.forEach(vo -> {
                // 设置叉车毛利
                vo.setForkliftGrossProfit(vo.getForkliftRevenue()
                        .subtract(vo.getForkliftDeduction())
                        .subtract(vo.getForkliftSalary())
                        .subtract(vo.getForkliftExpenses()));
                // 设置打包毛利
                vo.setPackageGrossProfit(vo.getPackageRevenue()
                        .subtract(vo.getPackageDeduction())
                        .subtract(vo.getPackageSalary())
                        .subtract(vo.getPackageExpenses()));
                // 设置搬运毛利
                vo.setPorterageGrossProfit(vo.getPorterageRevenue()
                        .subtract(vo.getPorterageDeduction())
                        .subtract(vo.getPorterageSalary())
                        .subtract(vo.getTransportationExpenses()));

                // 设置扣款明细
                List<SettlementItemDTO> item = itemMap.get(vo.getFactoryId());
                if (CollUtil.isNotEmpty(item)) {
                    // 获取打包扣款明细
                    List<SettlementItemDTO.Deduction> packageDeduction = item.stream()
                            .filter(data -> data.getBusinessType() == 1)
                            .flatMap( data -> data.getDeductionItems().stream())
                            .collect(Collectors.toList());

                    // 获取叉车扣款明细
                    List<SettlementItemDTO.Deduction> forkliftDeduction = item.stream()
                            .filter(data -> data.getBusinessType() == 2)
                            .flatMap( data -> data.getDeductionItems().stream())
                            .collect(Collectors.toList());

                    // 获取搬运扣款明细
                    List<SettlementItemDTO.Deduction> porterageDeduction = item.stream()
                            .filter(data -> data.getBusinessType() == 3)
                            .flatMap( data -> data.getDeductionItems().stream())
                            .collect(Collectors.toList());

                    // 设置打包扣款
                    vo.setPackageDeductionItem(getDeduction(packageDeduction));
                    // 设置叉车扣款
                    vo.setForkliftDeductionItem(getDeduction(forkliftDeduction));
                    // 设置搬运扣款
                    vo.setPorterageDeductionItem(getDeduction(porterageDeduction));
                }else {
                    // 设置打包扣款
                    vo.setPackageDeductionItem(getDeduction(null));
                    // 设置叉车扣款
                    vo.setForkliftDeductionItem(getDeduction(null));
                    // 设置搬运扣款
                    vo.setPorterageDeductionItem(getDeduction(null));
                }
            });
        }

        return result;
    }

    private FactoryProfitVO.Deduction getDeduction(List<SettlementItemDTO.Deduction> item) {

        FactoryProfitVO.Deduction deduction = new FactoryProfitVO.Deduction();
        if (CollUtil.isNotEmpty(item)) {
            BigDecimal administrativePenalty = item.stream()
                    .filter(data -> "xzfk".equals(data.getKey()))
                    .map(SettlementItemDTO.Deduction::getValue)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            BigDecimal damagePenalty = item.stream()
                    .filter(data -> "psfk".equals(data.getKey()))
                    .map(SettlementItemDTO.Deduction::getValue)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            BigDecimal missPenalty = item.stream()
                    .filter(data -> "sjkk".equals(data.getKey()))
                    .map(SettlementItemDTO.Deduction::getValue)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            BigDecimal other = item.stream()
                    .filter(data -> !"xzfk".equals(data.getKey()) && !"psfk".equals(data.getKey()) && !"sjkk".equals(data.getKey()))
                    .map(SettlementItemDTO.Deduction::getValue)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            // 设置扣款项，默认为 0
            deduction.setAdministrativePenalty(administrativePenalty);
            deduction.setDamagePenalty(damagePenalty);
            deduction.setMissPenalty(missPenalty);
            deduction.setOtherPenalty(other);
        } else {
            // 如果 item 为空，则所有值设为 0
            deduction.setAdministrativePenalty(BigDecimal.ZERO);
            deduction.setDamagePenalty(BigDecimal.ZERO);
            deduction.setMissPenalty(BigDecimal.ZERO);
            deduction.setOtherPenalty(BigDecimal.ZERO);
        }

        return deduction;
     }

    @Override
    public List<FactoryInfoDO> getCompanyFactoryList() {

        return factoryInfoMapper.selectList(new LambdaQueryWrapperX<FactoryInfoDO>()
                .eq(FactoryInfoDO::getStatus, CommonStatusEnum.ENABLE.getStatus())
                .in(FactoryInfoDO::getType, Arrays.asList(0,1)));
    }

    @Override
    public List<FactoryInfoDO> getFactoryListByLoginUser() {

        List<Long> factoryIds = new ArrayList<>();
        // 获取自己所在工厂
        DeptRespDTO respDTO = deptApi.getDept(userApi.getUser(getLoginUserId()).getCheckedData().getDeptId()).getCheckedData();
        if (respDTO != null && respDTO.getFactoryId() != null) {
            factoryIds.add(respDTO.getFactoryId());
        }

        // 查找担任负责人的工厂信息
        List<DeptRespDTO> deptRespDTO = deptApi.getDeptByLeaderId(getLoginUserId()).getCheckedData();

        if (deptRespDTO != null) {

            factoryIds.addAll(convertList(deptRespDTO, DeptRespDTO::getFactoryId));
        }

        return factoryInfoMapper.selectListByType(factoryIds);
    }

    @Override
    public List<FactoryInfoDO> getList() {

        return factoryInfoMapper.selectList(new LambdaQueryWrapperX<FactoryInfoDO>()
                .eq(FactoryInfoDO::getStatus, CommonStatusEnum.ENABLE.getStatus())
                .orderByAsc(FactoryInfoDO::getType));
    }
}
