package com.junmp.jyzb.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.junmp.jyzb.api.bean.dto.fetchingDataDto.WarehouseInfoDto;
import com.junmp.jyzb.api.bean.dto.WarehouseDto;
import com.junmp.jyzb.api.bean.query.InventorySumReq;
import com.junmp.jyzb.api.bean.query.WarehouseReq;
import com.junmp.jyzb.api.bean.req.OpenDoorReq;
import com.junmp.jyzb.api.bean.req.UpdateWarehouseReq;
import com.junmp.jyzb.api.bean.vo.InOrderInfoVo;
import com.junmp.jyzb.api.exception.enums.WarehouseExceptionEnum;
import com.junmp.jyzb.api.bean.query.WsWarehouseReq;
import com.junmp.jyzb.cache.DeviceRedisCache;
import com.junmp.jyzb.cache.TemperatureRedisCache;
import com.junmp.jyzb.entity.*;
import com.junmp.jyzb.api.exception.enums.CabinetExceptionEnum;
import com.junmp.jyzb.entity.Temp.HumidityAndtemperature;
import com.junmp.jyzb.mapper.*;
import com.junmp.jyzb.service.InventorySummaryService;
import com.junmp.jyzb.service.PubOrgService;
import com.junmp.jyzb.service.WarehouseService;
import com.junmp.jyzb.utils.*;
import com.junmp.v2.auth.api.context.LoginContext;
import com.junmp.v2.common.exception.base.ServiceException;
import com.junmp.v2.common.util.BeanPlusUtil;
import com.junmp.v2.common.util.HttpServletUtil;
import com.junmp.v2.office.api.OfficeExcelApi;
import com.junmp.v2.office.api.bean.ExcelExportParam;
import com.junmp.v2.sys.user.entity.SysUser;
import com.junmp.v2.sys.user.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class WarehouseServiceImpl extends ServiceImpl<WarehouseMapper,Warehouse> implements WarehouseService {


    @Resource
    private WarehouseMapper warehouseMapper;

    @Resource
    private PubOrgService pubOrgService;

    @Resource
    private TemperatureRedisCache temperatureRedisCache;

    @Autowired
    private RabbitMQSendMsg MQ;
    @Resource
    private DeviceRedisCache redisCache;
    @Resource
    private OfficeExcelApi officeExcelApi;
    @Resource
    private RabbitAdmin rabbitAdmin;

    @Resource
    private RabbitTemplate rabbitTemplate;
    @Resource
    private SysUserService sysUserService;

    @Resource
    private InventorySummaryService inventorySummaryService;


    @Override
    public WsWarehouseReq CheckState(WarehouseReq req) {
        WsWarehouseReq warehouseReq=new WsWarehouseReq();

       String deviceData= redisCache.get(req.getOrgId().toString());
       if (ObjectUtil.isNull(deviceData))
       {
           warehouseReq.setOrgId(req.getOrgId().toString());
           warehouseReq.setOnlineState("false");
       }
       else
       {
           warehouseReq.setOnlineState("true");
           warehouseReq = JSON.parseObject(deviceData, WsWarehouseReq.class);

       }
        return warehouseReq;
    }

    @Override
    public String AddWarehouse(UpdateWarehouseReq req) {
        List<Warehouse> list = list(new LambdaQueryWrapper<Warehouse>().eq(Warehouse::getName, req.getName()).eq(Warehouse::getOrgIdInt,req.getOrgId()));
        if (CollectionUtil.isNotEmpty(list)){
            throw new ServiceException(WarehouseExceptionEnum.WAREHOUSE_NAME_IS_EXIET);
        }
        Warehouse warehouse = new Warehouse();
        BeanPlusUtil.copyProperties(req, warehouse);
        warehouse.setOrgIdInt(req.getOrgId());
        warehouse.setCreateTime(DateTimeUtil.getCurrentDateTime());
        warehouse.setUpdateTime(DateTimeUtil.getCurrentDateTime());
        //随机生成6位库房编号
        Random random = new Random();
        int code;
        List<String> warehouseCodeList = list().stream().map(Warehouse::getCode).collect(Collectors.toList());
        boolean codeExists;
        do {
            code = random.nextInt(900000) + 100000; // 生成6位随机数
            codeExists = warehouseCodeList.contains(String.valueOf(code)); // 检查生成的随机数是否在列表中
        } while (codeExists);
        warehouse.setCode(String.valueOf(code));
        save(warehouse);
        MQ.SendMsg("warehouseMsg",req.getOrgId().toString(),"InfoChange",4,"Adding warehouseInfo",
                null,null,new ArrayList<>(),null,null);
        return warehouse.getId();
    }

    @Override
    public String OpenDoor(OpenDoorReq req) throws UnsupportedEncodingException {
        if (ObjectUtil.isNull(req.getUserId()) ) {
            // 人员信息没有传入，从上下文获取当前登录用户并设置到请求对象中
            SysUser StartUser= sysUserService.getById(LoginContext.getContext().getLoginUser());
            req.setUserId(String.valueOf(StartUser.getUserId()));
            req.setUserName(StartUser.getRealName());
        }
        String exchangeName="DeviceControl";

        // 将请求对象序列化为JSON字符串
        String jsonString = JSON.toJSONString(req);
        MessagePostProcessor messagePostProcessor = message -> {
            MessageProperties messageProperties = message.getMessageProperties();
            if (messageProperties == null) {
                messageProperties = new MessageProperties();
            }
            messageProperties.setContentType("application/json");
            messageProperties.setContentEncoding("UTF-8"); // 设置消息字符编码为UTF-8
            messageProperties.setExpiration("10000"); // 设置消息的过期时间为10秒
            return message;
        };

        // 创建广播交换器
        FanoutExchange exchange = new FanoutExchange ("DeviceControl");

        rabbitAdmin.declareExchange(exchange);
        // 将消息体封装到Message对象中
        Message message = MessageBuilder.withBody(jsonString.getBytes("UTF-8"))
                .setExpiration("10000") // 设置消息的过期时间为10秒
                .build();

        // 发送消息到RabbitMQ
        rabbitTemplate.convertAndSend(exchangeName, req.getWarehouseId(), message, messagePostProcessor);

        return null;
    }

    @Override
    public WarehouseDto getOneWarehouse(WarehouseReq req) {
        Warehouse warehouse = WarehoustExist(req.getId());
        WarehouseDto warehouseDto = new WarehouseDto();
        BeanPlusUtil.copyProperties(warehouse,warehouseDto);
        warehouseDto.setOrgId(warehouse.getOrgIdInt());
        //获取组织机构名称
        PubOrg pubOrg = pubOrgService.PubOrgExist(warehouse.getOrgIdInt());
        warehouseDto.setOrgName(pubOrg.getOrgName());
        return warehouseDto;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean DeleteWarehouse(UpdateWarehouseReq req) {
        if(ObjectUtil.isNull(req.getWarehouseList())||req.getWarehouseList().size()==0 ){
            throw new ServiceException(CabinetExceptionEnum.PARAMETER_ERROR);
        }
        List<String> warehouseList = req.getWarehouseList();
        for (String s:warehouseList) {
            if (s.equals("")){
                throw new ServiceException(CabinetExceptionEnum.PARAMETER_ERROR);
            }
        }
        return removeBatchByIds(warehouseList);
    }

    @Override
    public boolean updateWarehouse(UpdateWarehouseReq req) {
        List<Warehouse> list = list(new LambdaQueryWrapper<Warehouse>().eq(Warehouse::getName, req.getName()).eq(Warehouse::getOrgIdInt,req.getOrgId()));
        if (CollectionUtil.isNotEmpty(list)){
            if (list.size()>2 || (list.size()==1 && !list.get(0).getId().equals(req.getId()))){
                throw new ServiceException(WarehouseExceptionEnum.WAREHOUSE_NAME_IS_EXIET);
            }
        }
        Warehouse warehouse = new Warehouse();
        BeanPlusUtil.copyProperties(req,warehouse);
        if (ObjectUtil.isNotNull(req.getWarehouseType()) && req.getWarehouseType()==0){
            Warehouse one = getById(req.getId());
            //判断warehouse中是否有在库数量，如果有则直接弹出错误说库中存在装备，转换失败，需先将装备全部出库后再修改仓库属性
            InventorySumReq inventorySumReq = new InventorySumReq();
            inventorySumReq.setOrgId(req.getOrgId().toString());
            inventorySumReq.setLocationId(one.getId());
            inventorySumReq.setLocationType("0");
            inventorySumReq.setSearchItem("stockNumber");
            List<InventorySummary> totalNumberAndPrice = inventorySummaryService.getTotalNumberAndPrice(inventorySumReq);
            InventorySummary inventorySummary=new InventorySummary();
            if (CollectionUtil.isNotEmpty(totalNumberAndPrice)){
                inventorySummary=totalNumberAndPrice.get(0);
            }
            if (ObjectUtil.isNotNull(inventorySummary) && ObjectUtil.isNotNull(inventorySummary.getStockNumber()) && inventorySummary.getStockNumber()>0){
                throw new ServiceException(WarehouseExceptionEnum.WAREHOUSE_EXIST_EQS);
            }
        }
        warehouse.setUpdateTime(DateTimeUtil.getCurrentDateTime());
        MQ.SendMsg("warehouseMsg",req.getOrgId().toString(),"InfoChange",4,"Updating warehouseInfo",
                null,null,new ArrayList<>(),null,null);
        return this.updateById(warehouse);
    }



    @Override
    public List<WarehouseDto> getAllWarehouse(Long orgId,Integer state,Integer warehouseType) {
        List<WarehouseDto> warehouseDtoList=new ArrayList<>();
        //判断组织机构是否存在
        PubOrg pubOrg = pubOrgService.PubOrgExist(orgId);
        //根据组织机构id查询组织机构名称
        String orgName = pubOrg.getOrgName();
        List<Warehouse> list = new ArrayList<>();
        if (ObjectUtil.isNull(state) || (state!=1 && state!=0)){
            list = list(new LambdaQueryWrapper<Warehouse>()
                    .eq(Warehouse::getOrgIdInt, orgId)
                    .eq(ObjectUtil.isNotNull(warehouseType),Warehouse::getWarehouseType,warehouseType));
        }else {
            list = list(new LambdaQueryWrapper<Warehouse>()
                    .eq(Warehouse::getOrgIdInt, orgId)
                    .eq(Warehouse::getState,state)
                    .eq(ObjectUtil.isNotNull(warehouseType),Warehouse::getWarehouseType,warehouseType));

        }

        for (Warehouse warehouse:list) {
            WarehouseDto warehouseDto = new WarehouseDto();
            BeanPlusUtil.copyProperties(warehouse,warehouseDto);
            warehouseDto.setOrgName(orgName);
            warehouseDto.setOrgId(warehouse.getOrgIdInt());
            warehouseDtoList.add(warehouseDto);
        }
        return warehouseDtoList;
    }


    private List<Long> getAllOrgId(WarehouseReq msg) {
        List<Long> allOrg = new ArrayList<>();
        if (msg.getIncludeLowerLevel().equals("false")){
            allOrg.add(msg.getOrgId());
        }else if(msg.getIncludeLowerLevel().equals("true")){
            //查询某组织机构的本级及下级
            allOrg = pubOrgService.getLowerOrg(msg.getOrgId());
        }
        return allOrg;
    }

    private List<Warehouse> getAllWarehouseByOrg(List<Long> allOrgId) {
        List<Warehouse> allWarehouse = new ArrayList<>();

        LambdaQueryWrapper<Warehouse> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(Warehouse::getOrgIdInt, allOrgId);

        allWarehouse = warehouseMapper.selectList(queryWrapper);
        return allWarehouse;
    }



    @Override
    public boolean changeWarehouseState(WarehouseReq req) {
        Warehouse warehouse = WarehoustExist(req.getId());
        BeanPlusUtil.copyProperties(req, warehouse);
        warehouse.setUpdateTime(DateTimeUtil.getCurrentDateTime());
//        MQDto mqDto = new MQDto();
//        mqDto.setApi("WarehouseState");
//        mqDto.setWarehouseId(req.getId());
//        if (req.getState()==1){
//            mqDto.setMessage("仓库启用");
//            mqDto.setWarehouseState(1);
//        }else {
//            mqDto.setMessage("仓库禁用");
//            mqDto.setWarehouseState(0);
//        }
//        mqDto.setType(4);
//        MQ.SendMsg("warehouseMsg",warehouse.getOrgIdInt().toString(),mqDto);//推送至仓库主机
        MQ.SendMsg("warehouseMsg",warehouse.getOrgIdInt().toString(),"WarehouseState",4,req.getState()==1?"仓库启用":"仓库禁用",
                req.getId(),req.getState()==1?1:0,new ArrayList<>(),null,null);
        return this.updateById(warehouse);
    }


    //判断仓库是否存在
    @Override
    public Warehouse WarehoustExist(String id) {
        Warehouse warehouseMsg=this.getById(id);
        if (ObjectUtil.isNull(warehouseMsg)){
            throw new ServiceException(WarehouseExceptionEnum.WAREHOUSE_NOT_EXIST);
        }
        return warehouseMsg;
    }

    //设置仓库中的装备信息（在库数，总数，出库数，价格）
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean SetInventoryInfo(String id) {
        //统计仓库总数，在库总数，出库总数，装备总价格
        warehouseMapper.SetInventoryInfo(id);
        return true;
    }

    @Override
    public List<WarehouseInfoDto> alignWarehouseInfo(UpdateWarehouseReq req) {
        String date = DateTimeUtil.TimeLongToString(req.getUpdateTime());
        Long orgId = req.getOrgId();
        return warehouseMapper.alignWarehouseInfo(orgId,date);
    }

    //除湿机上传温湿度
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateHumidityAndtemperature(HumidityAndtemperature req) {

        //查询数据库仓库id取到仓库名称
        Warehouse warehouse = getById(req.getWarehouseId());
        //将数据放入redis
        temperatureRedisCache.addTemperatureHumidity(req.getWarehouseId(),warehouse.getName(),
                req.getCreateTime(),req.getHumidity(),req.getTemperature(),req.getDeviceName());
        //更新仓库的温度和湿度
        //将仓库信息存入redis中，
        warehouse.setHumidity(req.getHumidity());
        warehouse.setTemperature(req.getTemperature());
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            String redisExist= redisCache.get("warehouseHumAndTemp:"+warehouse.getId());
            if(redisExist!=null)//已有存在数据
            {

                String jsonData = objectMapper.writeValueAsString(warehouse);
                redisCache.put("warehouseHumAndTemp:"+warehouse.getId(), jsonData);
            }
            else
            {
                String jsonData = objectMapper.writeValueAsString(warehouse);
                redisCache.put("warehouseHumAndTemp:"+warehouse.getId(), jsonData);
            }
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }

        return true;

    }

    //获取redis中的温湿度记录
    @Override
    public List<HumidityAndtemperature> showHumidityAndtemperature(WarehouseReq req) {
//        String date="2023-12-01 00:00:00";
//        Long startTimeStamp = DateTimeUtil.TimeStringToLong(date);
//        Long endTimeStamp = DateTimeUtil.getCurrentDateTime().toInstant().toEpochMilli();
        List<Object> dataByTimestampRange =new ArrayList<>();
        if (ObjectUtil.isNotNull(req.getStartTime()) && ObjectUtil.isNotNull(req.getEndTime())){
            Long startTimeStamp = DateTimeUtil.TimeDateToLong(req.getStartTime());
            Long endTimeStamp = DateTimeUtil.TimeDateToLong(req.getEndTime());
            dataByTimestampRange = temperatureRedisCache.getDataByTimestampRange(req.getId(), startTimeStamp, endTimeStamp);
        }else {
            temperatureRedisCache.getRedisTemplate().opsForZSet().range("WarehouseDev:"+req.getId(),0,-1);
        }
        List<HumidityAndtemperature> collect = dataByTimestampRange.stream()
                .map(obj -> (HumidityAndtemperature) obj)
                .sorted(Comparator.comparingLong(HumidityAndtemperature::getCreateTime).reversed())
                .collect(Collectors.toList());

        return collect;
    }

    @Override
    public void HumidityAndtemperatureExport(WarehouseReq req) {
        List<HumidityAndtemperature> collect = showHumidityAndtemperature(req);
        HttpServletResponse response = HttpServletUtil.getResponse();
        ExcelExportParam param = new ExcelExportParam();
        param.setDataList(collect);
        param.setClazz(InOrderInfoVo.class);
        param.setResponse(response);
        param.setFileName("入库单据列表.xls");
        //对数据进行导出
        officeExcelApi.easyExportDownload(param);

    }

    @Override
    public Warehouse GetWareHouseInfoByRedis(WarehouseReq req) {
        String s = redisCache.get("warehouseHumAndTemp:" + req.getId());
        if (ObjectUtil.isNotEmpty(s)){
            return JSONObject.parseObject(s, Warehouse.class);
        }
        return getById(req.getId());
    }

    public List<String> checkWarehouseList(List<String> locationNameList) {
        LambdaQueryWrapper<Warehouse> warehosueEq=new LambdaQueryWrapper<>();
        warehosueEq.in(CollectionUtil.isNotEmpty(locationNameList),Warehouse::getName,locationNameList);
        List<Warehouse> locationList = list(warehosueEq);
        List<String> noneExitentLocations=new ArrayList<>();
        for (String locationName:locationNameList) {
            boolean flag=false;
            for (Warehouse location:locationList) {
                if (location.getName().equals(locationName)){
                    flag=true;
                    break;
                }
            }
            if (!flag){
                noneExitentLocations.add(locationName);
            }
        }
        return noneExitentLocations;
    }


}
