package com.gxwebsoft.hjm.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.support.geo.Point;
import com.gxwebsoft.common.core.utils.JSONUtil;
import com.gxwebsoft.common.core.utils.RedisUtil;
import com.gxwebsoft.hjm.entity.Gps;
import com.gxwebsoft.hjm.entity.HjmCar;
import com.gxwebsoft.hjm.entity.HjmFence;
import com.gxwebsoft.hjm.entity.HjmGpsLog;
import com.gxwebsoft.hjm.service.impl.HjmCarServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.concurrent.TimeUnit;

/**
 * GPS消息处理器
 *
 * @author 科技小王子
 * @since 2025-07-02
 */
@Service
public class GpsMessageProcessor {

    private static final Logger logger = LoggerFactory.getLogger(GpsMessageProcessor.class);

    @Resource
    private HjmCarService hjmCarService;

    @Resource
    private HjmGpsLogService hjmGpsLogService;

    @Resource
    private HjmFenceService hjmFenceService;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private HjmCarServiceImpl hjmCarServiceImpl;

    /**
     * 处理GPS消息
     *
     * @param payload 消息内容
     */
    public void processGpsMessage(String payload) {
        try {
            logger.debug("开始处理GPS消息: {}", payload);

            Gps gps = JSONUtil.parseObject(payload, Gps.class);
            if (ObjectUtil.isEmpty(gps)) {
                logger.warn("GPS数据为空，跳过处理");
                return;
            }

            processGpsData(gps);

        } catch (Exception e) {
            logger.error("处理GPS数据失败: {}", payload, e);
        }
    }

    /**
     * 处理GPS数据
     *
     * @param gps GPS数据
     */
    private void processGpsData(Gps gps) {
        try {
            String gpsNo = gps.getImei();
            if (StrUtil.isBlank(gpsNo)) {
                logger.warn("GPS设备编号为空，跳过处理");
                return;
            }

            // 详细记录GPS数据处理过程
            logger.info("处理GPS数据 - 设备编号: {}, Fixed: {}, 经度: {}, 纬度: {}, 速度: {}",
                       gpsNo, gps.getFixed(), gps.getLng(), gps.getLat(), gps.getSpeed());

            HjmCar car = hjmCarService.getByGpsNo(gpsNo);

            if (car == null) {
                logger.warn("GPS设备编号: {} 在数据库中未找到对应车辆，请检查车辆配置", gpsNo);
                return;
            }

            logger.info("GPS设备编号: {} 对应车辆: {} (ID: {})", gpsNo, car.getCode(), car.getId());

            if (!gps.getFixed()) {
                logger.warn("GPS设备编号: {} 定位未固定(Fixed=false)，跳过处理", gpsNo);
                return;
            }

            // 更新车辆GPS定位信息
            updateCarLocation(car, gps);

            // 保存GPS轨迹日志
            saveGpsLog(car, gps);

            // 检查电子围栏
            checkFence(car, gps);

        } catch (Exception e) {
            logger.error("处理GPS数据时发生错误", e);
        }
    }

    /**
     * 更新车辆位置信息
     */
    private void updateCarLocation(HjmCar car, Gps gps) {
        try {
            car.setLongitude(gps.getLng());
            car.setLatitude(gps.getLat());
            car.setSpeed(gps.getSpeed());
            car.setUpdateTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(gps.getTime() * 1000), ZoneId.systemDefault()));
            car.setGpsNo(gps.getImei());

            if (hjmCarService.updateByGpsNo(car)) {
                logger.debug("更新车辆GPS定位信息成功: {}", car.getCode());

                // 检查是否需要保存GPS日志（避免重复保存）
                String keyByGpsNo = redisUtil.get(gps.getImei());
                if (StrUtil.isBlank(keyByGpsNo)) {
                    saveGpsLogRecord(car, gps);
                }
            } else {
                logger.warn("更新车辆GPS定位信息失败: {}", car.getCode());
            }

        } catch (Exception e) {
            logger.error("更新车辆位置信息失败", e);
        }
    }

    /**
     * 保存GPS轨迹日志记录
     */
    private void saveGpsLogRecord(HjmCar car, Gps gps) {
        try {
            HjmGpsLog log = new HjmGpsLog();
            log.setTenantId(10519);
            log.setCarId(car.getId());
            log.setGpsNo(gps.getImei());
            log.setLatitude(gps.getLat());
            log.setLongitude(gps.getLng());
            log.setDdmmyy(gps.getDdmmyy());
            log.setHhmmss(gps.getHhmmss());
            log.setSpeed(gps.getSpeed());

            if (!log.getSpeed().equals("0.000")) {
              hjmGpsLogService.save(log);
              logger.debug("保存GPS轨迹日志成功: {}", gps.getImei());
            }

        } catch (Exception e) {
            logger.error("保存GPS轨迹日志失败", e);
        }
    }

    /**
     * 保存GPS日志（兼容原有方法）
     */
    private void saveGpsLog(HjmCar car, Gps gps) {
        // 这里可以添加其他GPS日志相关的处理逻辑
        logger.debug("处理GPS日志: 车辆={}, GPS={}", car.getCode(), gps.getImei());
    }

    /**
     * 检查电子围栏
     */
    private void checkFence(HjmCar car, Gps gps) {
        try {
            String gpsNo = gps.getImei();

            // 检查围栏缓存，避免频繁计算
            String inFenceKey = redisUtil.get("inFence:" + gpsNo);
            if (StrUtil.isNotBlank(inFenceKey)) {
                logger.debug("围栏检查缓存命中，跳过计算: {}", gpsNo);
                return;
            }

            // 设置围栏检查缓存（1天）
            redisUtil.set("inFence:" + gpsNo, "1", 1L, TimeUnit.DAYS);

            // 检查是否配置了围栏
            if (car.getFenceId() == null) {
                logger.debug("车辆未配置围栏: {}", car.getCode());
                return;
            }

            HjmFence fence = hjmFenceService.getById(car.getFenceId());
            if (fence == null) {
                logger.warn("围栏不存在: {}", car.getFenceId());
                return;
            }

            // 检查坐标有效性
            if (!isValidCoordinate(car.getLongitude(), car.getLatitude())) {
                logger.warn("车辆坐标无效: 经度={}, 纬度={}", car.getLongitude(), car.getLatitude());
                return;
            }

            // 执行围栏判断
            performFenceCheck(car, fence);

        } catch (Exception e) {
            logger.error("检查电子围栏时发生错误", e);
        }
    }

    /**
     * 检查坐标有效性
     */
    private boolean isValidCoordinate(String longitude, String latitude) {
        return longitude != null && latitude != null &&
               !longitude.trim().isEmpty() && !latitude.trim().isEmpty();
    }

    /**
     * 执行围栏判断
     */
    private void performFenceCheck(HjmCar car, HjmFence fence) {
        try {
            double lng = Double.parseDouble(car.getLongitude());
            double lat = Double.parseDouble(car.getLatitude());

            Point carPoint = new Point();
            carPoint.setLongitude(lng);
            carPoint.setLatitude(lat);

            // 使用多边形围栏判断
            boolean isInFence = hjmCarServiceImpl.checkPolygonFence(carPoint, fence);

            // 更新围栏状态
            car.setInFence(isInFence);
            car.setUpdateTime(LocalDateTime.now());
            hjmCarService.updateById(car);

            logger.info("车辆围栏检查完成: 车辆={}, 围栏={}, 是否在围栏内={}",
                       car.getCode(), fence.getId(), isInFence);

        } catch (NumberFormatException e) {
            logger.error("车辆坐标格式错误: 经度={}, 纬度={}", car.getLongitude(), car.getLatitude(), e);
        } catch (Exception e) {
            logger.error("执行围栏判断时发生错误", e);
        }
    }
}
