package com.gxwebsoft.hjm.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.support.geo.Point;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.hjm.entity.HjmFence;
import com.gxwebsoft.hjm.mapper.HjmCarMapper;
import com.gxwebsoft.hjm.service.HjmCarService;
import com.gxwebsoft.hjm.entity.HjmCar;
import com.gxwebsoft.hjm.param.HjmCarParam;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.hjm.service.HjmFenceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 黄家明_车辆管理Service实现
 *
 * @author 科技小王子
 * @since 2025-04-14 16:43:26
 */
@Service
public class HjmCarServiceImpl extends ServiceImpl<HjmCarMapper, HjmCar> implements HjmCarService {
  @Resource
  private HjmFenceService hjmFenceService;
  @Autowired
  private HjmCarService hjmCarService;


  @Override
  public PageResult<HjmCar> pageRel(HjmCarParam param) {
    PageParam<HjmCar, HjmCarParam> page = new PageParam<>(param);
    page.setDefaultOrder("sort_number asc, create_time desc");
    List<HjmCar> list = baseMapper.selectPageRel(page, param);
    return new PageResult<>(list, page.getTotal());
  }

  @Override
  public List<HjmCar> listRel(HjmCarParam param) {
    List<HjmCar> list = baseMapper.selectListRel(param);
    // 排序
    PageParam<HjmCar, HjmCarParam> page = new PageParam<>();
    page.setDefaultOrder("sort_number asc, create_time desc");
    return page.sortRecords(list);
  }

  @Override
  public HjmCar getByIdRel(Integer id) {
    HjmCarParam param = new HjmCarParam();
    param.setId(id);
    final HjmCar hjmCar = param.getOne(baseMapper.selectListRel(param));
    hjmCar.setFence(hjmFenceService.getById(hjmCar.getFenceId()));
    return hjmCar;
  }

  @Override
  public HjmCar getByGpsNo(String gpsNo) {
    return baseMapper.getByGpsNo(gpsNo);
  }

  @Override
  public boolean updateByGpsNo(HjmCar byGpsNo) {
    return baseMapper.updateByGpsNo(byGpsNo);
  }

  @Override
  public HjmCar getByCode(String code) {
    final HjmCar byCode = baseMapper.getByCode(code);

    // 检查车辆是否存在
    if (byCode == null) {
      return null;
    }

    // 检查是否有围栏ID
    if (byCode.getFenceId() == null) {
      return byCode;
    }

    final HjmFence fence = hjmFenceService.getById(byCode.getFenceId());
    byCode.setFence(fence);

    // 检查围栏是否存在
    if (fence == null) {
      return byCode;
    }

    // 检查车辆坐标是否有效
    if (byCode.getLongitude() == null || byCode.getLatitude() == null ||
        byCode.getLongitude().trim().isEmpty() || byCode.getLatitude().trim().isEmpty()) {
      return byCode;
    }

    try {
      // 字符串转为浮点
      final double lng = Double.parseDouble(byCode.getLongitude());
      final double lat = Double.parseDouble(byCode.getLatitude());
      Point carPoint = new Point();
      carPoint.setLongitude(lng);
      carPoint.setLatitude(lat);

      boolean isInFence = false;

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

      // 将围栏判断结果保存到车辆对象中
      byCode.setInFence(isInFence);
      System.out.println("车辆 " + code + " 是否在围栏内: " + isInFence);
      byCode.setUpdateTime(LocalDateTime.now());
      hjmCarService.updateById(byCode);
      return byCode;

    } catch (NumberFormatException e) {
      System.err.println("车辆坐标格式错误: " + e.getMessage());
      return byCode;
    } catch (Exception e) {
      System.err.println("判断围栏时发生错误: " + e.getMessage());
      e.printStackTrace();
      return byCode;
    }
  }



  /**
   * 判断点是否在多边形内
   * @param point 测试点
   * @param pts   多边形的点
   * @return boolean true:在多边形内, false:在多边形外
   * @throws
   * @Title: IsPointInPoly
   */
  public static boolean isInPolygon(Point point, List<Point> pts) {

    int N = pts.size();
    boolean boundOrVertex = true;
    //交叉点数量
    int intersectCount = 0;
    //浮点类型计算时候与0比较时候的容差
    double precision = 2e-10;
    //临近顶点
    Point p1, p2;
    //当前点
    Point p = point;

    p1 = pts.get(0);
    for (int i = 1; i <= N; ++i) {
      if (p.equals(p1)) {
        return boundOrVertex;
      }

      p2 = pts.get(i % N);
      if (p.getLongitude() < Math.min(p1.getLongitude(), p2.getLongitude()) || p.getLongitude() > Math.max(p1.getLongitude(), p2.getLongitude())) {
        p1 = p2;
        continue;
      }

      //射线穿过算法
      if (p.getLongitude() > Math.min(p1.getLongitude(), p2.getLongitude()) && p.getLongitude() < Math.max(p1.getLongitude(), p2.getLongitude())) {
        if (p.getLatitude() <= Math.max(p1.getLatitude(), p2.getLatitude())) {
          if (p1.getLongitude() == p2.getLongitude() && p.getLatitude() >= Math.min(p1.getLatitude(), p2.getLatitude())) {
            return boundOrVertex;
          }

          if (p1.getLatitude() == p2.getLatitude()) {
            if (p1.getLatitude() == p.getLatitude()) {
              return boundOrVertex;
            } else {
              ++intersectCount;
            }
          } else {
            double xinters = (p.getLongitude() - p1.getLongitude()) * (p2.getLatitude() - p1.getLatitude()) / (p2.getLongitude() - p1.getLongitude()) + p1.getLatitude();
            if (Math.abs(p.getLatitude() - xinters) < precision) {
              return boundOrVertex;
            }

            if (p.getLatitude() < xinters) {
              ++intersectCount;
            }
          }
        }
      } else {
        if (p.getLongitude() == p2.getLongitude() && p.getLatitude() <= p2.getLatitude()) {
          Point p3 = pts.get((i + 1) % N);
          if (p.getLongitude() >= Math.min(p1.getLongitude(), p3.getLongitude()) && p.getLongitude() <= Math.max(p1.getLongitude(), p3.getLongitude())) {
            ++intersectCount;
          } else {
            intersectCount += 2;
          }
        }
      }
      p1 = p2;
    }
    return intersectCount % 2 != 0;
  }



  /**
   * 检查点是否在多边形围栏内
   * @param carPoint 车辆位置点
   * @param fence 围栏信息
   * @return boolean true:在围栏内, false:在围栏外
   */
  public boolean checkPolygonFence(Point carPoint, HjmFence fence) {
    if (fence.getPoints() == null || fence.getPoints().trim().isEmpty()) {
      System.err.println("多边形围栏点数据为空");
      return false;
    }

    try {
      final String points = fence.getPoints();

      // 支持多种分隔符格式：逗号、分号、空格等
      String[] coordinates = parseCoordinates(points);

      // 检查点数据是否为偶数（经度,纬度 成对出现）
      if (coordinates.length % 2 != 0) {
        System.err.println("多边形围栏点数据格式错误，应为偶数个数值。当前数据: " + points);
        return false;
      }

      List<Point> pts = new ArrayList<>();
      for (int i = 0; i < coordinates.length; i += 2) {
        try {
          Point point = new Point();
          double lng = Double.parseDouble(coordinates[i].trim());
          double lat = Double.parseDouble(coordinates[i + 1].trim());

          // 验证坐标范围
          if (lng < -180 || lng > 180) {
            System.err.println("经度超出有效范围[-180,180]: " + lng);
            return false;
          }
          if (lat < -90 || lat > 90) {
            System.err.println("纬度超出有效范围[-90,90]: " + lat);
            return false;
          }

          point.setLongitude(lng);
          point.setLatitude(lat);
          pts.add(point);

          System.out.println("解析坐标点 " + (i/2 + 1) + ": (" + lng + ", " + lat + ")");

        } catch (NumberFormatException e) {
          System.err.println("坐标解析失败，位置 " + (i/2 + 1) + ": [" + coordinates[i] + ", " + coordinates[i + 1] + "]");
          throw e;
        }
      }

      // 至少需要3个点才能构成多边形
      if (pts.size() < 3) {
        System.err.println("多边形围栏至少需要3个点");
        return false;
      }

      return isInPolygon(carPoint, pts);

    } catch (NumberFormatException e) {
      System.err.println("多边形围栏点坐标格式错误: " + e.getMessage());
      return false;
    } catch (Exception e) {
      System.err.println("检查多边形围栏时发生错误: " + e.getMessage());
      e.printStackTrace();
      return false;
    }
  }

  /**
   * 解析坐标字符串，支持多种分隔符格式
   * @param coordinatesStr 坐标字符串
   * @return 坐标数组
   */
  private String[] parseCoordinates(String coordinatesStr) {
    if (coordinatesStr == null || coordinatesStr.trim().isEmpty()) {
      return new String[0];
    }

    // 移除首尾空格
    String cleanStr = coordinatesStr.trim();
    System.out.println("原始坐标数据: " + cleanStr);

    // 检查是否是混合分隔符格式：纬度,经度;纬度,经度;...
    if (cleanStr.contains(";") && cleanStr.contains(",")) {
      System.out.println("检测到混合分隔符格式（分号分隔点，逗号分隔经纬度）");
      return parseMixedFormat(cleanStr);
    }

    // 支持的单一分隔符格式
    String[] coordinates;

    if (cleanStr.contains(";")) {
      // 使用分号分隔
      coordinates = cleanStr.split(";");
      System.out.println("使用分号分隔符解析坐标");
    } else if (cleanStr.contains(",")) {
      // 使用逗号分隔
      coordinates = cleanStr.split(",");
      System.out.println("使用逗号分隔符解析坐标");
    } else {
      // 使用空格或制表符分隔
      coordinates = cleanStr.split("\\s+");
      System.out.println("使用空格分隔符解析坐标");
    }

    // 清理每个坐标值的空格
    for (int i = 0; i < coordinates.length; i++) {
      coordinates[i] = coordinates[i].trim();
    }

    return coordinates;
  }

  /**
   * 解析混合分隔符格式：纬度,经度;纬度,经度;...
   * @param coordinatesStr 坐标字符串
   * @return 坐标数组（按经度,纬度顺序）
   */
  private String[] parseMixedFormat(String coordinatesStr) {
    // 先按分号分隔得到各个坐标点
    String[] points = coordinatesStr.split(";");
    System.out.println("分解出 " + points.length + " 个坐标点");

    // 创建结果数组，每个点有2个坐标值
    String[] coordinates = new String[points.length * 2];

    for (int i = 0; i < points.length; i++) {
      String point = points[i].trim();
      String[] latLng = point.split(",");

      if (latLng.length != 2) {
        throw new IllegalArgumentException("坐标点格式错误: " + point + "，应为 '纬度,经度' 格式");
      }

      String lat = latLng[0].trim();
      String lng = latLng[1].trim();

      // 注意：输入格式是纬度,经度，但我们需要按经度,纬度的顺序存储
      coordinates[i * 2] = lng;     // 经度
      coordinates[i * 2 + 1] = lat; // 纬度

      System.out.println("坐标点 " + (i + 1) + ": 纬度=" + lat + ", 经度=" + lng + " -> 存储为 (" + lng + ", " + lat + ")");
    }

    return coordinates;
  }

  /**
   * 通用的围栏判断方法（只支持多边形围栏）
   * @param carPoint 车辆位置点
   * @param fence 围栏信息
   * @return boolean true:在围栏内, false:在围栏外
   */
  public boolean isPointInFence(Point carPoint, HjmFence fence) {
    if (carPoint == null || fence == null) {
      return false;
    }

    // 只使用多边形围栏判断
    return checkPolygonFence(carPoint, fence);
  }

  /**
   * 测试坐标解析功能
   * @param coordinatesStr 坐标字符串
   */
  public void testCoordinateParsing(String coordinatesStr) {
    System.out.println("=== 测试坐标解析 ===");
    System.out.println("输入: " + coordinatesStr);

    try {
      String[] coordinates = parseCoordinates(coordinatesStr);
      System.out.println("解析结果: " + java.util.Arrays.toString(coordinates));
      System.out.println("坐标点数量: " + coordinates.length / 2);

      if (coordinates.length % 2 == 0 && coordinates.length >= 6) {
        System.out.println("格式验证: ✓ 通过");
        for (int i = 0; i < coordinates.length; i += 2) {
          double lng = Double.parseDouble(coordinates[i].trim());
          double lat = Double.parseDouble(coordinates[i + 1].trim());
          System.out.println("最终坐标点 " + (i/2 + 1) + ": 经度=" + lng + ", 纬度=" + lat);
        }
      } else {
        System.out.println("格式验证: ✗ 失败 - 需要至少3个点（6个数值），当前有 " + coordinates.length + " 个数值");
      }
    } catch (Exception e) {
      System.err.println("解析失败: " + e.getMessage());
      e.printStackTrace();
    }
    System.out.println("==================");
  }



}
