package com.qmth.sop.business.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qmth.boot.api.exception.ApiException;
import com.qmth.sop.business.bean.dto.DataPermissionDto;
import com.qmth.sop.business.bean.params.ServiceUnitParam;
import com.qmth.sop.business.bean.result.ReductionResult;
import com.qmth.sop.business.bean.result.ServiceUnitResult;
import com.qmth.sop.business.entity.SysDingGroup;
import com.qmth.sop.business.entity.SysUser;
import com.qmth.sop.business.entity.TBService;
import com.qmth.sop.business.mapper.TBServiceMapper;
import com.qmth.sop.business.service.SysDingGroupService;
import com.qmth.sop.business.service.SysUserRoleService;
import com.qmth.sop.business.service.TBServiceService;
import com.qmth.sop.common.contant.SystemConstant;
import com.qmth.sop.common.enums.*;
import com.qmth.sop.common.util.ResultUtil;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 服务单元表 服务实现类
 * </p>
 *
 * @author wangliang
 * @since 2023-08-01
 */
@Service
public class TBServiceServiceImpl extends ServiceImpl<TBServiceMapper, TBService> implements TBServiceService {
    @Resource
    private SysUserRoleService sysUserRoleService;
    @Resource
    private SysDingGroupService sysDingGroupService;

    @Override
    public List<TBService> listEnable(Long id) {
        return this.list(new QueryWrapper<TBService>().lambda().eq(TBService::getEnable, true).eq(TBService::getId, id));
    }

    @Transactional
    @Override
    public Long edit(ServiceUnitParam serviceUnitParam, SysUser requestUser) {
        try {
            Long id = serviceUnitParam.getId();
            Long leaderId = serviceUnitParam.getServiceLeadId();
            Long startTime = serviceUnitParam.getStartTime();
            Long endTime = serviceUnitParam.getEndTime();

            Integer regionPeopleCount = serviceUnitParam.getRegionPeopleCount();
            Integer regionProjectCount = serviceUnitParam.getRegionProjectCount();
            ReductionResult reduction = this.reduction(regionPeopleCount, regionProjectCount);

            if (endTime < startTime) {
                throw ExceptionResultEnum.ERROR.exception("服务截止时间不能小于服务开始时间");
            }

            if (!sysUserRoleService.userContainsRoles(leaderId, RoleTypeEnum.BUSSINESS)) {
                throw ExceptionResultEnum.ERROR.exception("不包含'业务线负责人'角色的用户不能充当服务单元的负责人");
            }

            TBService tbService = new TBService();
            tbService.setName(serviceUnitParam.getName());
            tbService.setType(serviceUnitParam.getType());
            tbService.setStartTime(serviceUnitParam.getStartTime());
            tbService.setEndTime(serviceUnitParam.getEndTime());
            tbService.setRegionPeopleCount(reduction.getMolecular());
            tbService.setRegionProjectCount(reduction.getDenominator());
            tbService.setServiceLeadId(serviceUnitParam.getServiceLeadId());
            if (Objects.isNull(id)) {
                // id不存在新增
                tbService.setEnable(true);
                tbService.setStatus(ServiceStatusEnum.NEW);
                tbService.setCreateId(requestUser.getId());
                this.save(tbService);
                id = tbService.getId();
            } else {
                // id存在更新
                tbService.setId(id);
                tbService.setUpdateId(requestUser.getUpdateId());
                this.updateById(tbService);
            }
            return id;
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (e instanceof DuplicateKeyException) {
                String errorColumn = e.getCause().toString();
                String columnStr = errorColumn.substring(errorColumn.lastIndexOf("key") + 3).replaceAll("'", "");
                throw ExceptionResultEnum.SQL_ERROR.exception("[" + FieldUniqueEnum.convertToTitle(columnStr) + "]数据不允许重复插入");
            } else if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, ((ApiException) e).getCode(), e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
            return null;
        }
    }

    @Override
    public IPage<ServiceUnitResult> page(ProductTypeEnum type, Long serviceLeadId, ServiceStatusEnum status,
                                         Long createStartTime, Long createEndTime, String serviceUnitName, Integer pageNumber, Integer pageSize) {
        if (serviceUnitName != null && serviceUnitName.length() > 0) {
            serviceUnitName = SystemConstant.translateSpecificSign(serviceUnitName);
        }
        return this.baseMapper.findServiceUnitPage(new Page<>(pageNumber, pageSize), type, serviceLeadId, status, createStartTime, createEndTime, serviceUnitName);
    }

    @Transactional
    @Override
    public void cancelServiceUnit(Long serviceUnitId) {
        TBService tbService = this.getById(serviceUnitId);
        if (Objects.isNull(tbService)) {
            throw ExceptionResultEnum.ERROR.exception("未找到服务单元");
        }
        ServiceStatusEnum status = tbService.getStatus();
        if (!ServiceStatusEnum.NEW.equals(status)) {
            throw ExceptionResultEnum.ERROR.exception(String.format("只有[%s]状态的服务单元可以被删除，当前状态[%s]", ServiceStatusEnum.NEW.getTitle(), status.getTitle()));
        }
        tbService.setStatus(ServiceStatusEnum.CANCEL);
        tbService.setEnable(false);
        this.updateById(tbService);
    }

    @Transactional
    @Override
    public void publishServiceUnit(Long serviceUnitId) {
        TBService tbService = this.getById(serviceUnitId);
        if (Objects.isNull(tbService)) {
            throw ExceptionResultEnum.ERROR.exception("未找到服务单元");
        }
        ServiceStatusEnum status = tbService.getStatus();
        if (!ServiceStatusEnum.NEW.equals(status) && !ServiceStatusEnum.FINISH.equals(status)) {
            throw ExceptionResultEnum.ERROR.exception(String.format("只有[%s]状态的服务单元可以被发布，当前状态[%s]", ServiceStatusEnum.NEW.getTitle() + "或" + ServiceStatusEnum.FINISH.getTitle(), status.getTitle()));
        }
        // TODO: 2023/8/8 业务校验 服务单元完成了相关准备工作：服务范围划定、供应商划定
        List<SysDingGroup> sysDingGroupList = sysDingGroupService.list(new QueryWrapper<SysDingGroup>().lambda().eq(SysDingGroup::getServiceId,serviceUnitId));
        if (CollectionUtils.isEmpty(sysDingGroupList)){
            throw ExceptionResultEnum.ERROR.exception("未完成考勤组设置的服务单元不能发布");
        }

        tbService.setStatus(ServiceStatusEnum.PUBLISH);
        this.updateById(tbService);
    }

    @Transactional
    @Override
    public void clozeServiceUnit(Long serviceUnitId) {
        TBService tbService = this.getById(serviceUnitId);
        if (Objects.isNull(tbService)) {
            throw ExceptionResultEnum.ERROR.exception("未找到服务单元");
        }
        ServiceStatusEnum status = tbService.getStatus();
        if (!ServiceStatusEnum.PUBLISH.equals(status)) {
            throw ExceptionResultEnum.ERROR.exception(String.format("只有[%s]状态的服务单元可以被关闭，当前状态[%s]", ServiceStatusEnum.PUBLISH.getTitle(), status.getTitle()));
        }
        tbService.setStatus(ServiceStatusEnum.FINISH);
        this.updateById(tbService);
    }

    @Deprecated
    @Transactional
    @Override
    public void restartServiceUnit(Long serviceUnitId) {
        TBService tbService = this.getById(serviceUnitId);
        if (Objects.isNull(tbService)) {
            throw ExceptionResultEnum.ERROR.exception("未找到服务单元");
        }
        ServiceStatusEnum status = tbService.getStatus();
        if (!ServiceStatusEnum.FINISH.equals(status)) {
            throw ExceptionResultEnum.ERROR.exception(String.format("只有[%s]状态的服务单元可以被重启，当前状态[%s]", ServiceStatusEnum.FINISH.getTitle(), status.getTitle()));
        }
        tbService.setStatus(ServiceStatusEnum.PUBLISH);
        this.updateById(tbService);
    }

    @Override
    public List<TBService> queryServiceUnit(ProductTypeEnum type, List<ServiceStatusEnum> statusList, String name, DataPermissionDto dpr) {
        if (name != null && name.length() > 0) {
            name = SystemConstant.translateSpecificSign(name);
        }
        return this.baseMapper.queryServiceUnit(type, statusList, name, dpr);
    }

    /**
     * 约分
     *
     * @param molecular   分子   eg.10
     * @param denominator 分母   eg.8
     * @return 约分后的结果 map -> k:分子 v:分母  eg. map->(5,4)
     */
    private ReductionResult reduction(Integer molecular, Integer denominator) {
        if (SystemConstant.isOneNull(molecular, denominator)) {
            throw ExceptionResultEnum.ERROR.exception("约分失败，分子或分母不能为空");
        }

        int min = (molecular < denominator) ? molecular : denominator;
        int max = (molecular > denominator) ? molecular : denominator;

        if (max % min != 0) {
            min = min / 2 + 1;
        }

        int maxMultiple = 1;
        for (int i = min; i > 1; i--) {
            if (molecular % i == 0 && denominator % i == 0) {
                maxMultiple = i;
                break;
            }
        }
        ReductionResult result = new ReductionResult();
        result.setMolecular(molecular / maxMultiple);
        result.setDenominator(denominator / maxMultiple);
        return result;
    }
}