package com.casic.missiles.modular.system.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.casic.missiles.core.application.context.AbstractPermissionContext;
import com.casic.missiles.core.common.constant.Const;
import com.casic.missiles.core.datascope.DataScope;
import com.casic.missiles.model.exception.ServiceException;
import com.casic.missiles.model.exception.enums.CoreExceptionEnum;
import com.casic.missiles.model.response.ResponseData;
import com.casic.missiles.modular.system.constant.DeviceConst;
import com.casic.missiles.modular.system.dao.DeviceMapper;
import com.casic.missiles.modular.system.dto.*;
import com.casic.missiles.modular.system.enums.DeviceDataTableEnum;
import com.casic.missiles.modular.system.model.*;
import com.casic.missiles.modular.system.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.Validator;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 设备表 服务实现类
 * </p>
 *
 * @author lwh123
 * @since 2019-05-23
 */
@Service
@Slf4j
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements IDeviceService, IBusDeviceSupportService {

    @Autowired
    private IDeviceTypeService deviceTypeService;

    @Autowired
    private IDeviceModelsService deviceModelsService;

    @Autowired
    private IDeviceConcentratorService deviceConcentratorService;

    @Autowired
    private IDeviceWellService deviceWellService;

    @Autowired
    private AbstractPermissionContext permissionService;
    @Autowired
    private Validator validator;


    /**
     * 不分页
     *
     * @param dataScope
     * @param deviceType
     * @param deptid
     * @param beginTime
     * @param endTime
     * @param keywords
     * @param isOnline
     * @return
     */
    public List<DeviceDto> getDeviceList(DataScope dataScope, String deviceType, String deptid, String beginTime, String endTime, String keywords, String isOnline) {
        List<DeviceDto> deviceList = this.baseMapper.getDeviceList(dataScope, deviceType, Long.valueOf(StrUtil.isEmpty(deptid) ? "-1" : deptid), beginTime, endTime, keywords, isOnline);
        deviceList.forEach(
                deviceDto -> deviceDto.setOnlineState(deviceDto.getOnlineState() == "0" ? "0" : "1")
        );
        return deviceList;
    }

    /**
     * 判断设备是否关联集中器
     *
     * @param entity 设备类型
     * @return
     */
    private Boolean isAddConcentrator(Device entity) {
        DeviceModels deviceModels = deviceModelsService.getById(entity.getModelId());
        List<String> communis = Arrays.asList(deviceModels.getCommunication().split(","));
        return communis.contains(DeviceConst.YES);
    }

    @Override
    @Transactional
    public ResponseData addDevice(Device entity) {
        ResponseData responseData = new ResponseData();
        responseData.setCode(500);
        try {
            //根据井编号查询井信息
            DeviceWellDto wellDto = this.selectWellIdByCode(entity.getWellCode());
            if (wellDto == null) {
                responseData.setMessage("点位编号不存在");
                return responseData;
            }
            DeviceType deviceType = deviceTypeService.getById(entity.getDeviceType());
            if (deviceType == null) {
                responseData.setMessage("设备类型不存在");
                return responseData;
            }
            boolean isAddConcentrator = DeviceConst.YES.equals(deviceType.getIsNoConcent()) ? false : isAddConcentrator(entity);
            //根据集中器编号查询集中器信息
            DeviceConcentratorDto concentratorDto = null;
            if (isAddConcentrator) {
                concentratorDto = this.selectDeviceConcentorByCode(entity.getConcenCode());
                if (null == concentratorDto) {
                    responseData.setMessage("集中器编号不存在");
                    return responseData;
                }
            }
            //设置默认值
            entity.setOnlineState(DeviceConst.YES);
            entity.setValid(DeviceConst.YES);
            entity.setLogtime(new Date());
            super.save(entity);
            //关联设备集中器信息
            if (isAddConcentrator) {
                deviceConcentratorService.save(createConcentrator(entity.getId(), concentratorDto.getId()));
            }
            //关联设备井盖信息
            deviceWellService.save(createDeviceWell(entity.getId(), wellDto.getWellId()));
            responseData.setMessage("新增成功");
            responseData.setCode(200);
        } catch (DataAccessException dax) {
            log.error("主题：设备信息新增异常，设备编号:{}，异常信息:{}", entity.getDevcode(), dax);
            responseData.setMessage(dax.getMessage().contains("唯一性")&&dax.getMessage().contains("DEVCODE")?"设备编号重复":"新增异常");
        }
        return responseData;
    }

    @Transactional
    @Override
    public boolean updateById(Device entity) {
        DeviceConcentrator deviceConcentrator = deviceConcentratorService.getDeviceConcentratorBydevId(entity.getId());
        DeviceWell deviceWell = deviceWellService.getDeviceWellByDevId(entity.getId());

        //根据井编号查询井信息
        if (StrUtil.isNotEmpty(entity.getWellCode())) {
            DeviceWellDto wellDto = this.selectWellIdByCode(entity.getWellCode());
            if (null == wellDto) {
                ServiceException gunsException = new ServiceException(CoreExceptionEnum.REQUEST_NULL);
                gunsException.setErrorMessage("编号不存在");
                throw gunsException;
            }
            if (!deviceWell.getWellId().equals(wellDto.getWellId())) {
                deviceWellService.logicDelete(entity.getId());
                deviceWellService.save(createDeviceWell(entity.getId(), wellDto.getWellId()));
            }
        }

        DeviceType deviceType = deviceTypeService.getById(entity.getDeviceType());
        if (null == deviceType) {
            ServiceException gunsException = new ServiceException(CoreExceptionEnum.REQUEST_NULL);
            gunsException.setErrorMessage("设备类型不存在");
            throw gunsException;
        }
        //判断设备是否不需要关联集中器
        boolean isAddConcentrator = DeviceConst.YES.equals(deviceType.getIsNoConcent()) ? false : isAddConcentrator(entity);

        if (isAddConcentrator) {
            ServiceException gunsException = new ServiceException(CoreExceptionEnum.REQUEST_NULL);
            gunsException.setErrorMessage("集中器编号不存在");
            //校验设备是否需要绑定集中器
            if (StrUtil.isNotEmpty(entity.getConcenCode())) {
                //根据集中器编号查询集中器信息
                DeviceConcentratorDto concentratorDto = this.selectDeviceConcentorByCode(entity.getConcenCode());
                if (null == concentratorDto) {
                    throw gunsException;
                }
                //判断集中器是否修改
                if (deviceConcentrator == null || !deviceConcentrator.getConcenId().equals(concentratorDto.getId())) {
                    deviceConcentratorService.deleteByDeviceId(entity.getId());
                    deviceConcentratorService.save(createConcentrator(entity.getId(), concentratorDto.getId()));
                }
            } else {
                throw gunsException;
            }
        } else {
            deviceConcentratorService.deleteByDeviceId(entity.getId());
        }
        return super.updateById(entity);
    }

    @Override
    public List<DeviceDto> selectDataScopePage(DataScope dataScope, Page<DeviceDto> page, String deviceType, String deptid, String beginTime, String endTime, String keywords, String isOnline) {
        List<DeviceDto> deviceDtoList = this.baseMapper.selectDataScopePage(dataScope, page, Long.valueOf(StrUtil.isEmpty(deviceType) ? "-1" : deviceType), Long.valueOf(StrUtil.isEmpty(deptid) ? "-1" : deptid), beginTime, endTime, keywords, isOnline);
        deviceDtoList.forEach(
                deviceDto -> deviceDto.setOnlineState(ObjectUtils.isEmpty(deviceDto.getOnlineState()) || deviceDto.getOnlineState().equals("0") ? "0" : "1")
        );
        return deviceDtoList;
    }

    @Override
    public DeviceWellDto selectWellIdByCode(String wellCode) {
        return this.baseMapper.selectWellIdByCode(wellCode);
    }

    @Override
    public DeviceConcentratorDto selectDeviceConcentorByCode(String concenCode) {
        return this.baseMapper.selectDeviceConcentorByCode(concenCode);
    }

    @Override
    public Device getDeviceByDevCode(String devCode) {
        QueryWrapper device = new QueryWrapper();
        device.eq("DEVCODE", devCode);
        device.eq("VALID", "1");
        return this.baseMapper.selectOne(device);
    }

    @Transactional
    @Override
    public List<String> addDeviceBatch(List<Device> results) {

        BeanPropertyBindingResult beanPropertyBindingResult = new BeanPropertyBindingResult(Device.class, "设备类型导入校验");
        Map<String, Boolean> isAddConcentrator = new HashMap<>();
        List<String> list = new ArrayList<>();
        if (!CollectionUtil.isEmpty(results)) {
            final Integer[] index = {0};

            results.forEach(device -> {
                index[0]++;
                validator.validate(device, beanPropertyBindingResult);
                if (beanPropertyBindingResult.hasErrors()) {
                    List<FieldError> errors = beanPropertyBindingResult.getFieldErrors();
                    errors.forEach(error -> {
                                list.add("第" + index[0] + "行 ，".concat(error.getDefaultMessage()));
                                return;
                            }
                    );
                    return;
                }

                //设备类型校验
                DeviceType deviceType = deviceTypeService.selectDeviceTypeByName(device.getDeviceTypeName());
                if (null == deviceType || null == deviceType.getId()) {
                    list.add("第" + index[0] + "行，设备类型不存在！");
                    return;
                }


                //设备型号校验
                DeviceModels deviceModels = deviceModelsService.selectDeviceModelsBymodelName(device.getModelName());
                if (null == deviceModels) {
                    list.add("第" + index[0] + "行,设备型号不存在");
                    return;
                }
                if (!deviceModels.getDeviceType().equals(deviceType.getId())) {
                    list.add("第" + index[0] + "行,设备类型与设备型号不匹配");
                    return;
                }


                DeviceWellDto wellDto = this.selectWellIdByCode(device.getWellCode());
                if (null == wellDto) {
                    list.add("第" + index[0] + "行,编号不存在");
                    return;
                }

                //如果非NB则判断集中器 即设备类型包含1
                List<String> communis = Arrays.asList(deviceModels.getCommunication().split(","));
                //优先判断设备类型配置
                boolean isAdd = DeviceConst.YES.equals(deviceType.getIsNoConcent()) ? false : communis.contains(DeviceConst.YES);
                if (isAdd) {
                    DeviceConcentratorDto concentratorDto = this.selectDeviceConcentorByCode(device.getConcenCode());
                    isAddConcentrator.put(device.getDevcode(), true);
                    if (null == concentratorDto) {
                        list.add("第" + index[0] + "行,集中器编号不存在");
                        return;
                    }
                    device.setConcenId(concentratorDto.getId());
                } else {
                    isAddConcentrator.put(device.getDevcode(), false);
                }
                if (StrUtil.isNotEmpty(device.getInstallDateFmt())) {
                    try {
                        device.setInstallDate(new SimpleDateFormat("yyyy-MM-dd").parse(device.getInstallDateFmt()));
                    } catch (Exception e) {
                        list.add(" 第" + index[0] + "行，时间格式不正确");
                        return;
                    }
                } else {
                    device.setInstallDate(new Date());
                }

                //设置设备相关信息
                device.setDeviceType(deviceType.getId());
                device.setModelId(deviceModels.getId());
                device.setWellId(wellDto.getWellId());
                //设置有效位
                device.setValid(Const.ONE);

            });

            if (CollectionUtil.isNotEmpty(list)) {
                return list;
            }
            //保存设备信息
            this.saveBatch(results);
            List<DeviceConcentrator> deviceConcentrators = new ArrayList<>();
            List<DeviceWell> deviceWells = new ArrayList<>();

            results.forEach(device -> {
                deviceWells.add(createDeviceWell(device.getId(), device.getWellId()));

                //判断是否关联集中器
                if (isAddConcentrator.get(device.getDevcode())) {
                    deviceConcentrators.add(createConcentrator(device.getId(), device.getConcenId()));
                }
            });

            //设备闸井关联表 设备集中器关联表
            if (CollectionUtil.isNotEmpty(deviceConcentrators)) {
                this.deviceConcentratorService.saveBatch(deviceConcentrators);
            }
            if (CollectionUtil.isNotEmpty(deviceWells)) {
                this.deviceWellService.saveBatch(deviceWells);
            }

        } else {
            list.add("导入数据不能为空");
        }
        return list;
    }


    @Override
    public void batchDeletes(List<Long> ids) {
        Long currentTime = new Date().getTime();
        if (CollectionUtil.isNotEmpty(ids)) {
            ids.forEach(id -> {
                this.logicDelete(id);
                //删除井设备关联关系
                deviceWellService.logicDelete(id);
                //删除设备集中器关联
                deviceConcentratorService.deleteByDeviceId(id);
            });
        }
    }

    /**
     * 设备删除有效值设置为当前时间戳
     *
     * @param id
     */
    private void logicDelete(Long id) {
        this.baseMapper.logicDelete(id, new Date().getTime());
    }

    @Override
    public ResponseData offlineListPage(DataScope dataScope, Page<Map<String, Object>> page,
                                        String deviceCode, String deviceType) {
        ResponseData responseData = new ResponseData();
        Long deptId = permissionService.getAuthService().getLoginUser().getDeptId();
        String deviceTypes = getDeviceType(deptId);
        try {
            if (StrUtil.isEmpty(deviceTypes)) {
                responseData.setCode(200);
                responseData.setMessage("没有数据权限");
            } else {
                List<Map<String, Object>> offlineList = this.baseMapper.offlineListPage(dataScope, page, deviceCode, StrUtil.isEmptyOrUndefined(deviceType) ? -1 : Integer.valueOf(deviceType));
                Map<String, Map<String, Object>> deviceTimeList = getMapDataByType(deviceTypes);
                offlineList.forEach(
                        offlineData -> {
                            if (deviceTimeList.containsKey(offlineData.get("devcode"))) {
                                offlineData.putAll(deviceTimeList.get(offlineData.get("devcode")));
                            }

                        }
                );
//                List<Map<String, Object>> sortOfflineList = offlineList.stream().sorted(
//                        (e1, e2) -> Integer.valueOf(String.valueOf(e1.get("offlineDays"))) - (Integer.valueOf(String.valueOf(e2.get("offlineDays"))))
//                ).collect(Collectors.toList());
                page.setRecords(offlineList);
                responseData.setCode(200);
                responseData.setMessage("查询成功");
            }
        } catch (Exception ex) {
            log.error("主题：离线查询异常，设备型号" + deviceCode + "，" +
                    "设备编号:" + deviceType + ",异常信息{}" + ex);
            responseData.setCode(500);
            responseData.setMessage("查询异常");
        }
        return responseData;
    }

    @Override
    public List<DeviceCodeSelectDto> selectDevicesByConfig(DataScope dataScope, String deviceType, String configStatus) {
        return this.baseMapper.selectDevicesByConfig(dataScope, deviceType, configStatus);
    }


    /**
     * 关联集中器
     *
     * @param deviceId
     * @param concenId
     * @return
     */
    private DeviceConcentrator createConcentrator(Long deviceId, Long concenId) {
        return new DeviceConcentrator(deviceId, concenId, 0, 1, new Date());
    }

    /**
     * 关联闸井
     *
     * @param deviceId
     * @param wellId
     * @return
     */
    private DeviceWell createDeviceWell(Long deviceId, Long wellId) {
        return new DeviceWell(deviceId, wellId, new Date(), "1");
    }

    @Override
    public List<DeviceInfoDto> getDeviceList(DataScope dataScope) {
        return this.baseMapper.getDeviceListInfo(dataScope);
    }

    @Override
    public DeviceInfoDto selectDeviceById(Long id) {
        return this.baseMapper.selectDeviceById(id);
    }

    @Override
    public List<DeviceInWellInfo> getDeviceInWellInfo(Long id) {
        return this.baseMapper.getDeviceInWellInfo(id);
    }

    private String getDeviceType(Long deptId) {
        List<Map<String, String>> deptTypeList = this.baseMapper.getDeviceType();
        List<Map<String, String>> deptList = this.baseMapper.getDeptList();
        Map<String, String> deptTypeMap = deptTypeList.stream().collect(
                Collectors.toMap(e -> String.valueOf(e.get("deptid")), e -> String.valueOf(e.get("deviceType")))
        );
        Map<Long, Long> deptMap = deptList.stream().collect(
                Collectors.toMap(e -> Long.valueOf(String.valueOf(e.get("id"))),
                        e -> Long.valueOf(String.valueOf(e.get("pid"))))
        );
        String deviceTypes = deptTypeMap.get(String.valueOf(deptId));
        while (deptId != -1 && deviceTypes == null) {
            deptId = deptMap.get(deptId);
            deviceTypes = deptTypeMap.get(String.valueOf(deptId));
        }
        return deviceTypes;
    }

    private Map<String, Map<String, Object>> getMapDataByType(String deviceTypes) {
        List<Map<String, Object>> countRecordList = new ArrayList<>();
        JSON.parseObject(deviceTypes, List.class).stream().forEach(
                deviceType -> {
                    Integer typeId = Integer.valueOf(deviceType.toString());
                    DeviceDataTableEnum deviceDataTableEnum = DeviceDataTableEnum.DEVICE_TYPE_TABLE.getTableNameMap().get(typeId);
                    if (deviceDataTableEnum == null) {return;}
                    String tableName = deviceDataTableEnum.getTableName();
                    List<Map<String, Object>> timeList = this.baseMapper.getOfflineTimeList(tableName);
                    countRecordList.addAll(timeList);
                }
        );
        Map<String, Map<String, Object>> countRecordMap = countRecordList.stream().collect(
                Collectors.toMap(e -> String.valueOf(e.get("devcode")), e -> e)
        );
        return countRecordMap;
    }
}
