package com.xy.service;

import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xy.collections.list.JArrayList;
import com.xy.collections.list.JList;
import com.xy.collections.map.JHashMap;
import com.xy.collections.map.JMap;
import com.xy.device.EnumDeviceFactoryStatus;
import com.xy.device.EnumDeviceQualityStatus;
import com.xy.device.EnumDeviceQualityThreshold;
import com.xy.dto.DeviceQualityDto;
import com.xy.dto.DeviceQualityValueDto;
import com.xy.dto.be.MercDto;
import com.xy.entity.*;
import com.xy.error.CommRuntimeException;
import com.xy.mapper.DeviceInfoMapper;
import com.xy.mapper.DeviceQualityMapper;
import com.xy.service.be.MercService;
import com.xy.utils.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static com.xy.utils.PlusBeans.*;

/**
 * <p>
 * 设备-质检 服务实现类
 * </p>
 *
 * @author lijin
 * @since 2023-01-05
 */
@Service
@AllArgsConstructor
@Api(tags = "设备-质检")
public class DeviceQualityServiceImpl extends ServiceImpl<DeviceQualityMapper, DeviceQuality> implements DeviceQualityService {

    private DeviceInfoMapper deviceInfoMapper;

    private DeviceQualityValueServiceImpl deviceQualityValueService;

    private DeviceSysinfoServiceImpl deviceSysinfoService;

    private DeviceStatusServiceImpl deviceStatusService;

    private DeviceCreateIdsServiceImpl deviceCreateIdsService;

    private MercService mercService;

    private void queryDeviceQualityValue(List<DeviceQualityDto.Vo> list) {
        if (Emptys.check(list)) {
            JList<DeviceQualityDto.Vo> deviceQualitys = new JArrayList<>(list);
            //查询质检值
            JList<Integer> qualityIds = deviceQualitys.getProperty(DeviceQualityDto.Vo::getQualityId);
            List<DeviceQualityValue> deviceQualityValues = deviceQualityValueService.list(new LambdaQueryWrapper<DeviceQualityValue>().in(DeviceQualityValue::getQualityId, qualityIds));
            JMap<Integer, DeviceQualityValue> deviceQualityValueMap = new JArrayList<>(deviceQualityValues).toMap(DeviceQualityValue::getQualityId).cover();
            //查询机器ID号
            List<DeviceCreateIds> deviceCreateIds = deviceCreateIdsService.list(new LambdaQueryWrapper<DeviceCreateIds>()
                    .in(DeviceCreateIds::getDeviceId, deviceQualitys.getProperty(DeviceQualityDto.Vo::getDeviceId))
                    .isNotNull(DeviceCreateIds::getDeviceQrMercId)
                    .ge(DeviceCreateIds::getDeviceQrMercId, 0)
            );
            JMap<Long, DeviceCreateIds> deviceCreateIdsJMaps;
            JMap<Long, MercDto.Vo> mercsJMaps;
            if (Emptys.check(deviceCreateIds)) {
                JList<DeviceCreateIds> deviceCreateIdss = new JArrayList<>(deviceCreateIds);
                deviceCreateIdsJMaps = deviceCreateIdss.toMap(DeviceCreateIds::getDeviceId).cover();
                JList<Long> mercIds = deviceCreateIdss.getProperty(DeviceCreateIds::getDeviceQrMercId);
                List<MercDto.Vo> mercs = mercService.list(new MercDto.SelectList().setMercIds(mercIds)).getData();
                mercsJMaps = new JArrayList<>(mercs).toMap(MercDto.Vo::getId).cover();
            } else {
                deviceCreateIdsJMaps = new JHashMap<>();
                mercsJMaps = new JHashMap<>();
            }
            list.forEach(vo -> {
                //质检值信息
                DeviceQualityValue deviceQualityValue = deviceQualityValueMap.get(vo.getQualityId());
                if (deviceQualityValue == null) {
                    return;
                }
                vo.setDeviceQualityValue(copy(DeviceQualityValueDto.Vo.class, deviceQualityValue));
                //机器ID号商户信息
                DeviceCreateIds deviceCreateIdsInfo = deviceCreateIdsJMaps.get(vo.getDeviceId());
                if (Emptys.check(deviceCreateIdsInfo)) {
                    MercDto.Vo merc = mercsJMaps.get(deviceCreateIdsInfo.getDeviceQrMercId());
                    if (Emptys.check(merc)) {
                        vo.setDeviceQrMercId(merc.getId()).setDeviceQrMercName(merc.getName());
                    }
                }
            });
        }
    }

    @PostMapping("page")
    @ApiOperation("分页查询")
    public R<PageBean<DeviceQualityDto.Vo>> page(@RequestBody DeviceQualityDto.Page page) {
        PageBean pageBean = page.getPage();
        LambdaQueryWrapper<DeviceQuality> lambdaQueryWrapper = new MybatisPlusQuery().eqWrapper(page, DeviceQuality.class)
                .ge(DeviceQuality::getUpdateTime, page.getBeginUpdateTime())
                .le(DeviceQuality::getUpdateTime, page.getEndUpdateTime())
                .build()
                .orderByDesc(!Emptys.check(pageBean.getOrders()), DeviceQuality::getCreateTime);
        IPage<DeviceQuality> iPage = page(toIPage(pageBean), lambdaQueryWrapper);
        PageBean<DeviceQualityDto.Vo> voPageBean = toPageBean(DeviceQualityDto.Vo.class, iPage);
        List<DeviceQualityDto.Vo> list = voPageBean.getRecords();
        queryDeviceQualityValue(list);
        return R.ok(voPageBean);
    }

    @PostMapping("list")
    @ApiOperation("集合查询")
    public R<List<DeviceQualityDto.Vo>> list(@RequestBody DeviceQualityDto.SelectList selectList) {
        LambdaQueryWrapper<DeviceQuality> lambdaQueryWrapper = new MybatisPlusQuery().eqWrapper(selectList, DeviceQuality.class)
                .in(DeviceQuality::getQualityId, selectList.getQualityIds())
                .in(DeviceQuality::getDeviceId, selectList.getDeviceIds())
                .build();
        List<DeviceQuality> deviceQualities = list(lambdaQueryWrapper);
        List<DeviceQualityDto.Vo> list = copy(DeviceQualityDto.Vo.class, deviceQualities);
        queryDeviceQualityValue(list);
        return R.ok(list);
    }

    @PostMapping("obj")
    @ApiOperation("对象查询")
    public R<DeviceQualityDto.Vo> obj(@RequestBody DeviceQualityDto.Obj obj) {
        LambdaQueryWrapper<DeviceQuality> lambdaQueryWrapper = new MybatisPlusQuery().eqWrapper(obj, DeviceQuality.class)
                .build()
                .orderByDesc(DeviceQuality::getQualityId);
        List<DeviceQuality> deviceQualities = list(lambdaQueryWrapper);
        List<DeviceQualityDto.Vo> list = copy(DeviceQualityDto.Vo.class, deviceQualities);
        if (!Emptys.check(list)) {
            if (Emptys.check(obj.getDeviceId())) {
                save(Arrays.asList(new DeviceQualityDto.Save().setDeviceId(obj.getDeviceId())));
                return obj(obj);
            }
            return R.ok();
        }
        DeviceQualityDto.Vo vo = copy(DeviceQualityDto.Vo.class, list.get(0));
        queryDeviceQualityValue(Arrays.asList(vo));
        return R.ok(vo);
    }

    @PostMapping("update")
    @ApiOperation("修改")
    public R update(@RequestBody List<DeviceQualityDto.Vo> vos) {
        List<DeviceQuality> deviceQualities = copy(DeviceQuality.class, vos);
        LocalDateTime now = LocalDateTime.now();
        List<DeviceSysinfo> deviceSysinfos = deviceSysinfoService.list(new LambdaQueryWrapper<DeviceSysinfo>().in(DeviceSysinfo::getDeviceId, new JArrayList<>(vos).getProperty(DeviceQualityDto.Vo::getDeviceId)));
        JMap<Long, DeviceSysinfo> deviceSysinfosJMaps = new JArrayList<>(deviceSysinfos).toMap(DeviceSysinfo::getDeviceId).cover();
        int qualified = SysDictUtils.getValue(EnumDeviceQualityStatus.Code.CODE.getCode(), EnumDeviceQualityStatus.QUALIFIED.getCode(), Integer.class);
        List<DeviceStatus> deviceStatuses = new ArrayList<>();
        for (DeviceQuality deviceQuality : deviceQualities) {
            if (deviceQuality.getQualityState() != null) {
                //合格
                if (qualified == deviceQuality.getQualityState()) {
                    //检查磁盘空间和内存容量
                    DeviceSysinfo deviceSysinfo = deviceSysinfosJMaps.get(deviceQuality.getDeviceId());
                    Integer diskSpace = deviceSysinfo.getDiskSpace();
                    int diskSpaceSize = SysDictUtils.getValue(EnumDeviceQualityThreshold.Code.CODE.getCode(), EnumDeviceQualityThreshold.DISK_SPACE_SIZE.getCode(), Integer.class);
                    if (diskSpace == null || diskSpace < diskSpaceSize) {
                        return R.fail(deviceSysinfo.getDeviceId() + "磁盘空间不足" + diskSpaceSize + "G");
                    }
                    Integer memerySpace = deviceSysinfo.getMemerySpace();
                    int memerySpaceSize = SysDictUtils.getValue(EnumDeviceQualityThreshold.Code.CODE.getCode(), EnumDeviceQualityThreshold.MEMERY_SPACE_SIZE.getCode(), Integer.class);
                    if (memerySpace == null || memerySpace < memerySpaceSize) {
                        return R.fail(deviceSysinfo.getDeviceId() + "内存容量不足" + memerySpaceSize + "M");
                    }
                    //标记机器不可交易
                    DeviceStatus deviceStatus = new DeviceStatus()
                            .setDeviceId(deviceQuality.getDeviceId())
                            .setIsPay(false);
                    deviceStatuses.add(deviceStatus);
                }
                deviceQuality.setQualityAuditUserId(AuthorizeUtils.getLoginId(Long.class));
            }
            if (deviceQuality.getFactoryState() != null) {
                deviceQuality.setFactoryAuditUserId(AuthorizeUtils.getLoginId(Long.class));
            }
            deviceQuality.setUpdateTime(now);
        }
        updateBatchById(deviceQualities);
        if (Emptys.check(deviceStatuses)) {
            deviceStatusService.updateBatchById(deviceStatuses);
        }
        return R.ok();
    }

    @PostMapping("rest")
    @ApiOperation(value = "重置多项质检", hidden = true)
    public R rest(@RequestBody DeviceQualityDto.Rest rest) {
        SysDictRedis sysDictRedis1 = SysDictUtils.get(EnumDeviceQualityStatus.Code.CODE.getCode(), EnumDeviceQualityStatus.QUALIFIED.getCode());
        SysDictRedis sysDictRedis2 = SysDictUtils.get(EnumDeviceFactoryStatus.Code.CODE.getCode(), EnumDeviceFactoryStatus.CAN_SHIPPED.getCode());
        DeviceQuality deviceQuality = getById(rest.getQualityId());
        if (sysDictRedis1.getValue().equals(deviceQuality.getQualityState()) || sysDictRedis2.getValue().equals(deviceQuality.getFactoryState())) {
            return R.fail("设备已合格或已出厂");
        }
        List<String> types = rest.getTypes();
        LocalDateTime now = LocalDateTime.now();
        types.forEach(type -> {
            QualityEnum qualityEnum = QualityEnum.getQualityEnum(type);
            if (qualityEnum == null) {
                return;
            }
            //修改质检
            UpdateWrapper<DeviceQuality> updateWrapper = new UpdateWrapper<DeviceQuality>()
                    .set(qualityEnum.getBeginTime(), now)
                    .set(qualityEnum.getEndTime(), null)
                    .set(StringTools.humpToLine(LambdaUtils.getProperty(DeviceQuality::getUpdateTime)), now)
                    .eq(StringTools.humpToLine(LambdaUtils.getProperty(DeviceQuality::getQualityId)), rest.getQualityId());
            update(updateWrapper);
            //删除质检属性
            DeviceQualityValueDto.Vo del = new DeviceQualityValueDto.Vo()
                    .setQualityId(rest.getQualityId())
                    .setQualityType(type);
            deviceQualityValueService.del(del);
        });
        return R.ok();
    }

    @PostMapping("save")
    @ApiOperation("添加新质检")
    public R<List<Tuple.Tuple3<Long, Long, Boolean>>> save(@RequestBody List<DeviceQualityDto.Save> deviceQualitySaves) {
        List<DeviceQualityDto.Vo> updates = new ArrayList<>();
        List<DeviceQuality> saves = new ArrayList<>();
        JList<Long> deviceIds = new JArrayList<>(deviceQualitySaves).getProperty(DeviceQualityDto.Save::getDeviceId);
        //获取设备信息
        List<DeviceInfo> deviceInfos = deviceInfoMapper.selectList(new LambdaQueryWrapper<DeviceInfo>().in(DeviceInfo::getDeviceId, deviceIds));
        JMap<Long, DeviceInfo> deviceInfoJMap = new JArrayList<>(deviceInfos).toMap(DeviceInfo::getDeviceId).cover();
        //获取已有质检信息
        List<DeviceQuality> deviceQualities = list(new LambdaQueryWrapper<DeviceQuality>()
                .in(DeviceQuality::getDeviceId, deviceIds)
                .eq(DeviceQuality::getShowStatus, true)
        );
        JMap<Long, List<DeviceQuality>> deviceQualitieJMap = new JArrayList<>(deviceQualities).toMap(DeviceQuality::getDeviceId).group();
        LocalDateTime now = LocalDateTime.now();
        //封装修改和添加对象
        deviceQualitySaves.forEach(save -> {
            DeviceInfo deviceInfo = deviceInfoJMap.get(save.getDeviceId());
            if (deviceInfo == null) {
                throw new CommRuntimeException(save.getDeviceId() + "设备不存在");
            }
            DeviceQuality deviceQuality = new DeviceQuality()
                    .setDeviceId(save.getDeviceId())
                    .setDeviceType(deviceInfo.getDeviceType())
                    .setCreateTime(now);
            List<DeviceQuality> list = deviceQualitieJMap.get(deviceQuality.getDeviceId());
            if (Emptys.check(list)) {
                JList<Integer> qualityIds = new JArrayList<>(list).getProperty(DeviceQuality::getQualityId);
                List<DeviceQualityDto.Vo> vos2 = new ArrayList<>(qualityIds.size());
                qualityIds.forEach(qualityId -> vos2.add(new DeviceQualityDto.Vo().setQualityId(qualityId).setShowStatus(false)));
                updates.addAll(vos2);
            }
            saves.add(deviceQuality);
        });
        //修改
        if (Emptys.check(updates)) {
            update(updates);
        }
        //添加
        saveBatch(saves);
        return R.ok();
    }

    @ApiOperation(value = "质检结果通知", hidden = true)
    @PostMapping("qualityResultBack")
    public R qualityResultBack(@RequestBody DeviceQualityDto.QualityResultBack qualityResultBack) {
        Long deviceId = qualityResultBack.getDeviceId();
        String type = qualityResultBack.getType();
        JSONObject data = qualityResultBack.getData();
        LambdaQueryWrapper<DeviceQuality> lambdaQueryWrapper = new LambdaQueryWrapper<DeviceQuality>()
                .eq(DeviceQuality::getDeviceId, deviceId)
                .eq(DeviceQuality::getShowStatus, true).orderByDesc(DeviceQuality::getQualityId).last("limit 1");
        DeviceQuality deviceQuality = getOne(lambdaQueryWrapper);
        if (deviceQuality == null) {
            return R.fail("设备不存在");
        }
        //修改质检
        QualityEnum qualityEnum = QualityEnum.getQualityEnum(type);
        if (qualityEnum != null) {
            UpdateWrapper<DeviceQuality> updateWrapper = new UpdateWrapper<DeviceQuality>()
                    .set(qualityEnum.getEndTime(), LocalDateTime.now())
                    .eq(StringTools.humpToLine(LambdaUtils.getProperty(DeviceQuality::getDeviceId)), deviceId)
                    .eq(StringTools.humpToLine(LambdaUtils.getProperty(DeviceQuality::getShowStatus)), true);
            update(updateWrapper);
        }
        //修改质检值
        DeviceQualityValueDto.Vo saveOrUpdate = new DeviceQualityValueDto.Vo()
                .setQualityType(type)
                .setQualityValue(data.toString());
        saveOrUpdate.setQualityId(deviceQuality.getQualityId());
        deviceQualityValueService.saveOrUpdate(saveOrUpdate);
        return R.ok();
    }

    /**
     * 工厂枚举
     */
    @Getter
    @AllArgsConstructor
    public enum QualityEnum {

        /**
         * 软件硬系统检查
         */
        CHECK_SYSTEM("check_system", "system_state", "system_state_begin_time", "system_state_end_time"),

        /**
         * 交易测试检查
         */
        CHECK_TRADE("check_trade", "trade_state", "trade_state_begin_time", "trade_state_end_time"),

        /**
         * 门锁检查
         */
        CHECK_LOCKER("check_locker", "locker_state", "locker_state_begin_time", "locker_state_end_time"),

        /**
         * 温度检查
         */
        CHECK_TEMPERATURE("check_temperature", "temperature_state", "temperature_state_begin_time", "temperature_state_end_time"),

        /**
         * 模拟批量测试
         */
        CHECK_IMITATE_TEST("check_imitate_test", "imitate_test_state", "imitate_test_state_begin_time", "imitate_test_state_end_time"),

        /**
         * 参数设置检查
         */
        CHECK_SETTING("check_setting", "setting_state", "setting_state_begin_time", "setting_state_end_time"),

        ;

        /**
         * 质检类型
         */
        private String type;

        /**
         * 质检状态列名
         */
        private String state;

        /**
         * 质检状态开始时间列名
         */
        private String beginTime;

        /**
         * 质检状态结束时间列名
         */
        private String endTime;

        public static QualityEnum getQualityEnum(String type) {
            QualityEnum[] values = QualityEnum.values();
            for (QualityEnum qualityEnum : values) {
                if (qualityEnum.type.equals(type)) {
                    return qualityEnum;
                }
            }
            return null;
        }
    }
}
