package com.njzscloud.supervisory.device.service;

import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.map.MapBuilder;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njzscloud.common.core.tuple.Tuple2;
import com.njzscloud.common.mp.support.PageParam;
import com.njzscloud.common.mp.support.PageResult;
import com.njzscloud.common.mqtt.util.Mqtt;
import com.njzscloud.supervisory.config.AppProperties;
import com.njzscloud.supervisory.device.contant.DeviceCode;
import com.njzscloud.supervisory.device.mapper.DeviceInfoMapper;
import com.njzscloud.supervisory.device.pojo.entity.DeviceInfoEntity;
import com.njzscloud.supervisory.order.contant.CheckStatus;
import com.njzscloud.supervisory.order.contant.OrderStatus;
import com.njzscloud.supervisory.order.contant.PaymentStatus;
import com.njzscloud.supervisory.order.contant.SettlementWay;
import com.njzscloud.supervisory.order.pojo.entity.OrderCarInOutEntity;
import com.njzscloud.supervisory.order.pojo.entity.OrderInfoEntity;
import com.njzscloud.supervisory.order.pojo.param.TruckComingOrderParam;
import com.njzscloud.supervisory.order.pojo.param.TruckLeavingOrderParam;
import com.njzscloud.supervisory.order.pojo.result.OrderPagingResult;
import com.njzscloud.supervisory.order.service.OrderCarInOutService;
import com.njzscloud.supervisory.order.service.OrderInfoService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 设备信息表
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DeviceInfoService extends ServiceImpl<DeviceInfoMapper, DeviceInfoEntity> implements IService<DeviceInfoEntity> {
    private static final TimedCache<String, Tuple2<String, String>> waitOpen = CacheUtil.newTimedCache(600000);
    private final OrderInfoService orderInfoService;
    private final OrderCarInOutService orderCarInOutService;
    private final AppProperties appProperties;

    public static void open(String oredrSn) {
        Tuple2<String, String> tuple2 = waitOpen.get(oredrSn);
        if (tuple2 == null) {
            log.warn("开门: {} 无等待订单", oredrSn);
            return;
        }
        String sn = tuple2.get_0();
        String cid = tuple2.get_1();
        log.info("开门: {} {}", sn, cid);
        Mqtt.publish(cid + "/1/barrier", MapUtil.builder()
                .put("deviceNo", sn)
                .build());
    }

    /**
     * 新增
     *
     * @param deviceInfoEntity 数据
     */
    public void add(DeviceInfoEntity deviceInfoEntity) {
        Map<String, Object> config = deviceInfoEntity.getConfig();
        if (MapUtil.isEmpty(config)) {
            deviceInfoEntity.setConfig(MapUtil.empty());
        }
        this.save(deviceInfoEntity);
    }

    /**
     * 修改
     *
     * @param deviceInfoEntity 数据
     */
    public void modify(DeviceInfoEntity deviceInfoEntity) {
        this.updateById(deviceInfoEntity);
    }

    /**
     * 删除
     *
     * @param ids Ids
     */
    @Transactional(rollbackFor = Exception.class)
    public void del(List<Long> ids) {
        this.removeBatchByIds(ids);
    }

    /**
     * 详情
     *
     * @param id Id
     * @return DeviceInfoEntity 结果
     */
    public DeviceInfoEntity detail(Long id) {
        return this.getById(id);
    }

    /* public void recognition(DeviceRecognitionParam deviceRecognitionParam) {
        String sn = deviceRecognitionParam.getSn();
        DeviceInfoEntity deviceInfoEntity = this.getOne(Wrappers.<DeviceInfoEntity>lambdaQuery().eq(DeviceInfoEntity::getSn, sn));
        if (deviceInfoEntity == null) {
            log.error("设备不存在：{}", deviceRecognitionParam);
            return;
        }

        DeviceCode deviceCode = deviceInfoEntity.getDeviceCode();

        switch (deviceCode) {
            // TODO 进前置不启用
            case JinQianZhi: {
                OrderPagingResult orderInfoByLicensePlate = orderInfoService.pendingOrder(deviceRecognitionParam.getLicensePlate());
                if (orderInfoByLicensePlate == null) {
                    // 播语音
                    return;
                }
                // 播语音
                // 开门
                // orderInfoService.updateById(new OrderInfoEntity().setId(orderInfoByLicensePlate.getId()).setOrderStatus(OrderStatus.DaiJinChang));
            }
            break;
            case Jin: {
                OrderPagingResult orderInfoByLicensePlate = orderInfoService.pendingOrder(deviceRecognitionParam.getLicensePlate());
                if (orderInfoByLicensePlate == null) {
                    // 播语音
                    return;
                }
                // 播语音
                // 获取磅重
                // 播语音
                // 拍照
                Integer weight = null;
                String frontPhoto = null;
                String bodyPhoto = null;
                orderInfoService.truckComing(new TruckComingOrderParam()
                                .setOrderId(orderInfoByLicensePlate.getId())
                                .setWeight(weight)
                                .setFrontPhoto(frontPhoto)
                                .setBodyPhoto(bodyPhoto),
                        0);
            }
            break;
            // TODO 出前置不启用
            case ChuQianZhi: {
                OrderPagingResult orderInfoByLicensePlate = orderInfoService.pendingOrder(deviceRecognitionParam.getLicensePlate());
                if (orderInfoByLicensePlate == null) {
                    // 播语音
                    return;
                }
                CheckStatus checkStatus = orderInfoByLicensePlate.getCheckStatus();
                if (checkStatus == CheckStatus.WeiKanLiao) {
                    // 播语音
                    return;
                }
            }
            break;
            case Chu: {
                OrderPagingResult orderInfoByLicensePlate = orderInfoService.pendingOrder(deviceRecognitionParam.getLicensePlate());
                if (orderInfoByLicensePlate == null) {
                    // 播语音
                    return;
                }
                // 播语音
                // 获取磅重
                // 播语音
                // 拍照
                Integer weight = null;
                String frontPhoto = null;
                String bodyPhoto = null;
                orderInfoService.truckLeaving(new TruckLeavingOrderParam()
                                .setOrderId(orderInfoByLicensePlate.getId())
                                .setWeight(weight)
                                .setFrontPhoto(frontPhoto)
                                .setBodyPhoto(bodyPhoto),
                        0);
            }
            break;
            default:
                break;
        }


    } */

    /**
     * 分页查询
     *
     * @param deviceInfoEntity 筛选条件
     * @param pageParam        分页参数
     * @return PageResult&lt;DeviceInfoEntity&gt; 分页结果
     */

    public PageResult<DeviceInfoEntity> paging(PageParam pageParam, DeviceInfoEntity deviceInfoEntity) {
        return PageResult.of(this.page(pageParam.toPage(), Wrappers.<DeviceInfoEntity>query(deviceInfoEntity)));
    }

    private void open(String sn, String cid) {
        log.info("开门: {} {}", sn, cid);
        Mqtt.publish(cid + "/1/barrier", MapUtil.builder()
                .put("deviceNo", sn)
                .build());
    }



    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> report1(JSONObject data) {
        MapBuilder<String, Object> resBuilder = MapUtil.<String, Object>builder()
                .put("code", 0)
                .put("msg", "success");
        MapBuilder<String, Object> dataBuilder = MapUtil.<String, Object>builder()
                .put("order_no", "")
                .put("type", 0);
        try {
            String sn = data.getString("carDiscernCode");
            String licensePlate = data.getString("carNumber");
            DeviceInfoEntity deviceInfoEntity = this.getOne(Wrappers.<DeviceInfoEntity>lambdaQuery().eq(DeviceInfoEntity::getSn, sn));
            if (deviceInfoEntity == null) {
                log.error("设备不存在：{}", data);
                return resBuilder
                        .put("data", dataBuilder.put("type", 0).build())
                        .build();
            }
            String cid = deviceInfoEntity.getCid();
            OrderPagingResult orderPagingResult = orderInfoService.pendingOrder(licensePlate);
            if (orderPagingResult == null) {
                // 播语音
                playVoice(sn, cid, "{}无订单", licensePlate);
                return resBuilder
                        .put("data", dataBuilder.put("type", 0).build())
                        .build();
            }
            Long deviceStationId = deviceInfoEntity.getStationId();
            Long orderStationId = orderPagingResult.getStationId();
            if (!Objects.equals(deviceStationId, orderStationId)) {
                // 播语音
                playVoice(sn, cid, "{}站点错误，请前往预约的站点", licensePlate);
                return resBuilder
                        .put("data", dataBuilder.put("type", 0).build())
                        .build();
            }

            DeviceCode deviceCode = deviceInfoEntity.getDeviceCode();
            OrderStatus orderStatus = orderPagingResult.getOrderStatus();
            CheckStatus checkStatus = orderPagingResult.getCheckStatus();

            if (deviceCode == DeviceCode.JinQianZhi && orderStatus == OrderStatus.QingYunZhong) {
                PaymentStatus paymentStatus = orderPagingResult.getPaymentStatus();
                /* if (paymentStatus == null) {
                    OrderInfoEntity orderInfoEntity = orderInfoService.getById(orderPagingResult.getId());
                    orderInfoService.settleForTransCompany(orderInfoEntity, 0);
                    orderPagingResult = orderInfoService.detail(orderPagingResult.getId());
                    paymentStatus = orderPagingResult.getPaymentStatus();
                } */
                if (paymentStatus == PaymentStatus.WeiZhiFu) {
                    // 播语音
                    playVoice(sn, cid, "{}请先支付", licensePlate);
                    return resBuilder
                            .put("data", dataBuilder.put("type", 0).build())
                            .build();
                }

                // 开门
                open(sn, cid);
                return resBuilder
                        .put("data", dataBuilder.put("type", 0).build())
                        .build();
            }

            if (deviceCode == DeviceCode.Jin && orderStatus == OrderStatus.QingYunZhong) {
                return resBuilder
                        .put("data", dataBuilder.put("type", 1)
                                .put("order_no", orderPagingResult.getId() + "")
                                .build())
                        .build();
            }

            if (deviceCode == DeviceCode.JinQianZhi && orderStatus == OrderStatus.YiJinChang) {
                if (checkStatus == CheckStatus.WeiKanLiao) {
                    // 播语音
                    playVoice(sn, cid, "{}未看料", licensePlate);

                    return resBuilder
                            .put("data", dataBuilder.put("type", 0).build())
                            .build();
                }

                // 开门
                open(sn, cid);
                return resBuilder
                        .put("data", dataBuilder.put("type", 0).build())
                        .build();
            }

            if (deviceCode == DeviceCode.ChuQianZhi && checkStatus == CheckStatus.WeiKanLiao) {
                // 播语音
                playVoice(sn, cid, "{}未看料", licensePlate);

                return resBuilder
                        .put("data", dataBuilder.put("type", 0).build())
                        .build();
            }

            if (deviceCode == DeviceCode.ChuQianZhi && orderStatus == OrderStatus.YiJinChang) {
                // 开门
                open(sn, cid);
                return resBuilder
                        .put("data", dataBuilder.put("type", 0).build())
                        .build();
            }

            if (deviceCode == DeviceCode.Jin && orderStatus == OrderStatus.YiJinChang) {
                return resBuilder
                        .put("data", dataBuilder.put("type", 2)
                                .put("order_no", orderPagingResult.getId() + "")
                                .build())
                        .build();
            }

            if (deviceCode == DeviceCode.Chu && orderStatus == OrderStatus.YiJinChang) {
                return resBuilder
                        .put("data", dataBuilder.put("type", 2)
                                .put("order_no", orderPagingResult.getId() + "")
                                .build())
                        .build();
            }
        } catch (Exception e) {
            log.error("上报数据处理异常: {}", data, e);
        }

        return resBuilder
                .put("data", dataBuilder.put("type", 0).build())
                .build();
    }

    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> report2(JSONObject data) {
        MapBuilder<String, Object> resBuilder = MapUtil.<String, Object>builder()
                .put("code", 0)
                .put("msg", "success");
        MapBuilder<String, Object> dataBuilder = MapUtil.<String, Object>builder()
                .put("car_number", "")
                .put("order_no", "")
                .put("lane_code", "");
        try {
            String sn = data.getString("carDiscernCode");
            String licensePlate = data.getString("carNumber");
            Long orderId = data.getLong("orderNo");
            DeviceInfoEntity deviceInfoEntity = this.getOne(Wrappers.<DeviceInfoEntity>lambdaQuery().eq(DeviceInfoEntity::getSn, sn));
            if (deviceInfoEntity == null) {
                log.error("设备不存在：{}", data);
                return resBuilder
                        .put("data", dataBuilder.build())
                        .build();
            }
            String cid = deviceInfoEntity.getCid();
            OrderPagingResult orderPagingResult = orderInfoService.detail(orderId);

            if (orderPagingResult == null) {
                // 播语音
                playVoice(sn, cid, "{}无订单", licensePlate);
                return resBuilder
                        .put("data", dataBuilder.build())
                        .build();
            }
            Long deviceStationId = deviceInfoEntity.getStationId();
            Long orderStationId = orderPagingResult.getStationId();
            if (!Objects.equals(deviceStationId, orderStationId)) {
                // 播语音
                playVoice(sn, cid, "{}站点错误，请前往预约的站点", licensePlate);
                return resBuilder
                        .put("data", dataBuilder.build())
                        .build();
            }
            DeviceCode deviceCode = deviceInfoEntity.getDeviceCode();
            OrderInfoEntity orderInfo = orderInfoService.getById(orderId);
            if (orderInfo == null) {
                // 播语音
                playVoice(sn, cid, "{}无订单", orderId);
                return resBuilder
                        .put("data", dataBuilder.build())
                        .build();
            }
            Integer weight = data.getInteger("weight");
            String frontPhoto = data.getString("photoFront");
            String bodyPhoto = data.getString("photoBody");
            if (weight == null || weight == 0) {
                // 播语音
                playVoice(sn, cid, "{}磅重异常，请重新称重", licensePlate);
                return resBuilder
                        .put("data", dataBuilder.build())
                        .build();
            }
            if (deviceCode == DeviceCode.Jin) {
                // 播语音
                BigDecimal weight_ = new BigDecimal(weight);
                BigDecimal v = weight_.divide(new BigDecimal(1000), 2, RoundingMode.HALF_UP);
                OrderStatus orderStatus = orderInfo.getOrderStatus();

                if (orderStatus == OrderStatus.YiJinChang) {
                    Long carInOutId = orderInfo.getCarInOutId();
                    String orderInfoSn = orderInfo.getSn();
                    if (carInOutId == null) {
                        log.warn("订单{}不存在关联的车辆进场记录", orderInfoSn);
                        return resBuilder
                                .put("data", dataBuilder.build())
                                .build();
                    }
                    OrderCarInOutEntity orderCarInOutEntity = orderCarInOutService.getById(carInOutId);
                    if (orderCarInOutEntity == null) {
                        log.warn("订单{}不存在关联的车辆进场记录", orderInfoSn);
                        return resBuilder
                                .put("data", dataBuilder.build())
                                .build();
                    }
                    LocalDateTime inTime = orderCarInOutEntity.getInTime();

                    long interval = Duration.between(inTime, LocalDateTime.now()).toMillis() / 1000;
                    int inOutGap = appProperties.getInOutGap();
                    if (inOutGap <= 0) {
                        inOutGap = 60;
                    }
                    if (interval <= inOutGap) {
                        log.warn("车辆进场时间间隔不能小于{}秒，订单{}", inOutGap, orderInfoSn);
                        playVoice(sn, cid, "{}重复识别，请稍后再试", licensePlate);
                        return resBuilder
                                .put("data", dataBuilder.build())
                                .build();
                    }
                    log.info("进道闸转出道闸，订单号：{}", orderInfoSn);
                    if (orderInfo.getCheckStatus() == CheckStatus.WeiKanLiao) {
                        // 播语音
                        playVoice(sn, cid, "{}未看料", licensePlate);
                        return resBuilder
                                .put("data", dataBuilder.build())
                                .build();
                    }
                    boolean b = orderInfoService.truckLeaving(new TruckLeavingOrderParam()
                                    .setOrderId(orderId)
                                    .setWeight(weight)
                                    .setFrontPhoto(frontPhoto)
                                    .setBodyPhoto(bodyPhoto),
                            0);
                    // 播语音
                    playVoice(sn, cid, "{}称重完成，磅重{}吨", licensePlate, v.toPlainString());
                    if (b) {
                        // 开门
                        open(sn, cid);
                    } else {
                        waitOpen.put(orderPagingResult.getSn(), Tuple2.create(sn, cid));
                    }
                    return resBuilder
                            .put("data", dataBuilder.build())
                            .build();
                }
                // 开门
                orderInfoService.truckComing(new TruckComingOrderParam()
                                .setOrderId(orderId)
                                .setWeight(weight)
                                .setFrontPhoto(frontPhoto)
                                .setBodyPhoto(bodyPhoto),
                        0);
                playVoice(sn, cid, "{}称重完成，磅重{}吨", licensePlate, v.toPlainString());
                open(sn, cid);
            }

            if (deviceCode == DeviceCode.Chu) {
                BigDecimal weight_ = new BigDecimal(weight);
                BigDecimal v = weight_.divide(new BigDecimal(1000), 2, RoundingMode.HALF_UP);
                try {
                    String settlementWay = orderPagingResult.getSettlementWay();
                    if (SettlementWay.CASH.getTxt().equals(settlementWay)) {
                        playVoice(sn, cid, "{}请先支付", licensePlate);
                    }
                    if (orderInfo.getCheckStatus() == CheckStatus.WeiKanLiao) {
                        // 播语音
                        playVoice(sn, cid, "{}未看料", licensePlate);
                    }
                    boolean b = orderInfoService.truckLeaving(new TruckLeavingOrderParam()
                                    .setOrderId(orderId)
                                    .setWeight(weight)
                                    .setFrontPhoto(frontPhoto)
                                    .setBodyPhoto(bodyPhoto),
                            0);
                    // 播语音
                    playVoice(sn, cid, "{}称重完成，磅重{}吨", licensePlate, v.toPlainString());
                    if (b) {
                        // 开门
                        open(sn, cid);
                    } else {
                        waitOpen.put(orderPagingResult.getSn(), Tuple2.create(sn, cid));
                    }
                } catch (Exception e) {
                    playVoice(sn, cid, "{}称重异常，磅重{}吨", licensePlate, v.toPlainString());
                }
            }
        } catch (Exception e) {
            log.error("上报数据处理异常: {}", data, e);
        }

        return resBuilder
                .put("data", dataBuilder.build())
                .build();
    }


    private void playVoice(String sn, String cid, String content, Object... params) {
        String format = StrUtil.format(content, params);
        log.info("播语音: {} {} {}", sn, cid, format);
        Mqtt.publish(cid + "/1/voice", MapUtil.builder()
                .put("deviceNo", sn)
                .put("text", format)
                .build());
    }
}
