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.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.junmp.junmpProcess.dto.json.UserInfo;
import com.junmp.jyzb.api.bean.dto.FetchingDataDto.WarehouseInfoDto;
import com.junmp.jyzb.api.bean.dto.MQDto;
import com.junmp.jyzb.api.bean.dto.OrderMainDto;
import com.junmp.jyzb.api.bean.dto.TjDto.WarrantyDataDto;
import com.junmp.jyzb.api.bean.dto.WarehouseDto;
import com.junmp.jyzb.api.bean.query.PolicemanReq;
import com.junmp.jyzb.api.bean.query.QuerySupplierReq;
import com.junmp.jyzb.api.bean.query.TjReq.TjOrgPriceReq;
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.req.WarrantyReq;
import com.junmp.jyzb.api.bean.vo.InOrderInfoVo;
import com.junmp.jyzb.api.exception.enums.WarehouseExceptionEnum;
import com.junmp.jyzb.api.util.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.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.db.api.factory.PageFactory;
import com.junmp.v2.db.api.factory.PageResultFactory;
import com.junmp.v2.db.api.page.PageResult;
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.core.Queue;
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.text.ParseException;
import java.text.SimpleDateFormat;
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;


    @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()));
        if (CollectionUtil.isNotEmpty(list)){
            throw new ServiceException(WarehouseExceptionEnum.WAREHOUSE_NAME_IS_EXIET);
        }
        Warehouse warehouse = new Warehouse();
        BeanPlusUtil.copyProperties(req, warehouse);
        warehouse.setCreateTime(DateTimeUtil.getCurrentDateTime());
        warehouse.setUpdateTime(DateTimeUtil.getCurrentDateTime());
        save(warehouse);
        MQDto mqDto = new MQDto();
        mqDto.setApi("InfoChange");
        //更改类别，1为类型
        mqDto.setType(4);
        mqDto.setMessage("Adding warehouseInfo");
        MQ.SendMsg("warehouseMsg",req.getOrgId().toString(),mqDto);//推送至仓库主机
        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());
        }

        // 将请求对象序列化为JSON字符串
        String jsonString = JSON.toJSONString(req);
        // 创建广播交换器
        FanoutExchange exchange = new FanoutExchange ("DeviceControl");
        String exchangeName="DeviceControl";
        rabbitAdmin.declareExchange(exchange);
        // 将消息体封装到Message对象中
        Message message = MessageBuilder.withBody(jsonString.getBytes())
                .setExpiration("10000") // 设置消息的过期时间为10秒
                .build();

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

        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()));
        if (CollectionUtil.isNotEmpty(list)){
            throw new ServiceException(WarehouseExceptionEnum.WAREHOUSE_NAME_IS_EXIET);
        }
        Warehouse warehouse = new Warehouse();
        BeanPlusUtil.copyProperties(req,warehouse);
        warehouse.setUpdateTime(DateTimeUtil.getCurrentDateTime());
        MQDto mqDto = new MQDto();
        mqDto.setApi("InfoChange");
        //更改类别，1为类型
        mqDto.setType(4);
        mqDto.setMessage("Updating warehouseInfo");
        MQ.SendMsg("warehouseMsg",req.getOrgId().toString(),mqDto);//推送至仓库主机
        return this.updateById(warehouse);
    }



    @Override
    public List<WarehouseDto> getAllWarehouse(Long orgId,Integer state) {
        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));
        }else {
            list = list(new LambdaQueryWrapper<Warehouse>()
                    .eq(Warehouse::getOrgIdInt, orgId)
                    .eq(Warehouse::getState,state));
        }

        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(10);
        MQ.SendMsg("warehouseMsg",warehouse.getOrgIdInt().toString(),mqDto);//推送至仓库主机

        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());
        //更新仓库的温度和湿度
        //将仓库信息存入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());
    }


}
