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

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlRunner;
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.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.model.*;
import com.casic.missiles.modular.system.service.*;
import org.springframework.beans.factory.annotation.Autowired;
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 javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * <p>
 * 设备表 服务实现类
 * </p>
 *
 * @author lwh123
 * @since 2019-05-23
 */
@Service
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;

    @Resource
    private AbstractPermissionContext permissionService;

    @Autowired
    private Validator validator;

    /**
     * 判断设备是否关联集中器
     *
     * @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
    public boolean save(Device entity) {
        //根据井编号查询井信息
        DeviceWellDto wellDto = this.selectWellIdByCode(entity.getWellCode());
        if (wellDto == null) {
            ServiceException gunsException = new ServiceException(CoreExceptionEnum.REQUEST_NULL);
            gunsException.setErrorMessage("编号不存在");
            throw gunsException;
        }
        DeviceType deviceType = deviceTypeService.getById(entity.getDeviceType());
        if (deviceType == null) {
            ServiceException gunsException = new ServiceException(CoreExceptionEnum.REQUEST_NULL);
            gunsException.setErrorMessage("设备类型不存在");
            throw gunsException;
        }

        boolean isAddConcentrator = DeviceConst.YES.equals(deviceType.getIsNoConcent()) ? false : isAddConcentrator(entity);
        //根据集中器编号查询集中器信息
        DeviceConcentratorDto concentratorDto = null;
        if (isAddConcentrator) {
            concentratorDto = this.selectDeviceConcentorByCode(entity.getConcenCode());
            if (null == concentratorDto) {
                ServiceException gunsException = new ServiceException(CoreExceptionEnum.REQUEST_NULL);
                gunsException.setErrorMessage("集中器编号不存在");
                throw gunsException;
            }
        }
        //设置默认值
        entity.setOnlineState(DeviceConst.YES);
        entity.setValid(DeviceConst.YES);
        entity.setLogtime(new Date());
        boolean flag = super.save(entity);

        //关联设备集中器信息
        if (isAddConcentrator) {
            deviceConcentratorService.save(createConcentrator(entity.getId(), concentratorDto.getId()));
        }
        //关联设备井盖信息
        deviceWellService.save(createDeviceWell(entity.getId(), wellDto.getWellId()));
        return flag;
    }

    @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.deleteByDeviceId(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) {
        return this.baseMapper.selectDataScopePage(dataScope, page, deviceType, deptid, beginTime, endTime, keywords, isOnline);
    }

    @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 List<DeviceMonitorDataDto> selectWellDataScopePage(DataScope dataScope, Page<DeviceMonitorDataDto> page, String deptid, String beginTime, String endTime, String keywords) {

        return this.baseMapper.selectWellDataScopePage(dataScope, page, deptid, beginTime, endTime, keywords);
    }

    @Override
    public List<DeviceMonitorDataDto> selectLiquidDataScopePage(DataScope dataScope, Page<DeviceMonitorDataDto> page, String deptid, String beginTime, String endTime, String keywords) {
        return this.baseMapper.selectLiquidDataScopePage(dataScope, page, deptid, beginTime, endTime, keywords);
    }

    @Override
    public List<Map<String, Object>> selectGasDataScopePage(DataScope dataScope, Page<Map<String, Object>> page, String deptid, String beginTime, String endTime, String keywords) {
        List<Map<String, Object>> mapList = this.baseMapper.selectGasDataScopePage(dataScope, page, deptid, beginTime, endTime, keywords);
        for (Map<String, Object> map : mapList) {
            map.put("deptName", permissionService.getDeptService().getDeptName(Long.valueOf(map.get("deptid").toString())));
        }
        return mapList;
    }

    @Override
    public List<Map<String, Object>> selectTubeDataScopePage(DataScope dataScope, Page<Map<String, Object>> page, String deptid, String beginTime, String endTime, String keywords) {
        List<Map<String, Object>> mapList = this.baseMapper.selectTubeDataScopePage(dataScope, page, deptid, beginTime, endTime, keywords);
        for (Map<String, Object> map : mapList) {
            map.put("deptName", permissionService.getDeptService().getDeptName(Long.valueOf(map.get("deptid").toString())));
        }
        return mapList;
    }

    @Override
    public List<Map<String, Object>> selectHarmfulDataScopePage(DataScope dataScope, Page<Map<String, Object>> page, String deptid, String beginTime, String endTime, String keywords) {
        List<Map<String, Object>> mapList = this.baseMapper.selectHarmfulDataScopePage(dataScope, page, deptid, beginTime, endTime, keywords);
        for (Map<String, Object> map : mapList) {
            map.put("deptName", permissionService.getDeptService().getDeptName(Long.valueOf(map.get("deptid").toString())));
        }
        return mapList;
    }

    @Override
    public List<Map<String, Object>> selectTempDataScopePage(DataScope dataScope, Page<Map<String, Object>> page, String deptid, String beginTime, String endTime, String keywords) {
        List<Map<String, Object>> mapList = this.baseMapper.selectTempDataScopePage(dataScope, page, deptid, beginTime, endTime, keywords);
        for (Map<String, Object> map : mapList) {
            map.put("deptName", permissionService.getDeptService().getDeptName(Long.valueOf(map.get("deptid").toString())));
        }
        return mapList;
    }


    @Override
    public List<Map<String, Object>> selectTempPressDataScopePage(DataScope dataScope, Page<Map<String, Object>> page, String deptid, String beginTime, String endTime, String keywords) {
        List<Map<String, Object>> mapList = this.baseMapper.selectTempPressDataScopePage(dataScope, page, deptid, beginTime, endTime, keywords);
        for (Map<String, Object> map : mapList) {
            map.put("deptName", permissionService.getDeptService().getDeptName(Long.valueOf(map.get("deptid").toString())));
        }
        return mapList;
    }

    @Override
    public List<Map<String, Object>> selectDigDataScopePage(DataScope dataScope, Page<Map<String, Object>> page, String deptid, String beginTime, String endTime, String keywords) {
        List<Map<String, Object>> mapList = this.baseMapper.selectDigDataScopePage(dataScope, page, deptid, beginTime, endTime, keywords);
        for (Map<String, Object> map : mapList) {
            map.put("deptName", permissionService.getDeptService().getDeptName(Long.valueOf(map.get("deptid").toString())));
        }
        return mapList;
    }

    @Override
    public List<Map<String, Object>> selectWellLocDataScopePage(DataScope dataScope, Page<Map<String, Object>> page, String deptid, String beginTime, String endTime, String keywords) {
        List<Map<String, Object>> mapList = this.baseMapper.selectWellLocDataScopePage(dataScope, page, deptid, beginTime, endTime, keywords);
        for (Map<String, Object> map : mapList) {
            map.put("deptName", permissionService.getDeptService().getDeptName(Long.valueOf(map.get("deptid").toString())));
        }
        return mapList;
    }

    @Override
    public List<Map<String, Object>> selectNoiseDataScopePage(DataScope dataScope, Page<Map<String, Object>> page, String deptid, String beginTime, String endTime, String keywords) {
        List<Map<String, Object>> mapList = this.baseMapper.selectNoiseDataScopePage(dataScope, page, deptid, beginTime, endTime, keywords);
        for (Map<String, Object> map : mapList) {
            map.put("deptName", permissionService.getDeptService().getDeptName(Long.valueOf(map.get("deptid").toString())));
        }
        return mapList;
    }

    @Override
    public List<AlarmDeptStaticsDto> alarmsStaticsByDept(Long deviceType, String beginTime, String endTime, DataScope dataScope, Long deptId) {
        List<Long> deptIds = permissionService.getDeptService().getIdsByPid(deptId, DeviceConst.DEPT_TYPE_ORG);
        return this.baseMapper.alarmsStaticsByDept(deviceType, beginTime, endTime, dataScope, deptId, CollectionUtil.isEmpty(deptIds));
    }

    @Override
    public void deleteByIds(List<Long> ids) {
        if (CollectionUtil.isNotEmpty(ids)) {
            ids.forEach(id -> {
                this.baseMapper.deleteById(id);
                //删除井设备关联关系
                deviceWellService.deleteByDeviceId(id);
                //删除设备集中器关联
                deviceConcentratorService.deleteByDeviceId(id);
            });


        }
    }

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

    @Override
    public void registerGeTui(Long id, String clientid) {
        SqlRunner.db().delete("DELETE FROM SYS_USER_CLIENT WHERE USERID =  {0}", id);
        SqlRunner.db().insert("INSERT INTO SYS_USER_CLIENT (ID, USERID, CLIENTID,LOGTIME) VALUES ({0}, {1},{2},SYSDATE())", IdWorker.getId(), id, clientid);
    }

    /**
     * 关联集中器
     *
     * @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<Map<String, Object>> selectGasLiquidDataScopePage(DataScope dataScope, Page<Map<String, Object>> page, String sensorType, String deptid, String beginTime, String endTime, String keywords) {
        List<Long> deptIds = null;
        if (StrUtil.isNotEmpty(deptid)) {
            deptIds = permissionService.getDeptService().getIdsByPid(deptid, null);
            deptIds.add(Long.valueOf(deptid));
        }
        List<Map<String, Object>> mapList = new ArrayList<>();
        if ("liquid".equals(sensorType)) {
            mapList = this.baseMapper.selectGasLiquidDataLiquidScopePage(dataScope, page, deptIds, beginTime, endTime, keywords);
        }
        if ("gas".equals(sensorType)) {
            mapList = this.baseMapper.selectGasLiquidDataGasScopePage(dataScope, page, deptIds, beginTime, endTime, keywords);
        }
        for (Map<String, Object> map : mapList) {
            map.put("deptName", permissionService.getDeptService().getDeptName(Long.valueOf(map.get("deptid").toString())));
            setCompany(map);
            if ("liquid".equals(sensorType)) {
                float liquiddata = Float.valueOf(String.valueOf(map.get("data")));
                if (liquiddata <= 0) {
                    map.put("data", "正常水位");
                }
            }
        }
        return mapList;
    }

    private void setCompany(Map<String, Object> dataMap) {
        if (ObjectUtil.isNotEmpty(dataMap.get("deptid"))) {
            List<Long> parentDepts = permissionService.getDeptService().getParentListById(dataMap.get("deptid").toString());
            if (CollectionUtil.isNotEmpty(parentDepts)) {
                Long companyId = parentDepts.get(parentDepts.size() - 1);
                dataMap.put("companyId", companyId);
                dataMap.put("companyName", permissionService.getDeptService().getDeptName(companyId));
            }
        }
    }

    @Override
    public List<Map<String, Object>> selectDataList(DataScope dataScope, String wellCode, String watchType, String beginTime, String endTime) {
        if (StrUtil.isAllEmpty(beginTime, endTime)) {
            Calendar calendar = Calendar.getInstance();
            endTime = DateUtil.format(calendar.getTime(), "yyyy-MM-dd HH:mm:ss");
            calendar.add(Calendar.DATE, -7);
            beginTime = DateUtil.format(calendar.getTime(), "yyyy-MM-dd HH:mm:ss");
        }
        List<Map<String, Object>> list = new ArrayList<>();
        switch (watchType) {
            case "liquid":
                list = this.baseMapper.selectLiquidDataList(dataScope, wellCode, beginTime, endTime);
                break;
            case "gas":
                list = this.baseMapper.selectGasDataList(dataScope, wellCode, beginTime, endTime);
                break;
            case "temp":
                list = this.baseMapper.selectTempDataList(dataScope, wellCode, beginTime, endTime);
                break;
            case "harmful":
                list = this.baseMapper.selectHarmfulDataList(dataScope, wellCode, beginTime, endTime);
                break;
            default:
                break;
        }
        for (Map<String, Object> map : list) {
            map.put("deptName", permissionService.getDeptService().getDeptName(Long.valueOf(map.get("deptid").toString())));
            setCompany(map);
        }
        return list;
    }

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

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

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