package com.zd.bottle.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zd.bottle.domain.BottleStorage;
import com.zd.bottle.domain.BottleStorageError;
import com.zd.bottle.domain.UseRecord;
import com.zd.bottle.domain.UsegasApply;
import com.zd.bottle.dto.UseRecordDto;
import com.zd.bottle.mapper.UseRecordMapper;
import com.zd.bottle.service.BottleStorageErrorService;
import com.zd.bottle.service.BottleStorageService;
import com.zd.bottle.service.UseRecordService;
import com.zd.bottle.service.UsegasApplyService;
import com.zd.bottle.vo.AirAmount;
import com.zd.bottle.vo.UseRecordVo;
import com.zd.bottle.vo.WebUseRecordVo;
import com.zd.common.core.constant.HttpStatus;
import com.zd.common.core.constant.SecurityConstants;
import com.zd.common.core.domain.R;
import com.zd.common.core.exception.ServiceException;
import com.zd.common.core.utils.SecurityUtils;
import com.zd.common.core.utils.bean.TransferUtils;
import com.zd.common.security.service.TokenService;
import com.zd.system.api.RemoteUserService;
import com.zd.system.api.domain.SysUser;
import com.zd.system.api.model.LoginUser;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

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

/**
 * <p>
 * 使用记录表 服务实现类
 * </p>
 *
 * @author hanson
 * @since 2022-09-08
 */
@Service
public class UseRecordServiceImpl extends ServiceImpl<UseRecordMapper, UseRecord> implements UseRecordService {

    @Resource
    private BottleStorageService storageService;
    @Resource
    private RemoteUserService userService;
    @Resource
    private UsegasApplyService usegasApplyService;
    @Resource
    private BottleStorageErrorService errorService;
    @Resource
    private TokenService tokenService;
    @Resource
    private UseRecordMapper useRecordMapper;

    @Override
    public List<UseRecordVo> getListVo(List<UseRecord> records) {
        List<UseRecordVo> recordVos = TransferUtils.transferList(records, UseRecordVo.class);
        List<Long> storageIds = recordVos.stream().map(UseRecordVo::getStorageId).collect(Collectors.toList());
        List<BottleStorage> storages = storageService.listByIds(storageIds);
        Map<Long, BottleStorage> storageMap = storages.stream().collect(Collectors.toMap(BottleStorage::getId, b -> b));
        recordVos.forEach(u -> {
            Long storageId = u.getStorageId();
            if (storageMap.containsKey(storageId)) {
                BottleStorage bottleStorage = storageMap.get(storageId);
                u.setAirName(bottleStorage.getAirName())
                        .setElectronicTag(bottleStorage.getElectronicTag()).setAirNumber(bottleStorage.getAirNumber())
                        .setStorage(bottleStorage);
            }
        });
        return recordVos;
    }

    @Override
    public List<UseRecord> getList(UseRecord useRecord) {
        LambdaQueryWrapper<UseRecord> queryWrapper = Wrappers.lambdaQuery(UseRecord.class);
        String startTime = useRecord.getStartTime();
        String endTime = useRecord.getEndTime();

        queryWrapper.apply(StringUtils.hasLength(startTime)&&StringUtils.hasLength(endTime) , "DATE_FORMAT(use_time,'%Y-%m-%d') >=date_format({0},'%Y-%m-%d') and DATE_FORMAT(use_time,'%Y-%m-%d') <=date_format({1},'%Y-%m-%d')",startTime,endTime);
        String searchValue = useRecord.getSearchValue();
        if (StringUtils.hasLength(searchValue)) {
            queryWrapper.like(UseRecord::getContacts, searchValue)
                    .or()
                    .like(UseRecord::getPhone, searchValue);
        }

        List<Long> ids = useRecord.getIds();
        if (ids != null && !ids.isEmpty()) {
            queryWrapper.in(UseRecord::getId, ids);
        }
        queryWrapper.setEntity(useRecord);
        return list(queryWrapper);
    }

    @Override
    public List<UseRecordVo> getBottleInfoByStorageId(Long storageId) {
        return this.baseMapper.getBottleInfoByStorageId(storageId);
    }

    @Override
    public WebUseRecordVo getBottleInfo(Long id) {
        // 获取使用记录
        UseRecord useRecord = getById(id);
        Long storageId = useRecord.getStorageId();
        List<UseRecord> records = getByStorageId(storageId);
        return getWebUseRecordVo(records, storageId);
    }

    @Override
    public WebUseRecordVo getBottleRecord(Long storageId) {
        // 获取使用记录
        List<UseRecord> useRecords = getByStorageId(storageId);
        WebUseRecordVo recordVo = getWebUseRecordVo(useRecords, storageId);
        List<UseRecordVo> recordVos = Optional.ofNullable(recordVo.getRecordVos()).orElseGet(Collections::emptyList);

        Map<Long, Long> recordCount = recordVos.stream().collect(Collectors.groupingBy(UseRecordVo::getUserId, Collectors.counting()));

        recordVos = recordVos.stream().collect(Collectors.toCollection(() ->
                        new TreeSet<>(Comparator.comparing(UseRecordVo::getUserId))))
                .stream().map(r -> r.setCountNumber(Math.toIntExact(recordCount.get(r.getUserId()))))
                .sorted(Comparator.comparing(UseRecordVo::getUseTime).reversed())
                .collect(Collectors.toList());

        recordVo.setRecordVos(recordVos);
        return recordVo;
    }

    @Override
    public List<UseRecord> getByStorageId(Long storageId) {
        LambdaQueryWrapper<UseRecord> queryWrapper = Wrappers.lambdaQuery(UseRecord.class);
        queryWrapper.eq(UseRecord::getStorageId, storageId);
        return list(queryWrapper);
    }

    @Override
    public List<UseRecordVo> getListUseRecord(Long storageId) {
        return useRecordMapper.getListUseRecord(storageId);
    }

    @Override
    public List<AirAmount> calcApply(String airName) {
        return usegasApplyService.calcApply(airName);
    }

    /***
     * 查询气瓶是否归还
     * @param storageId storageId
     * @return List
     */
    @Override
    public List<UseRecord> getListNotReturn(Long storageId) {
        return useRecordMapper.getListNotReturn(storageId);
    }

    @Override
    public List<AirAmount> calcRepertory(String airName) {
        return baseMapper.calcRepertory(airName);
    }

    @Override
    public List<AirAmount> calcAmount(String airName) {
        return baseMapper.calcAmount(airName);
    }

    @Override
    public Integer add(UseRecordDto recordDto) {
        int result = 1;
        R<LoginUser> userInfo = userService.getUserInfo(SecurityUtils.getUsername(), SecurityConstants.INNER);
        if (userInfo.getCode() != HttpStatus.SUCCESS || userInfo.getData() == null) {
            throw new ServiceException("用户账号异常");
        }
        //查询用户使用资格
        LoginUser user = userInfo.getData();
        SysUser sysUser = user.getSysUser();
        Long storageId = recordDto.getStorageId();
        LambdaQueryWrapper<UsegasApply> queryWrapper = Wrappers.lambdaQuery(UsegasApply.class);
        queryWrapper.eq(UsegasApply::getUserId, sysUser.getUserId())
                .ge(UsegasApply::getEndTime, new Date())
                //todo 气体ID待确认
                .eq(UsegasApply::getUseGasName, recordDto.getBottleName())
                .eq(UsegasApply::getLeadAuditStaus, 1);
        List<UsegasApply> list = usegasApplyService.list(queryWrapper);
        if (list.isEmpty()) {
            throw new ServiceException("请先申请用气资格");
        }
        LambdaQueryWrapper<UseRecord> wrapper = Wrappers.lambdaQuery(UseRecord.class);
        wrapper.eq(UseRecord::getStorageId, storageId)
                .eq(UseRecord::getBackTime, null);
        if (getOne(wrapper) != null) {
            throw new ServiceException("气瓶正在使用中");
        }

        recordDto.setContacts(sysUser.getNickName())
                .setPhone(sysUser.getPhonenumber())
                .setUseTime(Calendar.getInstance().getTime());
        UseRecord useRecord = new UseRecord();
        BeanUtils.copyProperties(recordDto, useRecord);

        BottleStorage storage = storageService.getById(useRecord.getStorageId());
        if (storage == null) {
            throw new ServiceException("气瓶不存在");
        }

        storage.setStorageStatus(2);
        Integer isSurplus = recordDto.getIsSurplus();
        if (isSurplus == 1) {
            // 修改库存中气瓶余量标记
            storage.setIsSurplus(isSurplus).setCurrentPressure(useRecord.getBeforeUse());
            BottleStorageError bottleStorageError = new BottleStorageError();
            bottleStorageError.setStorageId(useRecord.getStorageId())
                    .setBeforeEdit(storage.getCurrentPressure())
                    .setAfterEdit(useRecord.getBeforeUse())
                    .setOpTime(Calendar.getInstance().getTime())
                    .setPhone(sysUser.getPhonenumber());
            bottleStorageError.setCommonValue(sysUser.getUserName(),sysUser.getUserId(),sysUser.getDeptId());
            errorService.save(bottleStorageError);
        }
        if (!storageService.updateById(storage)) {
            throw new ServiceException("入库数据异常");
        }
        //设置其他公共字段
        useRecord.setUserId(sysUser.getUserId());
        useRecord.setCommonValue(sysUser.getUserName(), sysUser.getUserId(), sysUser.getDeptId());
        if (save(useRecord)) {
            return result;
        }
        throw new ServiceException("使用登记记录错误");
    }

    @Override
    public Integer updateUseRecord(UseRecord useRecord) {
        R<LoginUser> userInfo = userService.getUserInfo(SecurityUtils.getUsername(), SecurityConstants.INNER);
        if (userInfo.getCode() != HttpStatus.SUCCESS || userInfo.getData() == null) {
            throw new ServiceException("未登录或登录失效");
        }
        Long storageId = useRecord.getStorageId();
        LambdaQueryWrapper<UseRecord> queryWrapper = Wrappers.lambdaQuery(UseRecord.class);
        queryWrapper.eq(UseRecord::getStorageId, storageId).isNull(UseRecord::getBackTime);
        UseRecord temp = getOne(queryWrapper);
        if (temp == null) {
            throw new ServiceException("数据异常");
        }
        BigDecimal afterUse = useRecord.getAfterUse();
        BigDecimal beforeUse = temp.getBeforeUse();
        if (afterUse.compareTo(beforeUse) > 0) {
            throw new ServiceException("使用后的气压不能大于使用前的气压");
        }
        if (ObjectUtil.isNotEmpty(beforeUse) && ObjectUtil.isNotEmpty(afterUse)) {
            useRecord.setAmount(beforeUse.subtract(afterUse));
            useRecord.setBackTime(Calendar.getInstance().getTime());
        }
        //修改库存中气瓶余量
        BottleStorage storage = storageService.getById(storageId);
        storage.setStorageStatus(1);
        storage.setCurrentPressure(afterUse);
        storage.setId(storage.getId());
        storageService.updateById(storage);

        useRecord.setId(temp.getId());
        SysUser sysUser = userInfo.getData().getSysUser();
        useRecord.setCommonValue(sysUser.getUserName(), sysUser.getUserId(), sysUser.getDeptId());
        return baseMapper.updateById(useRecord);
    }

    @Override
    public List<UseRecord> getByUserId(UseRecord useRecord) {
        Long userId = tokenService.getLoginUser().getSysUser().getUserId();
        LambdaQueryWrapper<UseRecord> queryWrapper = Wrappers.lambdaQuery(UseRecord.class);
        queryWrapper.eq(UseRecord::getUserId, userId);
        return list(queryWrapper);
    }

    private WebUseRecordVo getWebUseRecordVo(List<UseRecord> useRecords, Long storageId) {
        List<UseRecordVo> recordVos = TransferUtils.transferList(useRecords, UseRecordVo.class);
        BottleStorage storage = storageService.getById(storageId);
        // 获取入库信息
        //气瓶名称等相关内容
        WebUseRecordVo recordVo = new WebUseRecordVo();
        BeanUtils.copyProperties(storage, recordVo);
        return recordVo.setRecordVos(recordVos);
    }
}
