import type { DataModel } from "@imengyu/js-request-transform";
import { MapServerRequestModule } from "../RequestModules";

/** 路线规划 - 阶段路线步骤（驾车/步行/骑行等通用） */
export interface DirectionStep {
  instruction: string;
  polyline_idx: number[] | [number, number];
  road_name?: string;
  dir_desc?: string;
  distance: number;
  duration?: number;
  act_desc?: string;
  accessorial_desc?: string;
  type?: number; // 步行设施类型：0普通道路 1过街天桥 2地下通道 3人行横道
  speed?: { polyline_idx: number[]; distance: number; level: number }[];
}

/** 路线规划 - 单条方案（驾车） */
export interface DrivingRoute {
  mode: 'DRIVING';
  tags?: string[];
  distance: number;
  duration: number;
  traffic_light_count?: number;
  toll?: number;
  restriction?: { status: number };
  polyline: number[];
  waypoints?: { title?: string; location: { lat: number; lng: number }; polyline_idx?: number; distance?: number; duration?: number; input_order_idx?: number }[];
  steps: DirectionStep[];
  taxi_fare?: { fare: number };
}

/** 路线规划 - 单条方案（步行/骑行/电动车） */
export interface WalkingRoute {
  mode: 'WALKING' | 'BICYCLING' | 'EBICYCLING';
  distance: number;
  duration: number;
  direction?: string;
  polyline: number[];
  steps: DirectionStep[];
}

/** 路线规划 - 驾车结果 */
export interface DirectionDrivingResult {
  routes: DrivingRoute[];
}

/** 路线规划 - 步行/骑行/电动车结果 */
export interface DirectionWalkingResult {
  routes: WalkingRoute[];
}

/** 路线规划 - 公交步骤（步行为 WALKING，公交为 TRANSIT，结构不同） */
export type TransitStep = (
  | { mode: 'WALKING'; distance: number; duration: number; direction: string; polyline: number[]; steps?: DirectionStep[] }
  | { mode: 'TRANSIT'; vehicle: string; [key: string]: unknown }
);

/** 路线规划 - 公交结果 */
export interface DirectionTransitResult {
  routes: { distance: number; duration: number; bounds: string; steps: TransitStep[] }[];
}

export class MapApi extends MapServerRequestModule<DataModel> {
  constructor() {
    super();
  }

  /**
   * 逆地址解析（坐标位置描述）
   * 
   * 文档：https://lbs.qq.com/service/webService/webServiceGuide/address/Gcoder
   * 
   * 说明：
   * 本接口提供由经纬度到文字地址及相关位置信息的转换能力，广泛应用于物流、出行、O2O、社交等场景。服务响应速度快、稳定，支撑亿级调用。
   * 支持根据输入经纬度，获取：
   * 1 . 经纬度所在省、市、区、乡镇、门牌号、行政区划代码，及周边参考位置信息，如道路及交叉口、河流、湖泊、桥等
   * 2 . 通过知名地点、地标组合形成的易于理解的地址，如：北京市海淀区中钢国际广场(欧美汇购物中心北)。
   * 3 . 商圈、附近知名的一级地标、代表当前位置的二级地标等。
   * 4 . 周边POI（AOI）列表。
   * 
   * @param location 经纬度（GCJ02坐标系），格式：location=lat<纬度>,lng<经度>
   * @param radius 半径，单位：米
   * @param get_poi 是否获取周边POI（AOI）列表
   * @param poi_options 周边POI（AOI）列表选项，格式：poi_options=type<POI类型>,radius<半径>,数量<数量>
   * @returns 
   */
  async geocoder(location: string, radius?: number, get_poi?: boolean, poi_options?: string) {
    return (await this.get<{
      address: string;
      formatted_addresses: {
        recommend: string;
        rough: string;
        standard_address: string;
      };
      address_component: {
        nation: string;
        province: string;
        city: string;
        district: string;
        street: string;
        street_number: string;
      };
    }>('/ws/geocoder/v1/', '逆地址解析（坐标位置描述）', {
      location,
      radius,
      get_poi: get_poi ? 1 : 0,
      poi_options,
    })).data;
  }

  /**
   * 地址解析（地址转坐标）
   *
   * 文档：https://lbs.qq.com/service/webService/webServiceGuide/address/Geocoder
   *
   * 说明：
   * 本接口提供由文字地址到经纬度的转换能力，并同时提供结构化的省市区地址信息。
   * 为提升解析准确率，地址中请至少包含城市名称；地址请尽量完整、具体（包括省市区乡镇/街道门牌及详细地点信息）。
   *
   * @param address 要解析的输入地址（建议包含城市，尽量完整；若包含 # 等特殊字符需先 URL 编码）
   * @param policy 解析策略：0 标准（默认，地址须包含城市）；1 宽松（允许缺失城市，准确性可能受影响）
   * @returns 解析结果，含坐标（GCJ02）、省市区等结构化信息及可信度、解析级别
   */
  async geocodeAddress(
    address: string,
    policy?: 0 | 1
  ) {
    return (await this.get<{
      /** [废弃] 最终用于坐标解析的地址或地点名称，仅供参考 */
      title: string;
      /** 解析到的坐标（GCJ02 坐标系） */
      location: { lat: number; lng: number };
      /** 解析后的地址部件 */
      address_components: {
        province: string;
        city: string;
        district: string;
        street: string;
        street_number: string;
      };
      /** 行政区划信息 */
      ad_info: { adcode: string };
      /** 可信度 1–10，>=7 时解析结果较为准确 */
      reliability: number;
      /** 解析精度级别，一般 >=9 即可采用（定位到点） */
      level?: number;
    }>('/ws/geocoder/v1/', '地址解析（地址转坐标）', {
      address,
      ...(policy !== undefined && { policy }),
    })).data;
  }

  /**
   * 路线规划 - 驾车
   *
   * 文档：https://lbs.qq.com/service/webService/webServiceGuide/route/webServiceRoute
   *
   * @param from 起点坐标，格式：纬度,经度（如 39.915285,116.403857）
   * @param to 终点坐标，格式：纬度,经度
   * @param options 可选：waypoints 途经点、policy 策略、get_mp 多方案、get_speed 路况、no_step 不返回引导等
   */
  async directionDriving(
    from: string,
    to: string,
    options?: {
      from_poi?: string;
      to_poi?: string;
      to_poiname?: string;
      waypoints?: string;
      waypoint_order?: 0 | 1;
      policy?: string;
      plate_number?: string;
      cartype?: 0 | 1;
      get_mp?: 0 | 1;
      get_speed?: 0 | 1;
      no_step?: 0 | 1;
      avoid_polygons?: string;
      [key: string]: string | number | undefined;
    }
  ) {
    return (await this.get<DirectionDrivingResult>('/ws/direction/v1/driving/', '路线规划-驾车', {
      from,
      to,
      ...options,
    })).data;
  }

  /**
   * 路线规划 - 步行
   *
   * 文档：https://lbs.qq.com/service/webService/webServiceGuide/route/webServiceRoute
   *
   * @param from 起点坐标，格式：纬度,经度
   * @param to 终点坐标，格式：纬度,经度（直线距离 10米–300公里）
   */
  async directionWalking(from: string, to: string, options?: { to_poi?: string }) {
    return (await this.get<DirectionWalkingResult>('/ws/direction/v1/walking/', '路线规划-步行', {
      from,
      to,
      ...options,
    })).data;
  }

  /**
   * 路线规划 - 骑行
   *
   * 文档：https://lbs.qq.com/service/webService/webServiceGuide/route/webServiceRoute
   *
   * @param from 起点坐标，格式：纬度,经度
   * @param to 终点坐标，格式：纬度,经度（直线距离 10米–500公里）
   */
  async directionBicycling(from: string, to: string, options?: { to_poi?: string }) {
    return (await this.get<DirectionWalkingResult>('/ws/direction/v1/bicycling/', '路线规划-骑行', {
      from,
      to,
      ...options,
    })).data;
  }

  /**
   * 路线规划 - 电动车
   *
   * 文档：https://lbs.qq.com/service/webService/webServiceGuide/route/webServiceRoute
   *
   * @param from 起点坐标，格式：纬度,经度
   * @param to 终点坐标，格式：纬度,经度
   */
  async directionEbicycling(from: string, to: string, options?: { to_poi?: string }) {
    return (await this.get<DirectionWalkingResult>('/ws/direction/v1/ebicycling/', '路线规划-电动车', {
      from,
      to,
      ...options,
    })).data;
  }

  /**
   * 路线规划 - 公交（含地铁、火车等）
   *
   * 文档：https://lbs.qq.com/service/webService/webServiceGuide/route/webServiceRoute
   *
   * @param from 起点坐标，格式：纬度,经度
   * @param to 终点坐标，格式：纬度,经度
   * @param options 可选：departure_time 出发时间戳、policy 偏好（LEAST_TIME/LEAST_TRANSFER/LEAST_WALKING/RECOMMEND 等）
   */
  async directionTransit(
    from: string,
    to: string,
    options?: {
      from_poi?: string;
      to_poi?: string;
      departure_time?: number;
      policy?: string;
      added_fields?: string;
    }
  ) {
    return (await this.get<DirectionTransitResult>('/ws/direction/v1/transit/', '路线规划-公交', {
      from,
      to,
      ...options,
    })).data;
  }
}

export default new MapApi();