package com.zcxk.rmcp.web.service.impl;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.zcxk.core.common.enums.StatusEnum;
import com.zcxk.core.common.exception.BusinessException;
import com.zcxk.core.common.pojo.ResultMessage;
import com.zcxk.core.common.pojo.UserCondition;
import com.zcxk.core.common.util.BeanCopyUtils;
import com.zcxk.core.common.util.SnowflakeIdWorker;
import com.zcxk.core.mysql.pageing.Pagination;
import com.zcxk.core.oauth2.pojo.LoginUser;
import com.zcxk.core.oauth2.util.UserUtil;
import com.zcxk.core.utils.BigDecimalUtils;
import com.zcxk.core.utils.CollectionsUtils;
import com.zcxk.core.utils.ZoniotIntegerUtils;
import com.zcxk.core.utils.export.EasyExcelUtil;
import com.zcxk.rmcp.api.dto.BasePageDto;
import com.zcxk.rmcp.api.dto.device.DeviceInputDto;
import com.zcxk.rmcp.api.dto.device.DeviceQueryDto;
import com.zcxk.rmcp.api.enums.DeviceStatusEnum;
import com.zcxk.rmcp.api.enums.RmcpErrorEnum;
import com.zcxk.rmcp.api.enums.ValveStatusEnum;
import com.zcxk.rmcp.api.vo.*;
import com.zcxk.rmcp.core.dao.DeviceAlarmMapper;
import com.zcxk.rmcp.core.dao.DeviceMapper;
import com.zcxk.rmcp.core.dao.InstallListMapper;
import com.zcxk.rmcp.core.entity.Community;
import com.zcxk.rmcp.core.entity.Device;
import com.zcxk.rmcp.core.entity.Org;
import com.zcxk.rmcp.core.entity.Product;
import com.zcxk.rmcp.web.excel.download.adapter.DeviceExcelFillAdapter;
import com.zcxk.rmcp.web.excel.download.service.DeviceDownloadExcelServiceImpl;
import com.zcxk.rmcp.web.excel.model.DeviceImportData;
import com.zcxk.rmcp.web.excel.model.DownloadExcelData;
import com.zcxk.rmcp.web.excel.model.ExcelData;
import com.zcxk.rmcp.web.service.CommunityService;
import com.zcxk.rmcp.web.service.DeviceService;
import com.zcxk.rmcp.web.service.OrgService;
import com.zcxk.rmcp.web.service.ProductService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 
 * @author linqingwei
 * @date 2021-07-19 9:44
 */
@Slf4j
@Service
public class DeviceServiceImpl implements DeviceService{

    @Resource
    private DeviceMapper deviceMapper;
    @Autowired
    private SnowflakeIdWorker idWorker;
    @Autowired
    private DeviceDownloadExcelServiceImpl deviceDownloadExcelService;
    @Autowired
    private CommunityService communityService;
    @Autowired
    private ProductService productService;
    @Autowired
    private OrgService orgService;
    @Resource
    private InstallListMapper installListMapper;
    @Resource
    private DeviceAlarmMapper deviceAlarmMapper;

    @Override
    public int insertSelective(Device record) {
        record.setCreateBy(UserUtil.getUsername());
        record.setCreateDate(LocalDateTime.now());
        record.setUpdateBy(UserUtil.getUsername());
        record.setUpdateDate(LocalDateTime.now());
        return deviceMapper.insertSelective(record);
    }

    @Override
    public int updateByPrimaryKeySelective(Device record) {
        record.setUpdateBy(UserUtil.getUsername());
        record.setUpdateDate(LocalDateTime.now());
        return deviceMapper.updateByPrimaryKeySelective(record);
    }

    @Override
    public Device findById(Long id) {
        return deviceMapper.findById(id);
    }

    @Override
    public Pagination<DeviceVo> getPage(DeviceQueryDto dto, BasePageDto page) {

        PageHelper.startPage(page.getPageNum(),page.getPageSize());
        List<DeviceVo> list = deviceMapper.findList(dto,UserUtil.getCurrentUser().getUserCondition());
        return new Pagination<>(list);
    }

    @Override
    public void getDeviceListExcel(DeviceQueryDto dto, HttpServletResponse response) {
        try {
            List<DeviceVo> list = deviceMapper.findList(dto,UserUtil.getCurrentUser().getUserCondition());

            EasyExcelUtil.excelWrite(response,DownloadDeviceVo.class,"设备列表",convert(list));
        }catch (Exception e){
            throw BusinessException.builder(RmcpErrorEnum.RMCP_DOWNLOAD_ERROR);
        }

    }

    private List<DownloadDeviceVo> convert (List<DeviceVo> list){
        List<DownloadDeviceVo> results = new ArrayList<>();
        for (DeviceVo deviceVo : list) {
            DownloadDeviceVo vo = new DownloadDeviceVo();
            BeanCopyUtils.copyProperties(deviceVo, vo, DownloadDeviceVo.class);
            vo.setDeviceTypeName(deviceVo.getManufacturerName()+"/"+deviceVo.getProductName()+"/"+deviceVo.getProductModel());
            vo.setValveStatusName(ValveStatusEnum.getMessage(deviceVo.getValveStatus()));
            vo.setDeviceStatusName(DeviceStatusEnum.getMessage(deviceVo.getDeviceStatus().toString()));
            results.add(vo);
        }
        return results;
    }


    @Override
    public void add(DeviceInputDto dto) {
        log.info("begin DeviceServiceImpl add dto = {}", JSON.toJSON(dto));
        LoginUser user = UserUtil.getCurrentUser();

        if (deviceMapper.findByDeviceNoUnique(null, dto.getDeviceNo()) > 0) {
            throw BusinessException.builder(RmcpErrorEnum.RMCP_DEVICE_NO_UNIQUE_ERROR);
        }
        if (deviceMapper.findByMeterNoUnique(null, dto.getMeterNo()) > 0) {
            throw BusinessException.builder(RmcpErrorEnum.RMCP_METER_NO_UNIQUE_ERROR);
        }

        Product product = productService.findById(dto.getProductId());

        //保存数据
        Device device = new Device();
        BeanCopyUtils.copyProperties(dto, device, Device.class);
        device.setId(idWorker.nextId());
        device.setTenantId(user.getTenantId());
        device.setCategoryId(product.getProductCategoryId());
        device.setDeviceStatus(DeviceStatusEnum.UNUSED.getCode());
        device.setValveStatus(ValveStatusEnum.ON.getCode());
        device.setStatus(StatusEnum.OK.getCode());
        this.insertSelective(device);

        log.info("end DeviceServiceImpl add ");
    }

    @Override
    public void edit(DeviceInputDto dto) {
        log.info("begin DeviceServiceImpl edit device = {}", JSON.toJSON(dto));

        if (deviceMapper.findByDeviceNoUnique(dto.getId(), dto.getDeviceNo()) > 0) {
            throw BusinessException.builder(RmcpErrorEnum.RMCP_DEVICE_NO_UNIQUE_ERROR);
        }
        if (deviceMapper.findByMeterNoUnique(dto.getId(), dto.getMeterNo()) > 0) {
            throw BusinessException.builder(RmcpErrorEnum.RMCP_METER_NO_UNIQUE_ERROR);
        }

        Product product = productService.findById(dto.getProductId());
        //更新数据
        Device device = new Device();
        BeanCopyUtils.copyProperties(dto, device, Device.class);
        device.setCategoryId(product.getProductCategoryId());
        this.updateByPrimaryKeySelective(device);
        log.info("end DeviceServiceImpl edit ");
    }

    @Override
    public DeviceDetailVo deviceDetail(Long deviceId) {
        DeviceDetailVo device = deviceMapper.findDetail(deviceId);
        return device;
    }

    @Override
    @Transactional
    public void batchDelele(List<Long> ids) {
        log.info("begin DeviceServiceImpl batchDel ids = {}", JSON.toJSON(ids));
        deviceMapper.delByIds(ids);
        // 删除计划清单
        installListMapper.deleteByDeviceId(ids);
        // 删除告警记录
        deviceAlarmMapper.deleteByDeviceId(ids);
        log.info("end DeviceServiceImpl batchDel ");
    }

    @Override
    @Transactional
    public void allDelele(DeviceQueryDto dto) {
        log.info("begin DeviceServiceImpl allDel dto = {}", JSON.toJSON(dto));
        List<DeviceVo> list = deviceMapper.findList(dto,UserUtil.getCurrentUser().getUserCondition());
        List<Long> ids = new ArrayList<>();
        if (list != null && list.size() > 0) {
            for (DeviceVo vo : list) {
                ids.add(vo.getId());
            }
            this.batchDelele(ids);
        }
        log.info("end DeviceServiceImpl allDel ");
    }


    @Override
    public DeviceStatisticsVo statisticsDevice() {
        List<DeviceStatusVo> list = deviceMapper.totalDeviceStatus(UserUtil.getCurrentUser().getUserCondition());
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        // 总数
        int allTotal = 0;
        // 单个设备总数
        int deviceTotal = 0;
        DeviceStatisticsVo  statisticsVo = new DeviceStatisticsVo();
        Map<String, StatusStatisticsVo> statusMap = new HashMap<>();
        List<DeviceStatisticsVo.DeviceRatio> ratioList = new ArrayList<>();
        for (DeviceStatusVo deviceStatusVo : list) {
            for (StatusStatisticsVo statistic : deviceStatusVo.getStatistics()) {
                // 统计同一个状态的条数
                totalStatus(statusMap, statistic);
                deviceTotal += statistic.getTotal();
            }
            DeviceStatisticsVo.DeviceRatio ratio = new DeviceStatisticsVo.DeviceRatio();
            ratio.setName(deviceStatusVo.getName());
            ratio.setTotal(deviceTotal);
            ratioList.add(ratio);
            allTotal += deviceTotal;
        }
        // 占比运算
        ratioDevice(ratioList, allTotal);
        // 状态统计数
        statisticsVo.setStatusList(statusMap.values().stream().collect(Collectors.toList()));
        // 设备占比数
        statisticsVo.setRatios(ratioList);
        // 总数
        statisticsVo.setTotal(ZoniotIntegerUtils.decimalFormat(allTotal));
        return statisticsVo;
    }


    @Override
    public DeviceMapDataVo listDeviceAndCommunityInfo(Integer categoryId){
        UserCondition condition = UserUtil.getCurrentUser().getUserCondition();
        List<DeviceCategoryCommunityVo> communityVos = deviceMapper.listCommunityDevice(categoryId, condition);
        DeviceMapDataVo result = new DeviceMapDataVo();
        // 分类
        Map<Long, ProductCategoryCommunityVo> productCategoryCommunityVoMap = new HashMap<>();
        // 小区
        Map<Long, CommunityProductCategoryVo> communityProductCategoryVoHashMap = new HashMap<>();
        for (DeviceCategoryCommunityVo communityVo : communityVos) {
            if (communityVo.getCategoryId() != null) {
                mergeCategoryCommunity(productCategoryCommunityVoMap, communityVo);
            }
            mergeCommunityCategory(communityProductCategoryVoHashMap, communityVo);
        }
        result.setCategoryCommunityVos(CollectionsUtils.mapToList(productCategoryCommunityVoMap));
        result.setCommunityCategoryVos(CollectionsUtils.mapToList(communityProductCategoryVoHashMap));
        result.setNoCellVoList(deviceMapper.listNoCellDevice(categoryId, condition));
        return result;
    }


    /**
    * @author Andy 
    * @description 合并相同的小区数据
    * @date 14:05 2021/7/30
    * @param communityProductCategoryVoHashMap, communityVo]
    * @return void 
    **/
    private void mergeCommunityCategory(Map<Long, CommunityProductCategoryVo> communityProductCategoryVoHashMap, DeviceCategoryCommunityVo communityVo){
        CommunityProductCategoryVo communityProductCategoryVo = communityProductCategoryVoHashMap.get(communityVo.getCommunityId());
        if (communityProductCategoryVo == null) {
            communityProductCategoryVo = new CommunityProductCategoryVo();
            BeanCopyUtils.copyProperties(communityVo, communityProductCategoryVo, CommunityProductCategoryVo.class);
        }

        // 查找分类
        List<ProductCategoryStatusVo> deviceCommunityVos = communityProductCategoryVo.getCategoryStatusVos();
        if (CollectionUtils.isEmpty(deviceCommunityVos)) {
            deviceCommunityVos = new ArrayList<>();
        }
        ProductCategoryStatusVo deviceCommunityVo = findProductCategory(communityVo.getCategoryId(), deviceCommunityVos);
        boolean isEmpty = false;
        if (deviceCommunityVo == null) {
            deviceCommunityVo = new ProductCategoryStatusVo();
            BeanCopyUtils.copyProperties(communityVo, deviceCommunityVo, ProductCategoryStatusVo.class);
            isEmpty = true;
        }
        List<StatusStatisticsVo> statusStatisticsVos = deviceCommunityVo.getStatusVos();
        if (statusStatisticsVos == null) {
            statusStatisticsVos = new ArrayList<>();
            deviceCommunityVo.setStatusVos(statusStatisticsVos);
        }
        setStatusStatisticsVos(statusStatisticsVos,communityVo);
        if (isEmpty) {
            deviceCommunityVos.add(deviceCommunityVo);
            communityProductCategoryVo.setCategoryStatusVos(deviceCommunityVos);
        }
        communityProductCategoryVoHashMap.put(communityVo.getCommunityId(), communityProductCategoryVo);
    }

    /**
    * @author Andy
    * @description 合并相同的分类数据
    * @date 14:05 2021/7/30
    * @param productCategoryCommunityVoMap, communityVo
    * @return void
    **/
    private void mergeCategoryCommunity(Map<Long, ProductCategoryCommunityVo> productCategoryCommunityVoMap, DeviceCategoryCommunityVo communityVo){
        ProductCategoryCommunityVo productCategoryCommunityVo = productCategoryCommunityVoMap.get(communityVo.getCategoryId());
        if (productCategoryCommunityVo == null) {
            productCategoryCommunityVo = new ProductCategoryCommunityVo();
            productCategoryCommunityVo.setCategoryId(communityVo.getCategoryId());
            productCategoryCommunityVo.setCategoryName(communityVo.getCategoryName());
        }
        // 查找小区
        List<DeviceCommunityVo> deviceCommunityVos = productCategoryCommunityVo.getCommunityVos();
        if (CollectionUtils.isEmpty(deviceCommunityVos)) {
            deviceCommunityVos = new ArrayList<>();
        }
        DeviceCommunityVo deviceCommunityVo = findCommunity(communityVo.getCommunityId(), deviceCommunityVos);
        boolean isEmpty = false;
        if (deviceCommunityVo == null) {
            deviceCommunityVo = new DeviceCommunityVo();
            BeanCopyUtils.copyProperties(communityVo, deviceCommunityVo, DeviceCommunityVo.class);
            isEmpty = true;
        }
        List<StatusStatisticsVo> statusStatisticsVos = deviceCommunityVo.getStatusVos();
        if (statusStatisticsVos == null) {
            statusStatisticsVos = new ArrayList<>();
            deviceCommunityVo.setStatusVos(statusStatisticsVos);
        }
        setStatusStatisticsVos(statusStatisticsVos, communityVo);
        if (isEmpty) {
            deviceCommunityVos.add(deviceCommunityVo);
            productCategoryCommunityVo.setCommunityVos(deviceCommunityVos);
        }
        productCategoryCommunityVoMap.put(communityVo.getCategoryId(), productCategoryCommunityVo);
    }

    /**
    * @author Andy
    * @description 设置状态数据
    * @date 14:06 2021/7/30
    * @param statusStatisticsVos, communityVo
    * @return void
    **/
    private void setStatusStatisticsVos(List<StatusStatisticsVo> statusStatisticsVos, DeviceCategoryCommunityVo communityVo){
        StatusStatisticsVo statusStatisticsVo = new StatusStatisticsVo();
        BeanCopyUtils.copyProperties(communityVo, statusStatisticsVo, StatusStatisticsVo.class);
        statusStatisticsVos.add(statusStatisticsVo);
    }

    /**
    * @author Andy
    * @description 查找小区
    * @date 14:06 2021/7/30
    * @param communityId, list
    * @return com.zcxk.rmcp.api.vo.DeviceCommunityVo
    **/
    private DeviceCommunityVo findCommunity(Long communityId, List<DeviceCommunityVo> list){
        for (DeviceCommunityVo deviceCommunityVo : list) {
            if (deviceCommunityVo.getCommunityId().equals(communityId)) {
                return deviceCommunityVo;
            }
        }
        return null;
    }

    /**
    * @author Andy
    * @description 查找分类
    * @date 14:06 2021/7/30
    * @param categoryId, list
    * @return com.zcxk.rmcp.api.vo.ProductCategoryStatusVo
    **/
    private ProductCategoryStatusVo findProductCategory(Long categoryId, List<ProductCategoryStatusVo> list){
        for (ProductCategoryStatusVo productCategoryStatusVo : list) {
            if (productCategoryStatusVo.getCategoryId().equals(categoryId)) {
                return productCategoryStatusVo;
            }
        }
        return null;
    }

    /**
     * @author Andy
     * @description 统计状态数
     * @date 16:34 2021/7/21
     * @param statusMap, statistic
     * @return void
     **/
    private void totalStatus(Map<String, StatusStatisticsVo> statusMap, StatusStatisticsVo statistic){
        StatusStatisticsVo statusStatisticsVo = statusMap.get(statistic.getStatus());
        if (statusStatisticsVo == null) {
            statusStatisticsVo = new StatusStatisticsVo();
        }
        statusStatisticsVo.setStatus(statistic.getStatus());
        statusStatisticsVo.setTotal(statusStatisticsVo.getTotal() + statistic.getTotal());
        statusMap.put(statistic.getStatus(), statusStatisticsVo);
    }

    /**
     * @author Andy
     * @description 占比运算
     * @date 16:34 2021/7/21
     * @param ratioList, total
     * @return void
     **/
    private void ratioDevice(List<DeviceStatisticsVo.DeviceRatio> ratioList, int total){
        for (DeviceStatisticsVo.DeviceRatio ratio : ratioList) {
            ratio.setRatio(BigDecimalUtils.percentDivide(ratio.getTotal(), total, 2));
        }
    }

    @Override
    public void downTemplate(Integer categoryId, HttpServletResponse response) {
        DownloadExcelData downloadExcelData = new DownloadExcelData();
        downloadExcelData.setCategoryId(categoryId);
        downloadExcelData.setResponse(response);
        DeviceExcelFillAdapter template = new DeviceExcelFillAdapter();
        template.build(downloadExcelData).setParam(deviceDownloadExcelService).fillData().downloadExcel();
    }

    @Override
    public ResultMessage saveExcelData(DeviceImportData data, ExcelData excelData) {
        log.info("device saveExcelData data = {}",JSON.toJSONString(data));
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(false);
        try {
            // 1、校验检查
            if (deviceMapper.findByDeviceNoUnique(null, data.getDeviceNo()) > 0) {
                resultMessage.setMessage(RmcpErrorEnum.RMCP_DEVICE_NO_UNIQUE_ERROR.getMessage());
                return resultMessage;
            }
            if (deviceMapper.findByMeterNoUnique(null, data.getMeterNo()) > 0) {
                resultMessage.setMessage(RmcpErrorEnum.RMCP_METER_NO_UNIQUE_ERROR.getMessage());
                return resultMessage;
            }

            // 2、小区查询
            Community community = null;
            if(StringUtils.isNotEmpty(data.getCommunityName())){
                community = communityService.findByName(excelData.getImportFile().getTenantId(),data.getCommunityName());
                if (community == null) {
                    resultMessage.setMessage("小区不存在");
                    return resultMessage;
                }
            }


            // 3、公司部门查询
            Org companyOrg = orgService.findByName(excelData.getImportFile().getTenantId(),data.getCompanyOrgName());
            if (companyOrg == null) {
                resultMessage.setMessage("公司不存在");
                return resultMessage;
            }
            Org deptOrg = null;
            if(StringUtils.isNotEmpty(data.getDeptOrgName())){
                deptOrg = orgService.findByParentIdAndName(companyOrg.getId(),data.getDeptOrgName());
                if (deptOrg == null) {
                    resultMessage.setMessage("部门不存在");
                    return resultMessage;
                }
            }

            // 4、产品（设备类型）查询
            String[] deviceType  = StringUtils.split(data.getDeviceTypeName(),"/");
            Product product = productService.getByName(deviceType[1],deviceType[2]);
            if (product == null) {
                resultMessage.setMessage("设备型号不存在");
                return resultMessage;
            }

            // 5、保存数据
            Device device = new Device();
            device.setId(idWorker.nextId());
            device.setTenantId(excelData.getImportFile().getTenantId());
            device.setDeviceNo(data.getDeviceNo());
            device.setMeterNo(data.getMeterNo());
            device.setFileNo(data.getFileNo());
            device.setSealNo(data.getSealNo());
            device.setProductId(product.getId());
            device.setCategoryId(product.getProductCategoryId());
            device.setCompanyOrgId(companyOrg.getId());
            if (deptOrg != null) {
                device.setDeptOrgId(deptOrg.getId());
            }
            if (community != null) {
                device.setCommunityId(community.getId());
            }
            device.setUserName(data.getUsername());
            device.setUserPhone(data.getPhone());
            device.setIdCard(data.getIdCard());
            device.setOldEndDegree(data.getReadData());
            device.setAddress(data.getAddress());
            device.setDeviceStatus(DeviceStatusEnum.UNUSED.getCode());
            device.setValveStatus(ValveStatusEnum.ON.getCode());
            device.setStatus(StatusEnum.OK.getCode());
            this.insertSelective(device);

            resultMessage.setStatus(true);
        }catch (Exception e){
            log.info("导入数据异常 e : {} {}",e.getMessage(),e);
            resultMessage.setMessage("数据异常");
            return resultMessage;
        }

        return resultMessage;
    }

    @Override
    public void batchValve(List<Long> ids, Integer valveStatus) {
        log.info("begin batchValve ids:{},valveStatus:{}",ids,valveStatus);
        log.info("end batchValve");
    }

    @Override
    public List<DeviceVo> queryDeviceInfoList(String deviceNo, String meterNo) {
        return deviceMapper.queryDeviceInfoList(deviceNo,meterNo,UserUtil.getCurrentUser().getUserCondition());
    }
}
