package cn.com.ty.lift.business.maintenance.service;

import cn.com.ty.lift.business.common.CommonRequest;
import cn.com.ty.lift.business.evaluation.dao.entity.Evaluation;
import cn.com.ty.lift.business.evaluation.service.EvaluationService;
import cn.com.ty.lift.business.framework.util.MessageUtils;
import cn.com.ty.lift.business.library.dao.entity.Lift;
import cn.com.ty.lift.business.library.service.LiftService;
import cn.com.ty.lift.business.maintenance.dao.entity.MaintenancePlan;
import cn.com.ty.lift.business.maintenance.dao.entity.MaintenanceRecord;
import cn.com.ty.lift.business.maintenance.dao.entity.MtRecordCost;
import cn.com.ty.lift.business.maintenance.dao.entity.MtRecordImg;
import cn.com.ty.lift.business.maintenance.dao.entity.model.request.MaintenanceRecordRequest;
import cn.com.ty.lift.business.maintenance.dao.entity.model.request.MtRecordRequest;
import cn.com.ty.lift.business.maintenance.dao.entity.model.response.MaintenanceRecordDetailResponse;
import cn.com.ty.lift.business.maintenance.dao.entity.model.response.MaintenanceRecordResponse;
import cn.com.ty.lift.business.maintenance.dao.entity.model.response.MtRecordResponse;
import cn.com.ty.lift.business.maintenance.dao.mapper.MaintenanceRecordMapper;
import cn.com.ty.lift.common.constants.CommonEnum;
import cn.com.ty.lift.common.utils.MapHelper;
import cn.com.xwy.boot.web.dto.RestResponse;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author bieao
 * @date 2019/12/12
 * @description 保养记录业务层
 */
@Service
@Slf4j
@AllArgsConstructor
public class MaintenanceRecordService extends ServiceImpl<MaintenanceRecordMapper, MaintenanceRecord> {


    private LiftService            liftService;
    private MtRecordCostService    mtRecordCostService;
    private MtRecordImgService     mtRecordImgService;
    private MaintenancePlanService maintenancePlanService;
    private EvaluationService      evaluationService;

    private Gson gson;

    /**
     * @param request 公司id和电梯id
     * @return RestResponse 保养信息
     * @description 根据公司id和电梯id查询上次保养信息
     * @date 2020/1/6 5:37 下午
     */
    public MaintenanceRecordResponse recordInfo(MaintenanceRecordRequest request) {
        MaintenanceRecordResponse project = baseMapper.findProjectByCompanyId(request);
        MaintenanceRecordResponse record = baseMapper.findRecordByCompanyId(request);
        if (ObjectUtil.isNotEmpty(record)) {
            project.setType(record.getType());
            project.setWorkDate(record.getWorkDate());
            return project;
        }
        return project;
    }

    /**
     * @param id 电梯id
     * @return 电梯经纬度
     * @description 根据电梯id获取经纬度
     * @date 2020/1/13 11:37 上午
     */
    public String getCoordinate(Long id){
        Lift lift = liftService.getById(id);
        return Optional.ofNullable(lift).map(Lift::getCoordinate).orElse(null);
    }


    /**
     * @param coordinate 维保工经纬度
     * @return 是否在范围内
     * @description 计算维保工开始保养时，是否在电梯200米范围内
     * @date 2020/1/13 11:30 上午
     */
    public boolean calc(String liftCoordinate, String coordinate) {
        double expected = 200;
        double result = MapHelper.GetPointDistance(liftCoordinate, coordinate);
        return (result * 1000) > expected;
    }

    /**
     * @param planId 计划id
     * @param mtCompanyId 公司id
     * @return 是否存在
     * @description 根据计划id和公司id查询是否有保养记录
     * @date 2020/1/20 2:41 下午
     */
    public boolean count(Long planId, Long mtCompanyId, Long workerId) {
        LambdaQueryWrapper<MaintenanceRecord> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.eq(MaintenanceRecord::getMtPlanId, planId);
        lambdaQueryWrapper.eq(MaintenanceRecord::getMtCompanyId, mtCompanyId);
        lambdaQueryWrapper.eq(MaintenanceRecord::getWorkerId, workerId);
        return count(lambdaQueryWrapper) > 0;
    }

    /**
     * @param request 保养单信息
     * @return 是否成功
     * @description 新增保养记录
     * @date 2020/1/13 1:47 下午
     */
    @Transactional(rollbackFor = Exception.class)
    public RestResponse saveRecord(MaintenanceRecordRequest request) {
        MaintenanceRecord record = request.getRecord();
        Long planId = record.getMtPlanId();
        Long mtCompanyId = record.getMtCompanyId();
        Long workerId = record.getWorkerId();
        String liftCoordinate = getCoordinate(record.getLiftId());
        if (StrUtil.isEmpty(liftCoordinate)) return RestResponse.fail(MessageUtils.get("msg.lift.not.position"));
        boolean count = count(planId, mtCompanyId, workerId);
        if (count) return RestResponse.fail(MessageUtils.get("msg.exist.record"));
        boolean result = calc(liftCoordinate, request.getCoordinate());
        if (result) return RestResponse.fail(MessageUtils.get("msg.error.person.scope"));
        Long liftId = record.getLiftId();
        Optional<Lift> lift = liftService.getOne(null, liftId);
        if (lift.isPresent()) {
            Lift l = lift.get();
            record.setCode(l.getLiftCode());
            record.setLiftType(l.getLiftType());
            record.setStatus(CommonEnum.MaintenanceRecordStatus.MAINTENANCE_DOING.getCode());
            record.setWorkerId1(record.getWorkerId1());
            record.setWorkDate(LocalDate.now());
            MaintenancePlan plan = maintenancePlanService.getOne(record.getMtPlanId());
            if (ObjectUtil.isEmpty(plan)) return RestResponse.fail(MessageUtils.get("msg.add.fail"));
            record.setPlanDate(plan.getPlanDate());
            boolean ret = save(record);
            if (!ret) {
                return RestResponse.fail(MessageUtils.get("msg.add.fail"));
            }
            plan.setStatus(Integer.parseInt(CommonEnum.MaintenancePlanStatus.MAINTENANCE_DOING.getCode()));
            boolean planResult = maintenancePlanService.updateById(plan);
            if (!planResult){
                rollback();
                return RestResponse.fail(MessageUtils.get("msg.add.fail"));
            }
        } else {
            return RestResponse.fail(MessageUtils.get("msg.add.fail"));
        }
        return RestResponse.success(record.getId(), MessageUtils.get("msg.add.success"));
    }

    /**
     * @param request 保养信息
     * @return 是否成功
     * @description 编辑保养信息
     * @date 2020/1/13 2:31 下午
     */
    @Transactional(rollbackFor = Exception.class)
    public RestResponse modify(MaintenanceRecordRequest request) {
        MaintenanceRecord record = request.getRecord();
        MaintenanceRecord oldRecord = detail(record.getId());
        if (Objects.isNull(oldRecord))
            return RestResponse.success(null, MessageUtils.get("msg.record.not.exist"));

        record.setStatus(CommonEnum.MaintenanceRecordStatus.COMPLETE.getCode());
        boolean result = updateById(record);
        if (!result){
            return RestResponse.fail(MessageUtils.get("msg.modify.fail"));
        }
        log.info("维保记录：" + gson.toJson(oldRecord));
        log.info("维保计划id：" + oldRecord.getMtPlanId());
        MaintenancePlan plan = maintenancePlanService.getOne(oldRecord.getMtPlanId());
        if (ObjectUtil.isEmpty(plan)) return RestResponse.fail(MessageUtils.get("msg.modify.fail"));
        plan.setStatus(Integer.parseInt(CommonEnum.MaintenancePlanStatus.COMPLETE.getCode()));
        plan.setWorkDate(LocalDate.now());
        //修改保养计划为完成
        boolean planResult = maintenancePlanService.updateById(plan);
        if (!planResult){
            rollback();
            return RestResponse.fail(MessageUtils.get("msg.modify.fail"));
        }
        List<MtRecordImg> imageList = new ArrayList<>();
        //更新保养图片
        request.getRecordImageList().forEach(entry -> {
            MtRecordImg image = new MtRecordImg();
            image.setImgUrl(entry);
            image.setMtRecordId(record.getId());
            imageList.add(image);
        });
        boolean ret = mtRecordImgService.saveBatch(imageList, imageList.size());
        if (!ret){
            rollback();
            return RestResponse.fail(MessageUtils.get("msg.modify.fail"));
        }
        return RestResponse.success(null, MessageUtils.get("msg.modify.success"));
    }

    /**
     * @param id 保养记录id
     * @return 保养信息详情
     * @description 查看保养信息详情
     * @date 2020/1/13 2:39 下午
     */
    public MaintenanceRecord detail(Long id) {
        return getById(id);
    }

    /**
     * @param id 保养记录id
     * @return 保养信息详情
     * @description 查看保养信息详情
     * @date 2020/1/13 2:39 下午
     */
    public MaintenanceRecordDetailResponse queryById(Long id) {
        MaintenanceRecord record = getById(id);
        List<MtRecordImg> imgList = mtRecordImgService.listByRecord(id);
        MaintenanceRecordDetailResponse response = new MaintenanceRecordDetailResponse();
        response.setRecord(record);
        response.setRecordImageList(imgList);
        return response;
    }

    /**
     * 根据条件分页查询维保-日常保养
     * @author wcz
     * @param request MtRecordRequest
     * @return IPage<MtRecordResponse>
     */
    public IPage<MtRecordResponse> pageRecordByCondition(MtRecordRequest request){
        return baseMapper.pageRecordByCondition(request.getPage(),request);
    }

    /**
     * 根据维保公司统计维保-日常保养
     * @author wcz
     * @param request MtRecordRequest
     * @return long
     */
    public long countRecordByCondition(MtRecordRequest request){
        return baseMapper.countRecordByCondition(request);
    }

    /**
     * 日常保养-保养单：根据id查询,带关联信息
     * @author wcz
     * @param request MtRecordRequest
     * @return boolean
     */
    public MtRecordResponse infoById(MtRecordRequest request){
        return baseMapper.infoById(request);
    }

    private void rollback(){
        //强制手动事务回滚
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }

    /**
     * 点击填写保养单，带收费项，新增record
     * @author wcz
     * @param entity MaintenanceRecord
     * @return boolean
     */
    @Transactional(rollbackFor = Exception.class)
    public RestResponse tofill(MaintenanceRecord entity){
        //总计 partsCost, manCost, 拼接sparepart
        List<MtRecordCost> mtRecordCosts = entity.getMtRecordCosts();
        if(IterUtil.isNotEmpty(mtRecordCosts)){
            BigDecimal partsCost = mtRecordCosts.stream().map(MtRecordCost::getPartsCost).reduce(BigDecimal.ZERO, (m1, m2) -> m1.add(m2));
            BigDecimal manCost = mtRecordCosts.stream().map(MtRecordCost::getManCost).reduce(BigDecimal.ZERO, (m1, m2) -> m1.add(m2));
            String sparepart = mtRecordCosts.stream().map(MtRecordCost::getSparepart).collect(Collectors.joining(";"));
            entity.setPartsCost(partsCost);
            entity.setManCost(manCost);
            entity.setSparepart(sparepart);
        }
        boolean mr = saveOrUpdate(entity);
        if(!mr){
            return RestResponse.fail("修改保养单失败，请稍后重试");
        }
        //如果没有收费项
        if(IterUtil.isEmpty(mtRecordCosts)){
            return RestResponse.success(entity.getId());
        }
        mtRecordCosts.forEach(cost ->{
            cost.setMtRecordId(entity.getId());
        });
        boolean rc = mtRecordCostService.saveOrUpdateBatch(mtRecordCosts, mtRecordCosts.size());
        if(!rc){
            //强制手动事务回滚
            rollback();
            return RestResponse.fail("修改保养收费项失败，请稍后重试");
        }
        MaintenancePlan plan = maintenancePlanService.getById(entity.getMtPlanId());
        if(Objects.isNull(plan)){
            return RestResponse.success(entity.getId());
        }
        plan.setWorkDate(LocalDate.now());
        boolean mp = maintenancePlanService.updateById(plan);
        if(mp){
            return RestResponse.success(entity.getId());
        }else{
            //强制手动事务回滚
            rollback();
            return RestResponse.fail("修改保养计划执行时间失败，请稍后重试");
        }
    }

    /**
     * 填写保养单-确认，带维保项和现场图片 ，修改record
     * @author wcz
     * @param entity MaintenanceRecord
     * @param imgs List<String>
     * @return boolean
     */
    @Transactional(rollbackFor = Exception.class)
    public RestResponse fill(MaintenanceRecord entity,List<String> imgs){
        boolean mr = saveOrUpdate(entity);
        if(!mr){
            return RestResponse.fail("修改保养单失败，请稍后重试");
        }
        if(IterUtil.isEmpty(imgs)){
            return RestResponse.success(true);
        }
        List<MtRecordImg> mtRecordImgs = new ArrayList<>();
        for (int i = 0; i < imgs.size(); i++) {
            MtRecordImg mri = new MtRecordImg();
            mri.setMtRecordId(entity.getId());
            mri.setImgUrl(imgs.get(i));
            mri.setSort(i);
            mtRecordImgs.add(mri);
        }
        boolean mi = mtRecordImgService.saveBatch(mtRecordImgs,mtRecordImgs.size());
        if(mi){
            return RestResponse.success(true);
        }else{
            //强制手动事务回滚
            rollback();
            return RestResponse.fail("修改保养单收费项失败，请稍后重试");
        }
    }

    /**
     * 通过：app端提交的保养单点通过后生成正式保养单  status:-1 -> 2
     * 清除超期: 超期的计划修改status ->1,workDate -> now
     * @author wcz
     * @param entity MaintenanceRecord
     * @return boolean
     */
    @Transactional(rollbackFor = Exception.class)
    public RestResponse pass(MaintenanceRecord entity){
        boolean mr = updateById(entity);
        if(!mr){
            return RestResponse.fail("修改保养单失败，请稍后重试");
        }
        //清除超期
        MaintenancePlan plan = maintenancePlanService.getById(entity.getMtPlanId());
        if(Objects.isNull(plan)){
            return RestResponse.success(true);
        }
        plan.setStatus(1);
        plan.setWorkDate(LocalDate.now());
        boolean mp = maintenancePlanService.updateById(plan);
        if(mp){
            return RestResponse.success(true);
        }else{
            //强制手动事务回滚
            rollback();
            return RestResponse.fail("修改维保计划失败，请稍后重试");
        }
    }

    /**
     * 维保记录评价，同时更新维保记录状态 status -> 3
     * @author wcz
     * @param record MaintenanceRecord
     * @param entity Evaluation
     * @return boolean
     */
    @Transactional(rollbackFor = Exception.class)
    public RestResponse evaluate(MaintenanceRecord record, Evaluation entity){
        boolean ev = evaluationService.save(entity);
        if(!ev){
            return RestResponse.fail("添加评价失败，请稍后重试");
        }
        boolean mr = updateById(record);
        if(mr){
            return RestResponse.success(true);
        }else{
            //强制手动事务回滚
            rollback();
            return RestResponse.fail("更新维保记录失败，请稍后重试");
        }
    }

    /**
     * 删除维保收费项，汇总金额，拼接sparepart
     * @author wcz
     * @param record MaintenanceRecord
     * @param mtRecordCost MtRecordCost
     * @return boolean
     */
    @Transactional(rollbackFor = Exception.class)
    public RestResponse deleteCost(MaintenanceRecord record, MtRecordCost mtRecordCost) {
        BigDecimal partsCost = mtRecordCost.getPartsCost();
        BigDecimal manCost = mtRecordCost.getManCost();
        String sparepart = mtRecordCost.getSparepart();
        if (partsCost.compareTo(BigDecimal.ZERO) > 0) {
            record.setPartsCost(record.getPartsCost().subtract(partsCost));
        }
        if (manCost.compareTo(BigDecimal.ZERO) > 0) {
            record.setManCost(record.getManCost().subtract(manCost));
        }
        if (StrUtil.isNotEmpty(sparepart)) {
            record.setSparepart(record.getSparepart().replace(sparepart + ";", ""));
        }
        boolean cost = mtRecordCostService.removeById(mtRecordCost.getId());
        if (!cost) {
            return RestResponse.fail("删除收费项失败，请稍后重试");
        }
        boolean re = updateById(record);
        if (re) {
            return RestResponse.success(true);
        } else {
            rollback();
            return RestResponse.fail("更新维保记录失败，请稍后重试");
        }
    }

    public IPage<MtRecordResponse> pageByLift(MtRecordRequest request){
        return baseMapper.pageByLift(request.getPage(), request);
    }

    /**
     * @param request 公司id，用户id
     * @return 条数
     * @description 根据公司id和用户id查询保养中的任务数量
     * @date 2020/4/25 9:31 上午
     */
    public long countDoingByUser(CommonRequest request) {
        return baseMapper.countDoingByUser(request);
    }
}
