import amapFile from '../libs/amap-wx.130.js';
import { _AMAP_KEY, _ROBOTAXI_HOST, _UID } from '../constants/api';
import Taro from '@tarojs/taro';
import request from './request';
import { getFenceCheck, getNearestSite } from '../robotaxi/api/home';
import { getOpenCity } from '../robotaxi/api/select-city';
import { getStorage, getOrCreateLocalId } from './tools';
import {
  GEOFENCE_STATION_FILL_COLOR,
  GEOFENCE_STATION_STROKE_COLOR,
  GEOFENCE_TYPE_OPERATING,
  GEOFENCE_TYPE_STATION
} from '../robotaxi/constants/geofence';
import { APPID } from '../constants/app'
import {
  MODIFY_DESTINATION_SESSION_KEY,
  MODIFY_DESTINATION_CANDIDATE_KEY,
  MODIFY_DESTINATION_OVERRIDE_KEY,
  MODIFY_DESTINATION_ROUTE_POINTS_KEY,
  MODIFY_DESTINATION_SKIP_AC_QUERY_ON_RETURN_KEY,
  MODIFY_DESTINATION_SOCKET_STATUS_KEY,
  MODIFY_DESTINATION_PENDING_SAME_SITE_TOAST_KEY
} from '../robotaxi/constants/modify-destination';

/**
 * 安全的 JSON 解析函数
 * @param str 需要解析的字符串
 * @param defaultVal 解析失败时的默认返回值
 */
export const safeParse = (str: any, defaultVal: any = null) => {
  if (typeof str !== 'string') {
    return str || defaultVal;
  }

  const trimmed = str.trim();
  // 简单的格式预判：JSON 对象或数组字符串通常以 { 或 [ 开头
  // 如果不是这两种开头，大概率不是我们需要解析的 JSON，直接返回原值或默认值，避免引发 JSON.parse 的异常和错误日志
  if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) {
    return str || defaultVal;
  }

  try {
    return JSON.parse(trimmed);
  } catch (e) {
    console.error('safeParse error:', e, 'original string:', str);
    return defaultVal;
  }
};

/**
 * 安全拨打电话：号码为空时给出提示，避免传空字符串触发系统拨号异常。
 * @param phoneNumber 待拨打的号码
 * @param emptyTip 号码缺失时的提示文案
 */
export const safeMakePhoneCall = (phoneNumber?: string, emptyTip = '暂无客服电话') => {
  const cachedPhoneNumber = Taro.getStorageSync('customerServicePhone');
  const normalizedPhoneNumber = String(phoneNumber || cachedPhoneNumber || '').trim();
  if (!normalizedPhoneNumber) {
    Taro.showToast({
      title: emptyTip,
      icon: 'none'
    });
    return Promise.resolve(false);
  }
  return Taro.makePhoneCall({
    phoneNumber: normalizedPhoneNumber
  })
    .then(() => true)
    .catch(() => false);
};

/**
 * 安全解析 `"longitude,latitude"` 格式的坐标字符串，格式非法时返回 `null`。
 * @param location 坐标字符串
 */
export const parseLocationCoordinateString = (location?: string) => {
  const locationParts = String(location || '').split(',');
  if (locationParts.length < 2) {
    return null;
  }
  const longitude = Number(locationParts[0]);
  const latitude = Number(locationParts[1]);
  if (!Number.isFinite(longitude) || !Number.isFinite(latitude)) {
    return null;
  }
  return {
    longitude,
    latitude
  };
};

// 辅助函数：计算两点之间的距离（单位：米）
export const getDistance = (lat1: number, lng1: number, lat2: number, lng2: number) => {
  const radLat1 = lat1 * Math.PI / 180.0;
  const radLat2 = lat2 * Math.PI / 180.0;
  const a = radLat1 - radLat2;
  const b = lng1 * Math.PI / 180.0 - lng2 * Math.PI / 180.0;
  let s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
  s = s * 6378.137; // 地球半径
  s = Math.round(s * 10000) / 10000;
  return s * 1000;
};

/**
 * 统一标准化围栏点位，兼容 `{ lat, lng }` 和 `{ latitude, longitude }` 两种结构。
 */
const normalizePolygonPoints = (points: any[] = []) => {
  return points
    .map((point) => ({
      latitude: Number(point?.latitude ?? point?.lat),
      longitude: Number(point?.longitude ?? point?.lng)
    }))
    .filter((point) => Number.isFinite(point.latitude) && Number.isFinite(point.longitude));
};

/**
 * 将经纬度投影到近似平面，便于计算点到边的距离。
 */
const projectPoint = (point: { latitude: number; longitude: number }, referenceLatitude: number) => {
  const metersPerDegreeLat = 111320;
  const metersPerDegreeLng = 111320 * Math.cos(referenceLatitude * Math.PI / 180);
  return {
    x: point.longitude * metersPerDegreeLng,
    y: point.latitude * metersPerDegreeLat
  };
};

/**
 * 计算点到线段的最短距离，单位为米。
 */
export const getDistanceToSegment = (
  point: { latitude: number; longitude: number },
  start: { latitude: number; longitude: number },
  end: { latitude: number; longitude: number }
) => {
  const referenceLatitude = (point.latitude + start.latitude + end.latitude) / 3;
  const pointXY = projectPoint(point, referenceLatitude);
  const startXY = projectPoint(start, referenceLatitude);
  const endXY = projectPoint(end, referenceLatitude);
  const dx = endXY.x - startXY.x;
  const dy = endXY.y - startXY.y;
  const lengthSquared = dx * dx + dy * dy;

  if (lengthSquared === 0) {
    return Math.sqrt((pointXY.x - startXY.x) * (pointXY.x - startXY.x) + (pointXY.y - startXY.y) * (pointXY.y - startXY.y));
  }

  let ratio = ((pointXY.x - startXY.x) * dx + (pointXY.y - startXY.y) * dy) / lengthSquared;
  ratio = Math.max(0, Math.min(1, ratio));
  const closestX = startXY.x + ratio * dx;
  const closestY = startXY.y + ratio * dy;

  return Math.sqrt((pointXY.x - closestX) * (pointXY.x - closestX) + (pointXY.y - closestY) * (pointXY.y - closestY));
};

/**
 * 判断点是否命中多边形内部。
 */
export const isPointInPolygon = (
  point: { latitude: number; longitude: number },
  polygonPoints: Array<{ latitude: number; longitude: number }>
) => {
  if (!Array.isArray(polygonPoints) || polygonPoints.length < 3) {
    return false;
  }

  let isInside = false;
  const pointX = point.longitude;
  const pointY = point.latitude;

  for (let index = 0, lastIndex = polygonPoints.length - 1; index < polygonPoints.length; lastIndex = index, index += 1) {
    const currentPoint = polygonPoints[index];
    const previousPoint = polygonPoints[lastIndex];
    const currentX = currentPoint.longitude;
    const currentY = currentPoint.latitude;
    const previousX = previousPoint.longitude;
    const previousY = previousPoint.latitude;

    const isIntersected = ((currentY > pointY) !== (previousY > pointY))
      && (pointX < ((previousX - currentX) * (pointY - currentY)) / ((previousY - currentY) || Number.EPSILON) + currentX);

    if (isIntersected) {
      isInside = !isInside;
    }
  }

  return isInside;
};

/**
 * 查找当前点命中的围栏；未命中时可退化为最近围栏边界。
 */
export const findMatchedPolygon = (
  point: { latitude: number; longitude: number },
  polygonList: any[] = [],
  maxDistance = 180
) => {
  if (!Array.isArray(polygonList) || polygonList.length === 0) {
    return null;
  }

  const insidePolygon = polygonList.find((item) => {
    const polygonPoints = normalizePolygonPoints(item?.polygonPoints || item?.points || []);
    return isPointInPolygon(point, polygonPoints);
  });

  if (insidePolygon) {
    return insidePolygon;
  }

  let nearestPolygon: any = null;
  let nearestDistance = Number.POSITIVE_INFINITY;

  polygonList.forEach((item) => {
    const polygonPoints = normalizePolygonPoints(item?.polygonPoints || item?.points || []);
    if (polygonPoints.length < 2) {
      return;
    }

    let minDistanceToBorder = Number.POSITIVE_INFINITY;
    for (let index = 0; index < polygonPoints.length; index += 1) {
      const start = polygonPoints[index];
      const end = polygonPoints[(index + 1) % polygonPoints.length];
      const distanceToSegment = getDistanceToSegment(point, start, end);
      if (distanceToSegment < minDistanceToBorder) {
        minDistanceToBorder = distanceToSegment;
      }
    }

    const distanceToFirstPoint = getDistance(
      point.latitude,
      point.longitude,
      polygonPoints[0].latitude,
      polygonPoints[0].longitude
    );
    const matchDistance = Math.min(minDistanceToBorder, distanceToFirstPoint);

    if (matchDistance < nearestDistance) {
      nearestDistance = matchDistance;
      nearestPolygon = item;
    }
  });

  return nearestDistance <= maxDistance ? nearestPolygon : null;
};

/**
 * 根据站点空间分布估算推荐缩放等级；如提供中心点，则优先保证从中心点往外至少可见 3 个点位。
 */
export const getAutoScaleBySites = (sites: any[], centerLat?: number, centerLng?: number) => {
  if (!Array.isArray(sites) || sites.length === 0) return null;
  const validSites = sites
    .map((site) => ({
      latitude: Number(site?.latitude),
      longitude: Number(site?.longitude)
    }))
    .filter((site) => Number.isFinite(site.latitude) && Number.isFinite(site.longitude)); // 过滤无效坐标点位
  if (validSites.length === 0) return null;
  if (validSites.length === 1) return 16;

  const resolveScaleByDiagonal = (diagonalMeters: number) => {
    if (diagonalMeters > 12000) return 11;
    if (diagonalMeters > 8000) return 12;
    if (diagonalMeters > 5000) return 13;
    if (diagonalMeters > 3000) return 14;
    if (diagonalMeters > 1500) return 15;
    if (diagonalMeters > 800) return 16;
    return 17;
  }; // 统一距离到缩放等级的映射规则

  const hasValidCenter = Number.isFinite(Number(centerLat)) && Number.isFinite(Number(centerLng)); // 是否提供了有效中心点

  /**
   * 基于中心点计算至少可见 3 个点位所需缩放等级。
   */
  const resolveScaleByCenterVisibleSites = () => {
    if (!hasValidCenter) return null;
    const visibleSiteCount = Math.min(validSites.length, 3); // 最多按最近 3 个点位估算
    if (visibleSiteCount <= 1) return 16;
    const sortedDistances = validSites
      .map((site) => getDistance(Number(centerLat), Number(centerLng), site.latitude, site.longitude))
      .filter((distance) => Number.isFinite(distance))
      .sort((a, b) => a - b);
    const targetRadius = sortedDistances[visibleSiteCount - 1]; // 取第 N 个最近点的半径，保证中心点往外至少覆盖 N 个点
    if (!Number.isFinite(targetRadius)) return null;
    const safeDiagonal = Math.max(targetRadius * 2 * 1.35, 300); // 预留边缘与卡片遮挡余量，避免第 3 个点卡边
    return resolveScaleByDiagonal(safeDiagonal);
  };

  const centerVisibleScale = resolveScaleByCenterVisibleSites(); // 中心点口径下的推荐缩放等级
  if (typeof centerVisibleScale === 'number') {
    return centerVisibleScale;
  }

  /**
   * 计算稀疏场景下“至少可见 3 个点位”所需的最大安全缩放等级。
   */
  const resolveSparseScaleForThreeVisibleSites = () => {
    if (validSites.length < 3) return null;
    const radiusNeedForThreeSites = validSites.reduce((maxRadius, baseSite) => {
      const neighborDistances = validSites
        .filter((site) => site !== baseSite)
        .map((site) => getDistance(baseSite.latitude, baseSite.longitude, site.latitude, site.longitude))
        .sort((a, b) => a - b);
      const radius = neighborDistances[1]; // 取第 2 个邻居距离，保证当前点周围至少覆盖 3 个点
      if (!Number.isFinite(radius)) return maxRadius;
      return Math.max(maxRadius, radius);
    }, 0); // 取所有基点中的最大值，保证任意基点都能满足 3 点可见
    if (radiusNeedForThreeSites <= 0) return null;
    return resolveScaleByDiagonal(radiusNeedForThreeSites * 2);
  };

  /**
   * 计算高密度场景下“精细视角至少可见 3 个点”的推荐缩放等级。
   */
  const resolveDenseScaleForThreeVisibleSites = () => {
    if (validSites.length < 3) return null;
    const denseAnchor = validSites.reduce((bestSite, currentSite) => {
      if (!bestSite) return currentSite;
      const currentNeighborDistances = validSites
        .filter((site) => site !== currentSite)
        .map((site) => getDistance(currentSite.latitude, currentSite.longitude, site.latitude, site.longitude))
        .sort((a, b) => a - b);
      const bestNeighborDistances = validSites
        .filter((site) => site !== bestSite)
        .map((site) => getDistance(bestSite.latitude, bestSite.longitude, site.latitude, site.longitude))
        .sort((a, b) => a - b);
      const currentRadius = currentNeighborDistances[1];
      const bestRadius = bestNeighborDistances[1];
      if (!Number.isFinite(bestRadius)) return currentSite;
      if (!Number.isFinite(currentRadius)) return bestSite;
      return currentRadius < bestRadius ? currentSite : bestSite;
    }, null as any); // 选择“第 3 个点最近”的簇中心，避免被远端离散点拉远
    if (!denseAnchor) return null;
    const denseNeighborDistances = validSites
      .filter((site) => site !== denseAnchor)
      .map((site) => getDistance(denseAnchor.latitude, denseAnchor.longitude, site.latitude, site.longitude))
      .sort((a, b) => a - b);
    const denseRadius = denseNeighborDistances[1];
    if (!Number.isFinite(denseRadius) || denseRadius <= 0) return null;
    return resolveScaleByDiagonal(denseRadius * 2);
  };

  const sparseScaleForThreeVisibleSites = resolveSparseScaleForThreeVisibleSites(); // 稀疏场景至少可见 3 点的最大缩放等级
  const denseScaleForThreeVisibleSites = resolveDenseScaleForThreeVisibleSites(); // 高密度场景局部精细视角的缩放等级

  const nearbyCounts = validSites.map((targetSite, targetIndex) => {
    return validSites.reduce((count, compareSite, compareIndex) => {
      if (targetIndex === compareIndex) return count; // 密度统计不包含自身
      const meters = getDistance(targetSite.latitude, targetSite.longitude, compareSite.latitude, compareSite.longitude);
      return meters <= 1000 ? count + 1 : count;
    }, 0);
  }); // 每个点位在 1km 半径内的“邻居点”数量
  const maxNearbyCount = Math.max(...nearbyCounts);

  // 高密度区：1km 内点位 >= 2（按邻居数统计），固定精细视角。
  if (maxNearbyCount >= 2) {
    if (typeof denseScaleForThreeVisibleSites === 'number') {
      return Math.min(17, denseScaleForThreeVisibleSites);
    }
    return 17;
  }

  // 低密度区：1km 内点位 < 2，自动缩小到至少可见 3 个点位。
  if (maxNearbyCount < 2) {
    if (typeof sparseScaleForThreeVisibleSites === 'number') {
      return sparseScaleForThreeVisibleSites;
    }
  }

  let minLat = Number.POSITIVE_INFINITY;
  let maxLat = Number.NEGATIVE_INFINITY;
  let minLng = Number.POSITIVE_INFINITY;
  let maxLng = Number.NEGATIVE_INFINITY;
  validSites.forEach((site) => {
    if (site.latitude < minLat) minLat = site.latitude;
    if (site.latitude > maxLat) maxLat = site.latitude;
    if (site.longitude < minLng) minLng = site.longitude;
    if (site.longitude > maxLng) maxLng = site.longitude;
  });
  const diagonalMeters = getDistance(minLat, minLng, maxLat, maxLng);
  return resolveScaleByDiagonal(diagonalMeters);
};

/**
 * 计算点 P 在线段 AB 上的投影点（吸附算法）
 * @param p 真实点 {latitude, longitude}
 * @param a 线段起点 {latitude, longitude}
 * @param b 线段终点 {latitude, longitude}
 * @returns 投影点 {latitude, longitude}
 */
export const getProjectedPoint = (p: any, a: any, b: any) => {
  if (!p || !a || !b) return p;
  if (a.latitude === b.latitude && a.longitude === b.longitude) return a;

  const x0 = p.longitude, y0 = p.latitude;
  const x1 = a.longitude, y1 = a.latitude;
  const x2 = b.longitude, y2 = b.latitude;

  // 向量 AB
  const dx = x2 - x1;
  const dy = y2 - y1;
  // 向量 AP
  const ex = x0 - x1;
  const ey = y0 - y1;

  // 计算投影比例 t
  const dotProduct = ex * dx + ey * dy;
  const lengthSquared = dx * dx + dy * dy;
  const t = dotProduct / lengthSquared;

  // 如果投影点落在线段外，则取最近的端点
  if (t <= 0) return { latitude: a.latitude, longitude: a.longitude };
  if (t >= 1) return { latitude: b.latitude, longitude: b.longitude };

  // 返回投影点
  return {
    latitude: y1 + t * dy,
    longitude: x1 + t * dx
  };
};

// 判断是否需要更新路线（距离大于100米或时间超过10秒）
export const shouldUpdateRoute = (lastLat: number, lastLng: number, newLat: number, newLng: number, lastUpdateTime: number): boolean => {
  const distance = getDistance(lastLat, lastLng, newLat, newLng);
  const now = Date.now();
  const timeElapsed = now - lastUpdateTime;
  return distance > 100 || timeElapsed >= 10000;
};

// 格式化距离
export const formatDistance = (val: any) => {
  if (!val) return '0m';
  const d = Number(val);
  if (Number.isNaN(d)) return val;
  if (d >= 1000) {
    return (d / 1000).toFixed(1) + 'km';
  }
  return d.toFixed(0) + 'm';
}

/**
 * 背景：这个方法是让ai写的[新月脸]  当时是因为全览路线时下面老是会被卡片挡住  所以加的这个方法
 * 搞不懂为什么要这么做
 */
export const computeAdaptiveBottomPadding = (
  points: any[],
  basePadding: number,
  minPadding = 200,
  minAspect = 0.8,
  minRatio = 0.7
) => {
  if (!Array.isArray(points) || points.length < 2) {
    return basePadding;
  }
  let minLat = Number.POSITIVE_INFINITY;
  let maxLat = Number.NEGATIVE_INFINITY;
  let minLng = Number.POSITIVE_INFINITY;
  let maxLng = Number.NEGATIVE_INFINITY;
  for (const p of points) {
    const lat = Number(p?.latitude);
    const lng = Number(p?.longitude);
    if (!Number.isFinite(lat) || !Number.isFinite(lng)) {
      continue;
    }
    if (lat < minLat) minLat = lat;
    if (lat > maxLat) maxLat = lat;
    if (lng < minLng) minLng = lng;
    if (lng > maxLng) maxLng = lng;
  }
  if (!Number.isFinite(minLat) || !Number.isFinite(maxLat) || !Number.isFinite(minLng) || !Number.isFinite(maxLng)) {
    return basePadding;
  }
  const latRange = maxLat - minLat;
  const lngRange = maxLng - minLng;
  if (latRange <= 0 || lngRange <= 0) {
    return basePadding;
  }
  const avgLat = (minLat + maxLat) / 2;
  const adjustedLngRange = lngRange * Math.cos((avgLat * Math.PI) / 180);
  if (!Number.isFinite(adjustedLngRange) || adjustedLngRange <= 0) {
    return basePadding;
  }
  const aspect = latRange / adjustedLngRange;
  if (aspect >= minAspect) {
    return basePadding;
  }
  const ratio = Math.max(minRatio, Math.min(1, minRatio + (aspect / minAspect) * (1 - minRatio)));
  return Math.max(minPadding, Math.round(basePadding * ratio));
};

// 查找最近的标记点
export const findNearestMarker = (lat: number, lng: number, markers: any[]) => {
  let minDistance = Infinity;
  let targetMarker: any = null;

  markers.forEach(marker => {
    const distance = getDistance(lat, lng, marker.latitude, marker.longitude);
    if (distance < minDistance) {
      minDistance = distance;
      targetMarker = marker;
    }
  });

  return { targetMarker, minDistance };
};

// 解析路线数据为坐标点数组
export const parseRouteToPoints = (routeData: any) => {
  const points: any[] = [];
  if (routeData.paths && routeData.paths[0] && routeData.paths[0].steps) {
    const steps = routeData.paths[0].steps;
    for (let i = 0; i < steps.length; i++) {
      const poLen = steps[i].polyline.split(';');
      for (let j = 0; j < poLen.length; j++) {
        points.push({
          longitude: parseFloat(poLen[j].split(',')[0]),
          latitude: parseFloat(poLen[j].split(',')[1])
        })
      }
    }
  }
  return points;
};

// 格式化站点为标记点
export const formatSiteToMarker = (sites: any[]) => {
  return sites.map((site, index) => ({
    ...site,
    name: site.name,
    // id: index + 1,
    iconPath: 'https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/v2/golden-site-20260708.png',
    width: 18,
    height: 18,
    anchor: { x: 0.5, y: 0.5 }
  }));
};

// 获取位置的逆地理编码
export const getAddressByLocation = (longitude: number, latitude: number): Promise<any> => {
  return new Promise((resolve, reject) => {
    const myAmapFun = new amapFile.AMapWX({ key: _AMAP_KEY });
    myAmapFun.getRegeo({
      location: `${longitude},${latitude}`,
      success: (data) => {
        if (data && data[0]) {
          resolve(data[0]);
        } else {
          reject('No data found');
        }
      },
      fail: (info) => {
        reject(info);
      }
    });
  });
};

// 获取天气信息
export const getWeatherInfo = (city?: string): Promise<any> => {
  return new Promise((resolve, reject) => {
    const myAmapFun = new amapFile.AMapWX({ key: _AMAP_KEY });
    const options: any = {
      success: (data) => resolve(data),
      fail: (info) => reject(info)
    };
    if (city) {
      options.city = city;
    }
    myAmapFun.getWeather(options);
  });
};

/**
 * 过滤可渲染的围栏数据，首页需要同时渲染运营区与场站围栏。
 */
export const filterRenderableGeofence = (geofenceList: any[]) => {
  if (!Array.isArray(geofenceList)) return [];
  return geofenceList.filter((item) => [GEOFENCE_TYPE_OPERATING, GEOFENCE_TYPE_STATION].includes(Number(item?.type)));
};

const GEOFENCE_STATION_DASH_ARRAY = [10, 10] as [number, number];

/**
 * 格式化电子围栏面覆盖物，场站围栏使用独立配色以便和运营区区分。
 */
export const formatGeofencePolygons = (geofenceList: any[]) => {
  if (!geofenceList || !Array.isArray(geofenceList)) {
    return [];
  }
  return geofenceList.map(item => {
    const type = Number(item?.type); // 围栏类型
    return {
      points: item.points.map(p => ({
        latitude: p.lat,
        longitude: p.lng
      })),
      strokeWidth: type === GEOFENCE_TYPE_STATION ? 2 : 1.5,
      strokeColor: type === GEOFENCE_TYPE_STATION ? GEOFENCE_STATION_STROKE_COLOR : '#DFB369',
      fillColor: type === GEOFENCE_TYPE_STATION ? GEOFENCE_STATION_FILL_COLOR : '#DFB36929',
      dashArray: type === GEOFENCE_TYPE_STATION ? GEOFENCE_STATION_DASH_ARRAY : [0, 0],
      zIndex: 1
    }
  });
};

/**
 * 格式化场站围栏虚线边框，和选点页保持同一套表现。
 */
export const formatGeofenceFencePolylines = (geofenceList: any[]) => {
  if (!Array.isArray(geofenceList)) {
    return [];
  }
  return geofenceList.reduce((acc: any[], item: any, index: number) => {
    const type = Number(item?.type); // 围栏类型
    if (type !== GEOFENCE_TYPE_STATION || !Array.isArray(item?.points) || item.points.length < 2) {
      return acc;
    }
    const linePoints = item.points.map((p: any) => ({
      latitude: p.lat,
      longitude: p.lng
    }));
    acc.push({
      id: 900000 + index,
      points: [...linePoints, linePoints[0]],
      color: GEOFENCE_STATION_STROKE_COLOR,
      width: 2,
      dottedLine: true,
      arrowLine: false
    });
    return acc;
  }, []);
};

/**
 * 按统一规则格式化围栏覆盖物，供首页和选点页复用同一套渲染结果。
 */
export const formatGeofenceByType = (geofenceList: any[]) => {
  return {
    polygons: formatGeofencePolygons(geofenceList),
    fencePolylines: formatGeofenceFencePolylines(geofenceList)
  };
};

/**
 * 从围栏数据提取场站元信息映射，避免首页与选点页重复维护场站元数据格式。
 */
export const buildStationMetaMap = (geofenceList: any[]) => {
  const stationMetaMap: Record<string, any> = {};
  if (!Array.isArray(geofenceList)) {
    return stationMetaMap;
  }
  geofenceList.forEach((item) => {
    const stationId = item?.stationId; // 围栏关联的场站 ID
    if (!stationId) {
      return;
    }
    stationMetaMap[String(stationId)] = {
      stationId: String(stationId),
      name: item?.name || '',
      isCollect: !!item?.stationIsCollect,
    };
  });
  return stationMetaMap;
};

// 提取多边形所有顶点
export const extractPointsFromPolygons = (polygons: any[]) => {
  const points: any[] = [];
  if (!polygons || !Array.isArray(polygons)) return points;

  polygons.forEach(polygon => {
    if (polygon.points && Array.isArray(polygon.points)) {
      points.push(...polygon.points);
    }
  });
  return points;
};

// 转换 adcode 为 cityCode
export const convertAdcodeToCityCode = (adcode: string, cityName: string, province: string) => {
  let cityCode = adcode;
  if (adcode && typeof adcode === 'string' && adcode.length === 6) {
    if (cityName === province) {
      // 直辖市：前2位 + 0000
      cityCode = adcode.substring(0, 2) + '0000';
    } else {
      // 普通城市：前4位 + 00
      cityCode = adcode.substring(0, 4) + '00';
    }
  }
  return cityCode;
};

// 处理 Banner 点击跳转
export const handleBannerJump = (item: any) => {
  if (!item) return;
  const { jumpType, jumpUrl } = item;
  // jumpType: 1小程序内页面 2小程序地址 3网页地址
  if (jumpType === 1) {
    if (jumpUrl) {
      Taro.navigateTo({
        url: jumpUrl
      });
    }
  } else if (jumpType === 2) {
    if (jumpUrl) {
      Taro.navigateToMiniProgram({
        appId: jumpUrl,
        // path: '',
        success(res) {
          console.log('打开小程序成功', res);
        },
        fail(err) {
          console.error('打开小程序失败', err);
          Taro.showToast({ title: '跳转失败', icon: 'none' });
        }
      });
    }
  } else if (jumpType === 3) {
    if (jumpUrl) {
      Taro.navigateTo({
        url: `/pages/webpage/index?pageUrl=${encodeURIComponent(jumpUrl)}`
      });
    }
  }
};

// 防抖函数
export const debounce = (fn: Function, wait: number) => {
  let timer: any = null;
  return function (this: any, ...args: any[]) {
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, args);
    }, wait);
  }
}

// 节流函数
export const throttle = (fn: Function, wait: number) => {
  let _lastTime: any = null;
  return function (this: any, ...args: any[]) {
    let _nowTime = +new Date();
    if (!_lastTime || _nowTime - _lastTime > wait) {
      fn.apply(this, args);
      _lastTime = _nowTime;
    }
  }
}

// 预下载图片，返回本地临时路径（WeApp），失败或非WeApp环境返回原始URL
export const preloadImageToTemp = async (url: string): Promise<string> => {
  try {
    if (typeof Taro.getEnv !== 'function' || Taro.getEnv() !== Taro.ENV_TYPE.WEAPP) {
      return url;
    }
    const res = await Taro.downloadFile({ url });
    if (res?.statusCode === 200 && res.tempFilePath) {
      return res.tempFilePath;
    }
    const info = await Taro.getImageInfo({ src: url });
    if (info?.path) {
      return info.path;
    }
  } catch (e) {
  }
  return url;
}

// 获取地图数据（围栏检查+附近站点）
export const fetchMapData = async (
  lat: number,
  lng: number,
  cityCode?: string,
  pointOnOff?: number,
  options?: { allowedElectronicAreaId?: string }
) => {
  try {
    // 1. 先检查是否在运营区域内
    const fenceRes: any = await getFenceCheck({ latitude: lat, longitude: lng, cityCode }).catch(e => {
      return { status: 'inside' }; // 默认兜底
    });

    const isInside = fenceRes.status === 'inside';
    const electronicAreaId = fenceRes?.electronicAreaId || '';

    // 2. 只有在运营区域内才获取附近站点  type 传1 地图查询附近站点  不传 查搜索页附近站点
    let sites: any = { points: [] };
    const allowedElectronicAreaId = String(options?.allowedElectronicAreaId || '');
    const shouldQueryNearbySites = isInside && (!allowedElectronicAreaId || allowedElectronicAreaId === String(electronicAreaId || ''));
    if (shouldQueryNearbySites) {
      sites = await getNearestSite({ latitude: lat, longitude: lng, electronicAreaId, pointOnOff, type:1 }).catch(e => {
        return { points: [] };
      });
      // 兼容处理
      if (!sites || !sites.points) {
        sites = { points: [] };
      }
    }

    const newMarkers = formatSiteToMarker(sites.points);

    return { isInside, electronicAreaId, newMarkers, sites: sites.points };
  } catch (error) {
    console.error('fetchMapData error', error);
    return { isInside: true, electronicAreaId: '', newMarkers: [], sites: [] };
  }
}

// 获取步行规划路线
export const getWalkingRoute = (origin: string, destination: string): Promise<{ points: any[], duration: number, distance: number }> => {
  return new Promise((resolve, reject) => {
    const myAmapFun = new amapFile.AMapWX({ key: _AMAP_KEY });
    myAmapFun.getWalkingRoute({
      origin: origin,
      destination: destination,
      success: (data) => {
        const points = parseRouteToPoints(data);
        let duration = 0;
        let distance = 0;
        if (data.paths && data.paths[0]) {
          duration = Number(data.paths[0].duration);
          distance = Number(data.paths[0].distance);
        }
        resolve({ points, duration, distance });
      },
      fail: (info) => {
        reject(info);
      }
    });
  });
};

// 获取城市中心经纬度
export const getCityLocation = (cityName: string): Promise<{ latitude: number, longitude: number }> => {
  return new Promise((resolve, reject) => {
    const myAmapFun = new amapFile.AMapWX({ key: _AMAP_KEY });
    myAmapFun.getInputtips({
      keywords: cityName,
      city: cityName,
      success: (data) => {
        if (data && data.tips && data.tips.length > 0) {
          // 优先取第一个有坐标的结果
          const tip = data.tips.find(t => t.location && t.location.length > 0);
          if (tip) {
            const locationArr = tip.location.split(',');
            if (locationArr.length === 2) {
              resolve({
                longitude: Number(locationArr[0]),
                latitude: Number(locationArr[1])
              });
              return;
            }
          }
          reject('No valid location found');
        } else {
          reject('No data found');
        }
      },
      fail: (info) => {
        reject(info);
      }
    });
  });
};

// 获取包含 ID 的城市信息
export const getCityInfoWithId = async (cityCode: string, cityName: string) => {

  try {
    const res: any = await getOpenCity();

    let cityId = 0;
    if (Array.isArray(res.cities)) {
      // 优先匹配 adcode
      let target = res.cities.find(item => item.adcode === cityCode);
      // 如果 adcode 匹配失败，尝试匹配 cityName
      if (!target && cityName) {
        // 移除"市"字进行模糊匹配，增加匹配成功率
        const normalizedCityName = cityName.replace(/市$/, '');
        target = res.cities.find(item => {
          const itemName = item.name.replace(/市$/, '');
          return itemName === normalizedCityName || item.name.includes(normalizedCityName) || normalizedCityName.includes(item.name);
        });
      }

      if (target) {
        cityId = target.id;
        // 修正返回的 code，确保使用的是系统匹配到的城市的标准 adcode
        if (target.adcode) {
          cityCode = target.adcode;
        }
      }
    }
    return {
      name: cityName,
      code: cityCode,
      id: cityId
    };
  } catch (error) {
    console.error('getOpenCity error', error);
    return {
      name: cityName,
      code: cityCode,
      id: 0
    };
  }
};

// 格式化秒数为时钟时间（分钟:秒）
export const formatDurationToClock = (sec: number) => {
  const safeSeconds = Math.max(0, sec);
  const m = Math.floor(safeSeconds / 60);
  const s = safeSeconds % 60;
  return `${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
};

// 格式化日期时间
export const formatDateTime = (date: Date) => {
  const y = date.getFullYear();
  const mo = String(date.getMonth() + 1).padStart(2, '0');
  const d = String(date.getDate()).padStart(2, '0');
  const h = String(date.getHours()).padStart(2, '0');
  const mi = String(date.getMinutes()).padStart(2, '0');
  const s = String(date.getSeconds()).padStart(2, '0');
  return `${y}-${mo}-${d} ${h}:${mi}:${s}`;
};

export const formatMoney = (value: any) => {
  const num = Number(value);
  if (Number.isNaN(num)) {
    return '--';
  }
  return num.toFixed(2);
};

export const formatNumber = (value: any, digits = 1) => {
  const num = Number(value);
  if (Number.isNaN(num)) {
    return '--';
  }
  return digits === 0 ? Math.round(num).toString() : num.toFixed(digits);
};

export const formatTripDistance = (value: any) => {
  const num = Number(value);
  if (!Number.isFinite(num)) {
    return '--';
  }
  const safe = Math.max(0, num);
  if (safe < 1000) {
    return `${Math.round(safe)}米`;
  }
  return `${(safe / 1000).toFixed(1)}公里`;
};

export const formatTripDurationFromSeconds = (value: any) => {
  const num = Number(value);
  if (!Number.isFinite(num)) {
    return '--';
  }
  const safe = Math.max(0, Math.round(num));
  if (safe < 60) {
    return `${safe}秒`;
  }
  if (safe < 3600) {
    return `${Math.floor(safe / 60)}分钟`;
  }
  const hours = Math.floor(safe / 3600);
  const minutes = Math.floor((safe % 3600) / 60);
  if (minutes === 0) {
    return `${hours}小时`;
  }
  return `${hours}小时${minutes}分钟`;
};

export const formatDurationDisplay = (value: any) => {
  const num = Number(value);
  if (Number.isNaN(num)) {
    return { value: 0, unit: '分钟' };
  }
  if (num < 60) {
    return { value: Math.max(0, Math.round(num)), unit: '秒' };
  }
  return { value: Math.ceil(num / 60), unit: '分钟' };
};

export const getTypeLabel = (type: any) => {
  if (type === 2) return '夜间行驶时段';
  if (type === 3) return '节假日时段';
  return '普通时段';
};

export const formatCountdown = (seconds: number) => {
  const safeSeconds = Math.max(0, seconds);
  const minutes = Math.floor(safeSeconds / 60);
  const restSeconds = safeSeconds % 60;
  const mm = String(minutes).padStart(2, '0');
  const ss = String(restSeconds).padStart(2, '0');
  return `${mm}:${ss}`;
};

export const getRemainingSeconds = (endTimeMs: number | null) => {
  if (!endTimeMs) {
    return null;
  }
  const diff = endTimeMs - Date.now();
  if (diff <= 0) {
    return 0;
  }
  return Math.ceil(diff / 1000);
};

export const parseFlexibleEndTimeMs = (value: any) => {
  const num = Number(value);
  if (Number.isNaN(num) || num <= 0) {
    return null;
  }
  if (num > 1000000000000) {
    return num;
  }
  if (num > 1000000000) {
    return num * 1000;
  }
  if (num <= 360) {
    return Date.now() + num * 60 * 1000;
  }
  return Date.now() + num * 1000;
};

// 清除订单行程存储
export const clearOrderTripStorage = () => {
  Taro.removeStorageSync('orderId');
  Taro.removeStorageSync('tripStatus');
  // 一并清空修改目的地的全部会话缓存，防止脏数据残留污染后续的新订单
  Taro.removeStorageSync(MODIFY_DESTINATION_SESSION_KEY);
  Taro.removeStorageSync(MODIFY_DESTINATION_CANDIDATE_KEY);
  Taro.removeStorageSync(MODIFY_DESTINATION_OVERRIDE_KEY);
  Taro.removeStorageSync(MODIFY_DESTINATION_ROUTE_POINTS_KEY);
  Taro.removeStorageSync(MODIFY_DESTINATION_SKIP_AC_QUERY_ON_RETURN_KEY);
  Taro.removeStorageSync(MODIFY_DESTINATION_SOCKET_STATUS_KEY);
  Taro.removeStorageSync(MODIFY_DESTINATION_PENDING_SAME_SITE_TOAST_KEY);
};

/**
 * 通过 IP 获取当前位置信息（用于定位授权失败时的兜底）
 */
export const getLocationByIP = (): Promise<any> => {
  return new Promise(async (resolve, reject) => {
    try {
      // 1. 获取当前 network IP
      const res: any = await request({
        url: _ROBOTAXI_HOST + '/map/base/v1/mini-program/point/getPointByIp',
        method: 'GET',
      });

      if (res && res.point && typeof res.point.latitude === 'number' && typeof res.point.longitude === 'number') {
        resolve({
          longitude: res.point.longitude,
          latitude: res.point.latitude,
          city: res.city || '',
          adcode: res.adcode || ''
        });
      } else {
        // 如果后端接口不可用或未返回数据，尝试使用第三方接口作为备选获取 IP
        Taro.request({
          url: 'https://api.ipify.org?format=json',
          success: (ipRes) => {
            const ip = ipRes.data?.ip;
            if (ip) {
              // 拿着获取到的 IP 去请求服务端接口
              request({
                url: _ROBOTAXI_HOST + '/map/base/v1/mini-program/point/getPointByIp',
                method: 'POST',
                payload: { ip }
              }).then((businessRes: any) => {
                if (businessRes && businessRes.point && typeof businessRes.point.latitude === 'number' && typeof businessRes.point.longitude === 'number') {
                  resolve({
                    longitude: businessRes.point.longitude,
                    latitude: businessRes.point.latitude,
                    city: businessRes.city || '',
                    adcode: businessRes.adcode || ''
                  });
                } else {
                  reject('Business IP location failed');
                }
              }).catch(reject);
            } else {
              reject('Failed to get network IP');
            }
          },
          fail: reject
        });
      }
    } catch (error) {
      reject(error);
    }
  });
};

export const mapOrderStatusToTripStatus = (status: any) => {
  switch (Number(status)) {
    case 0:
      return 1;
    case 1:
      return 3;
    case 2:
    case 3:
      return 4;
    case 4:
      return 5;
    case 5:
    case 6:
      return 6;
    case 7:
      return 6;
    case 8:
      return 8;
    case 9:
    case 10:
      return 9;
    case 11:
      return 9;
    case 12:
      return 9;
    case 13:
      return 9;
    default:
      return 0;
  }
}

/** 埋点操作类型。 */
type ReportEventType = 'pageView' | 'track';

/** 默认埋点操作类型。 */
const DEFAULT_REPORT_EVENT_TYPE: ReportEventType = 'track';

/** 页面路径兜底值。 */
const DEFAULT_PAGE_PATH = '/';

/** 来源页路径兜底值。 */
const DEFAULT_REFERRER_PATH = '';

/** Unix 秒时间戳的毫秒阈值。 */
const UNIX_SECONDS_MILLISECOND_THRESHOLD = 1000000000000;

/** 毫秒转秒的换算系数。 */
const MILLISECONDS_PER_SECOND = 1000;

/** 标准化埋点页面路径。 */
const normalizeReportPagePath = (route: any, fallbackPath: string) => {
  const normalizedRoute = String(route || '').trim();
  if (!normalizedRoute) {
    return fallbackPath;
  }
  return normalizedRoute.startsWith('/') ? normalizedRoute : `/${normalizedRoute}`;
};

/** 读取当前页与来源页路径。 */
const getReportPageContext = () => {
  const pages = Taro.getCurrentPages();
  const currentPage = pages[pages.length - 1];
  const referrerPage = pages[pages.length - 2];
  return {
    pagePath: normalizeReportPagePath(currentPage?.route, DEFAULT_PAGE_PATH),
    referrerPath: normalizeReportPagePath(referrerPage?.route, DEFAULT_REFERRER_PATH)
  };
};

/** 将任意时间字段安全转换为 Unix 秒时间戳。 */
export const toUnixSeconds = (value: any) => {
  if (typeof value === 'number' && Number.isFinite(value)) {
    return value > UNIX_SECONDS_MILLISECOND_THRESHOLD
      ? Math.floor(value / MILLISECONDS_PER_SECOND)
      : Math.floor(value);
  }
  if (typeof value === 'string') {
    const normalizedValue = value.trim();
    const numericValue = Number(normalizedValue);
    if (normalizedValue && Number.isFinite(numericValue)) {
      return numericValue > UNIX_SECONDS_MILLISECOND_THRESHOLD
        ? Math.floor(numericValue / MILLISECONDS_PER_SECOND)
        : Math.floor(numericValue);
    }
    const parsedTime = Date.parse(value);
    if (!Number.isNaN(parsedTime)) {
      return Math.floor(parsedTime / MILLISECONDS_PER_SECOND);
    }
  }
  return 0;
};

/** 判断埋点字段是否为需要自动 JSON 化的结构化数据。 */
const isStructuredReportValue = (value: any) => {
  if (Array.isArray(value)) {
    return true;
  }
  return Object.prototype.toString.call(value) === '[object Object]';
};

/** nearby_pickup_stations 埋点允许保留的字段。 */
const NEARBY_PICKUP_STATION_REPORT_KEYS = ['id', 'name', 'latitude', 'longitude', 'electronicAreaId'] as const;

/** nearby_pickup_stations 埋点最多保留的站点数量。 */
const MAX_NEARBY_PICKUP_STATIONS_REPORT_COUNT = 5;

/** 过滤 nearby_pickup_stations，仅保留约定字段。 */
const filterNearbyPickupStationsForReport = (value: any) => {
  if (!Array.isArray(value)) {
    return value;
  }
  return value.slice(0, MAX_NEARBY_PICKUP_STATIONS_REPORT_COUNT).map((item) => {
    if (Object.prototype.toString.call(item) !== '[object Object]') {
      return item;
    }
    return NEARBY_PICKUP_STATION_REPORT_KEYS.reduce((result: Record<string, any>, key) => {
      result[key] = item?.[key];
      return result;
    }, {});
  });
};

/** 预处理埋点字段：按字段规则裁剪后再进入序列化流程。 */
const preprocessReportValue = (key: string, value: any) => {
  if (key === 'nearby_pickup_stations') {
    return filterNearbyPickupStationsForReport(value);
  }
  return value;
};

/** 序列化单个埋点字段，避免对象被底层隐式转成 [object Object]。 */
const serializeReportValue = (value: any) => {
  if (!isStructuredReportValue(value)) {
    return value;
  }
  try {
    return JSON.stringify(value);
  } catch (error) {
    return Array.isArray(value) ? '[]' : '{}';
  }
};

/** 归一化自定义埋点参数：仅自动 JSON 化顶层对象/数组字段。 */
const normalizeReportParams = (para: any) => {
  if (!para || Object.prototype.toString.call(para) !== '[object Object]') {
    return {};
  }
  return Object.keys(para).reduce((result: Record<string, any>, key: string) => {
    result[key] = serializeReportValue(preprocessReportValue(key, para[key]));
    return result;
  }, {});
};

// 埋点
export const reportEvent = async (
  eventId: string,
  para: any,
  type: ReportEventType = DEFAULT_REPORT_EVENT_TYPE
) => {
  let appVersion = '';
  const $app: any = Taro.getApp().$app;
  const { openId } = await $app.getIdData() || {};
  const { pagePath, referrerPath } = getReportPageContext();
  const normalizedPara = normalizeReportParams(para);
  try {
    const accountInfo = Taro.getAccountInfoSync();
    appVersion = accountInfo?.miniProgram?.version || accountInfo?.miniProgram?.envVersion || '';
  } catch (e) {
    console.warn('获取小程序版本号失败:', e);
  }

  getStorage(_UID).then((uid) => {
    $app.xpReportSend({
      eventId,
      para: {
        ...normalizedPara,  // 自定义参数
        page_path: pagePath,  // 页面路径
        referrer_path: referrerPath,  // 来源页路径
        type,  // 埋点操作类型
        user_id: uid || '-1',  // 用户ID
        masked_device_id: openId,  // 设备ID
        device_id: openId,  // 设备ID
        event_time: Date.now(),  // 事件时间
        city: Taro.getStorageSync('selectedCity').name || '',  // 城市
        orderId: Taro.getStorageSync('orderId') || '',  // 订单ID
        os: Taro.getSystemInfoSync().system || '',  // 操作系统
        app_id: APPID,  // 微信小程序appid
        app_ver: appVersion,  // 微信小程序版本
        session_id: '',  // 会话ID
      },
    });
  });
}
