package cn.iocoder.yudao.module.pms.service.yanfan.product;

import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.module.pms.controller.admin.yanfan.cache.ITSLCache;
import cn.iocoder.yudao.module.pms.controller.admin.yanfan.cache.ITSLValueCache;
import cn.iocoder.yudao.module.pms.controller.admin.yanfan.product.vo.*;
import cn.iocoder.yudao.module.pms.controller.admin.yanfan.redis.RedisCache;
import cn.iocoder.yudao.module.pms.controller.admin.yanfan.redis.RedisKeyBuilder;
import cn.iocoder.yudao.module.pms.dal.dataobject.yanfan.device.YfIotDeviceDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.yanfan.product.IotYfProductDO;
import cn.iocoder.yudao.module.pms.dal.mysql.yanfan.device.YfIotDeviceMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.yanfan.devicetemplate.IotYfDeviceTemplateMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.yanfan.product.IotYfProductMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.yanfan.thingsmodel.IotYfThingsModelTemplateMapper;
import cn.iocoder.yudao.module.pms.service.yanfan.thingsmodel.IotYfThingsModelService;
import cn.iocoder.yudao.module.pms.util.StringUtils;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.collections4.CollectionUtils;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;


import javax.annotation.Resource;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;

/**
 * 产品 Service 实现类
 *
 * @author 超级管理员
 */
@Service
@Validated
public class IotYfProductServiceImpl implements IotYfProductService {

    @Resource
    private IotYfProductMapper iotYfProductMapper;
    @Value("${spring.mqtt.prod-def-user:yanfan}")
    private String prodDefUsername;
    @Autowired
    private IotYfDeviceTemplateMapper iotYfDeviceTemplateMapper;
    @Autowired
    private IotYfThingsModelTemplateMapper iotYfThingsModelTemplateMapper;
    @Autowired
    private IotYfThingsModelService iotYfThingsModelService;
    @Autowired
    private YfIotDeviceMapper yfIotDeviceMapper;
    @Resource
    private ITSLValueCache thingModelCache;
    @Resource
    private ITSLCache itslCache;
    @Autowired
    private RedisCache redisCache;

    @Override
    public void changeProductStatus(ChangeProductStatusModel model) {
        if (model.getStatus() != 1 && model.getStatus() != 2) {
            throw new ServiceException(new ErrorCode(111,"状态更新失败,状态值有误"));
        }
        if (model.getStatus() == 2) {
            // 不需要一定要有物模型才可以发布
            updateDeviceStatusByProductIdAsync(model.getProductId());
            //更新物模型缓存
            itslCache.setCacheThingsModelByProductId(model.getProductId());
        }
        IotYfProductDO iotYfProductDO = iotYfProductMapper.selectById(model.getProductId());
        iotYfProductDO.setStatus(model.getStatus());
        iotYfProductMapper.updateById(iotYfProductDO);
    }

    @Async
    public void updateDeviceStatusByProductIdAsync(Long productId) {
        List<String> deviceNumbers = yfIotDeviceMapper.selectList("product_id", productId).stream().map(YfIotDeviceDO::getSerialNumber).collect(Collectors.toList());
        deviceNumbers.forEach(x -> {
            // 缓存新的物模型值
            thingModelCache.addCacheDeviceStatus(productId, x);
        });
    }

    @Override
    public Long createIotProduct(IotYfProductSaveReqVO createReqVO) {
        // 插入
        IotYfProductDO product = BeanUtils.toBean(createReqVO, IotYfProductDO.class);

        // mqtt账号密码
        if (product.getMqttAccount() == null || product.getMqttAccount().equals("")) {
            product.setMqttAccount(prodDefUsername);
        }
        if (product.getMqttPassword() == null || product.getMqttPassword().equals("")) {
            product.setMqttPassword("P" + StringUtils.getStringRandom(15));
        }
        if (product.getMqttSecret() == null || product.getMqttSecret().equals("")) {
            product.setMqttSecret("K" + StringUtils.getStringRandom(15));
        }
        product.setStatus(product.getStatus() == null ? 1 : product.getStatus());
        product.setCreateTime(LocalDateTime.now());
        product.setDeleted(false);
        //todo
//        if("HTTP".equals(product.getTransport())){
//            List<HttpParam> headers = product.getHeadersList();
//            product.setHeaders(JSONArray.toJSONString(headers));
//            List<HttpParam> paramsDataList = product.getParamsDataList();
//            product.setParamsData(JSONArray.toJSONString(paramsDataList));
//            userParmas userParmas = product.getUserParmas();
//            product.setUsername(userParmas.getUser());
//            product.setUserpassword(userParmas.getPassword());
//            product.setHttpurl(userParmas.getUrl());
//            //需要获取登录key
//            if(userParmas.getIsLogin()){
//                product.setHttptype(1);
//                String key = httplogin(userParmas.getUser(),userParmas.getPassword(),userParmas.getUrl());
//                if (key.equals("请求参数失败")) {
//                    System.out.println("请求key参数失败");
//                    return null;
//                }
//                product.setUserkey(key);
//            }
//            else{
//                product.setHttptype(0);
//            }
//        }


        int i = iotYfProductMapper.insert(product);
        //todo
        //新增HTTP传输协议产品后创建定时任务
//        if("HTTP".equals(product.getTransport()) && i > 0){
//            SysJob sysJob = new SysJob();
//            sysJob.setJobId(product.getProductId());
//            sysJob.setJobName(product.getProductName()+"-http请求定时任务");
//            sysJob.setCronExpression(product.getCronExpression());
//            sysJob.setInvokeTarget("iotHttpClient.ProductJob("+product.getProductId() +  "L)");
//            sysJob.setMisfirePolicy("2");
//            sysJob.setStatus("0");
//            sysJob.setConcurrent("0");
//            sysJob.setJobGroup("SYSTEM");
//            sysJob.setCreateBy(getLoginUser().getUsername());
//            try {
//                sysJobService.insertJob(sysJob);
//            } catch (SchedulerException e) {
//                e.printStackTrace();
//            } catch (TaskException e) {
//                e.printStackTrace();
//            }
//        }
//        if("SNMP".equals(product.getTransport()) && i>0 ) {
//            SysJob sysJob = new SysJob();
//            sysJob.setJobId(product.getProductId());
//            sysJob.setJobName(product.getProductName()+"-snmp定时任务");
//            sysJob.setCronExpression(product.getCronExpression());
//            sysJob.setInvokeTarget("snmpJob.snmpProductJob("+product.getProductId() +  "L)");
//            sysJob.setMisfirePolicy("2");
//            sysJob.setStatus("0");
//            sysJob.setConcurrent("0");
//            sysJob.setJobGroup("SYSTEM");
//            sysJob.setCreateBy(getLoginUser().getUsername());
//            try {
//                sysJobService.insertJob(sysJob);
//            } catch (SchedulerException e) {
//                e.printStackTrace();
//            } catch (TaskException e) {
//                e.printStackTrace();
//            }
//        }

        /*如果产品属于modbus协议（云端轮询）需要记录变量模板与产品关系*/
//        if (product.getTemplateId() != null) {
//            IotYfDeviceTemplateDO template = new IotYfDeviceTemplateDO();
//            template.setProductId(product.getProductId());
//            template.setTemplateId(product.getTemplateId());
//            iotYfDeviceTemplateMapper.insert(template);
//
//            //将模板物模型导入到物模型表
//            List<IotYfThingsModelTemplateDO> thingsModelTemplates = iotThingsModelTemplateMapper.selectAllByTemplateId(product.getTemplateId(), String.valueOf(product.getTemplateId()));
//            Long[] ids = thingsModelTemplates.stream().map(IotYfThingsModelTemplateDO::getTemplateId).toArray(Long[]::new);
//            ImportThingsModelInput input = new ImportThingsModelInput();
//            input.setTemplateIds(ids);
//            input.setProductId(product.getProductId());
//            input.setProductName(product.getProductName());
//            iotYfThingsModelService.importByTemplateIds(input);
//        }
//        return product;
        // 返回
        return product.getProductId();
    }

    @Override
    public void updateIotProduct(IotYfProductSaveReqVO product) {
        //修改HTTP传输协议产品
        if("HTTP".equals(product.getTransport())){
            userParmas userParmas = product.getUserParmas();
            product.setUsername(userParmas.getUser());
            product.setUserpassword(userParmas.getPassword());
            product.setHttpurl(userParmas.getUrl());
            //需要获取登录key
            if(userParmas.getIsLogin()){
                product.setHttptype(1);
                String key = httplogin(userParmas.getUser(),userParmas.getPassword(),userParmas.getUrl());
                if (key.equals("请求参数失败")) {
                    return;
                }
                product.setUserkey(key);
            }
            else{
                product.setHttptype(0);
            }
            List<HttpParam> headers = product.getHeadersList();
            product.setHeaders(JSONArray.toJSONString(headers));
            List<HttpParam> paramsDataList = product.getParamsDataList();
            product.setParamsData(JSONArray.toJSONString(paramsDataList));

            //修改定时任务 cron表达式
            //todo yf
//            SysJob sysJob = new SysJob();
//            sysJob.setJobId(product.getProductId());
//            sysJob.setCronExpression(product.getCronExpression());
//            sysJob.setStatus("1");
//
//            try {
//                sysJobService.updateJob(sysJob);
//            } catch (SchedulerException e) {
//                e.printStackTrace();
//            } catch (TaskException e) {
//                e.printStackTrace();
//            }
        }

        //修改SNMP传输协议产品
        if("SNMP".equals(product.getTransport())){
            //修改定时任务 cron表达式
            //todo yf
//            SysJob sysJob = sysJobService.selectJobById(product.getProductId());
//            sysJob.setCronExpression(product.getCronExpression());
//            try {
//                sysJobService.updateJob(sysJob);
//            } catch (SchedulerException e) {
//                e.printStackTrace();
//            } catch (TaskException e) {
//                e.printStackTrace();
//            }
        }
        IotYfProductDO updateObj = BeanUtils.toBean(product, IotYfProductDO.class);

        iotYfProductMapper.updateById(updateObj);
    }

    @Override
    public String httplogin(String username, String password,String rul){
        String token = null;
        //连接
        HttpURLConnection connection = null;
        OutputStream os = null;
        InputStream is = null;
        BufferedReader br = null;
        try {
            //创建连接对象
            URL url = new URL(rul);
            //创建连接
            connection = (HttpURLConnection) url.openConnection();
            //设置请求方法
            connection.setRequestMethod("POST");
            //设置连接超时时间
            connection.setConnectTimeout(15000);
            //设置读取超时时间
            connection.setReadTimeout(15000);
            //DoOutput设置是否向httpUrlConnection输出，DoInput设置是否从httpUrlConnection读入，此外发送post请求必须设置这两个
            //设置是否可读取
            connection.setDoOutput(true);
            connection.setDoInput(true);
            //设置通用的请求属性
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
            connection.setRequestProperty("Content-Type", "application/json;charset=utf-8");

            //数据请求
            // 拼装参数
            String param = "{\"user_name\":\"" + username + "\",\"user_password\":\"" + password + "\"}";

            // 设置参数
            os = connection.getOutputStream();
            // 发送参数
            os.write(param.getBytes(StandardCharsets.UTF_8));
            os.flush();
            // 获取响应码
            int responseCode = connection.getResponseCode();
            System.out.println("响应码: " + responseCode);            //读取响应
            // 读取响应
            if (responseCode == HttpURLConnection.HTTP_OK) {
                InputStream iss = connection.getInputStream();
                br = new BufferedReader(new InputStreamReader(iss, StandardCharsets.UTF_8));

                StringBuilder responseData = new StringBuilder();
                String line;
                while ((line = br.readLine()) != null) {
                    responseData.append(line);
                }

                // 将响应数据解析为JSON对象
                JSONObject jsonResponse = JSONObject.parseObject(responseData.toString());
                // 假设你需要的数据在JSON对象的"data"键中
                String data = jsonResponse.getString("result_data");
                //获取token值
                JSONObject jsonResponsedata = JSONObject.parseObject(data);
                token = jsonResponsedata.getString("token");
            } else {
                System.out.println("请求失败");
                return "请求失败";
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            try {
                if (os != null) {
                    os.close();
                }
                if (is != null) {
                    is.close();
                }
                if (br != null) {
                    br.close();
                }
                if (connection != null) {
                    connection.disconnect();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return token;
    }

    @Override
    public void deleteIotProduct(Long id) {
        // 校验存在
        validateIotProductExists(id);
        // 删除
        iotYfProductMapper.deleteById(id);
    }

    private void validateIotProductExists(Long id) {
        if (iotYfProductMapper.selectById(id) == null) {
            throw exception(new ErrorCode(222,"不存在产品"));
        }
    }

    @Override
    public IotYfProductRespVO getIotProduct(Long id) {
        IotYfProductDO product = iotYfProductMapper.selectById(id);
        IotYfProductRespVO respVO = new IotYfProductRespVO();
        BeanUtils.copyProperties(product, respVO);
        if (Objects.nonNull(product) && Objects.equals(product.getTransport(),"HTTP")) {
            Integer httptype = product.getHttptype();
            userParmas userParmas = new userParmas();
            if (httptype==1) {
                userParmas.setUser(product.getUsername());
                userParmas.setPassword(product.getUserpassword());
                userParmas.setIsLogin(true);
                userParmas.setUrl(product.getUrl());
            }else {
                userParmas.setIsLogin(false);
            }
            respVO.setUserParmas(userParmas);
        }
        return respVO;
    }

    @Override
    public PageResult<IotYfProductDO> getIotProductPage(IotYfProductPageReqVO pageReqVO) {
        return iotYfProductMapper.selectPage(pageReqVO);
    }


    /**
     * 根据设备编号查询产品信息
     *
     * @param serialNumber 设备编号
     * @return 结果
     */
    @Cacheable(value = "product", key = "#root.methodName + '_' + #serialNumber", unless = "#result == null")
    @Override
    public IotYfProductDO getProductBySerialNumber(String serialNumber) {
        return iotYfProductMapper.getProductBySerialNumber(serialNumber);
    }

    @Override
    public String selectImgUrlByProductId(Long productId) {
        IotYfProductDO iotYfProductDO = iotYfProductMapper.selectById(productId);
        return iotYfProductDO.getImgUrl();
    }

    @CacheEvict(value = "product", allEntries = true)
    @Override
    @Transactional
    public void deleteProductByProductIds(Long[] productIds) {
        // 删除物模型JSON缓存
        for (int i = 0; i < productIds.length; i++) {
            String key = RedisKeyBuilder.buildTSLCacheKey(productIds[i]);
            redisCache.deleteObject(key);
        }
        // 产品下不能有固件
        //todo yf
//        int firmwareCount = productMapper.firmwareCountInProducts(productIds);
//        if (firmwareCount > 0) {
//            return AjaxResult.error("删除失败，请先删除对应产品下的固件");
//        }
        // 产品下不能有设备
        Long l = yfIotDeviceMapper.deviceCountInProducts(Arrays.asList(productIds));
        if (l > 0) {
            throw new ServiceException(new ErrorCode(111,"存在设备无法删除"));
        }
        //todo yf
        // 产品下不能有场景联动
//        List<SceneDeviceBindVO> sceneDeviceBindVOList = sceneDeviceMapper.listSceneProductBind(productIds);
//        if (CollectionUtils.isNotEmpty(sceneDeviceBindVOList)) {
//            String sceneNames = sceneDeviceBindVOList
//                    .stream()
//                    .map(SceneDeviceBindVO::getSceneName)
//                    .collect(Collectors.joining("，"));
//            return AjaxResult.error("删除失败，请先修改或删除对应产品下的场景联动：" + sceneNames);
//        }

        // 删除产品物模型
        iotYfProductMapper.deleteProductThingsModelByProductIds(productIds);
        //todo yf
        // 删除产品的授权码
//        productAuthorizeMapper.deleteProductAuthorizeByProductIds(productIds);
        //todo yf
        //删除产品的定时任务
//        List<Long> productJobIdList = new ArrayList<>();
//        for (Long productId : productIds) {
//            Product product = this.selectProductByProductId(productId);
//            if("HTTP".equals(product.getTransport()) || "SNMP".equals(product.getTransport())){
//                productJobIdList.add(productId);
//            }
//        }
        //todo yf
        // HTTP协议的产品id
//        Long[] productJobIds = productJobIdList.toArray(new Long[productJobIdList.size()]);
//
//        if(productJobIds.length > 0){
//            try {
//                sysJobService.deleteJobByIds(productJobIds);
//            } catch (SchedulerException e) {
//                e.printStackTrace();
//            }
//        }

        iotYfProductMapper.deleteByIds(Arrays.asList(productIds));
    }
}
