<template>
  <FlexCol innerClass="travel-route">
    <FlexCol position="absolute" :top="0" :left="0" :right="0" :zIndex="100">
      <StatusBarSpace backgroundColor="transparent">
        <template #background>
          <BackgroundBox 
            width="fill"
            height="300"
            color1="white"
            color2="transparent"
          />
        </template>
      </StatusBarSpace>
      <NavBar
        title="路线地图"
        leftButton="back"
      />
    </FlexCol>
    <FlexCol position="absolute" :bottom="630" :right="30" :zIndex="100">
      <Button icon="my-location" :iconProps="{ size: 40 }" @click="goToCurrentLocation" />
    </FlexCol>
    <map
      id="map"
      :markers="markers"
      :latitude="currentLocation[1]"
      :longitude="currentLocation[0]"
      :polyline="polyline"
      :circles="circles"
      :show-location="true"
      :enable-3D="true"
      :show-compass="true"
      @marker-tap="onMarkerClick"
    />
    <BottomSheet
      ref="bottomSheetRef"
      :show="true"
      :dragMaxHeight="700"
      :dragMinHeight="80"
      :dragSnapHeights="[ 80, 300, 700 ]"
    >
      <template #content> 
        <FlexCol v-if="travalDetail" :padding="25" :gap="20">
          <H2>{{ travalDetail.title }}</H2>
          <Text>{{ travalDetail.desc }}</Text>
          <Tabs 
            v-model:currentIndex="currentTabIndex"
            :autoItemWidth="false"
            :tabs="[
              { text: '路线规划', width: 140 },
              { text: '路线介绍', width: 140 },
            ]"
          />
          <!-- 路线规划 -->
          <FlexCol v-if="currentTabIndex === 0" :gap="20">
            <FlexCol :gap="20">
              <Text color="text.second">导航偏好</Text>
              <scroll-view :scroll-x="true" :style="{ width: '100%' }">
                <FlexRow :gap="10">
                  <Button 
                    v-for="way in preferredWays" 
                    :key="way" 
                    :text="getRouteToNextBestWayText(way as RouteToNextBestWay)"
                    :type="way === userPreferredWay ? 'primary' : 'default'"
                    @click="(userPreferredWay = way as RouteToNextBestWay)" 
                  />
                </FlexRow>
              </scroll-view>
            </FlexCol>
            <FlexCol :gap="20">
              <Text color="text.second">路线规划</Text>
              <FlexCol 
                v-for="(item, index) in routeInfo?.items || []" :key="item.id" 
                :gap="20"
              >
                <Touchable direction="row" justify="space-between" :gap="20" @click="onItemClick(item)">
                  <FlexRow :gap="20">
                    <Image :src="item.scenicSpot.image" :radius="20" :width="80" :height="80" mode="aspectFill" />
                    <FlexCol>
                      <Text bold :color="routeColors[index]">打卡点 {{ (index + 1) }}</Text><!-- //如果显示天数则用 item.atDay -->
                      <Text>{{ item.scenicSpot.name }}</Text>
                      <Text color="text.second">{{ item.scenicSpot.address }}</Text>
                    </FlexCol>
                  </FlexRow>
                  <FlexCol center :gap="10" :innerStyle="{ minWidth: '150rpx' }">
                    <Button type="text" icon="navigation" text="导航" @click="openLocation(item)" />
                    <template v-if="currentLocationGeted">
                      <Text color="text.second" :fontSize="22">距您约</Text>
                      <Text color="text.second" :fontSize="28" :text="getDistance(item)" />
                    </template>
                  </FlexCol>
                </Touchable>
                <NextBestWay 
                  :toNextRoute="item.toNextRoute"
                  :toNextBestWay="item.toNextBestWay"
                  :userPreferredWay="userPreferredWay"
                  @focusRoute="focusRoute(item)"
                >
                  <template #extra="{ finalWay }">
                    <!-- 公交地铁路线规划 -->
                    <FlexCol 
                      v-if="item.toNextRoute && item.toNextRoute['transit'] && finalWay === 'transit'" 
                      :gap="8" 
                      :margin="[10,0,10,100]"
                    >
                      <FlexCol v-for="(step, stepIdx) in (item.toNextRoute.transit.steps || [])" :key="stepIdx" :gap="4">
                        <template v-if="step.mode === 'WALKING'">
                          <FlexRow :gap="8" align="center">
                            <Tag type="primary" :text="(stepIdx + 1).toString()" />
                            <Icon icon="walk" :size="40" />
                            <Text color="text.second">步行</Text>
                            <Text>{{ formatDistance(step.distance) }} · 约 {{ formatDuration(step.duration) }}</Text>
                          </FlexRow>
                        </template>
                        <template v-else-if="step.mode === 'TRANSIT' && step.lines?.length">
                          <FlexRow :gap="8" align="center">
                            <Tag type="success" :text="(stepIdx + 1).toString()" />
                            <Icon icon="bus" :size="40" />
                            <Button 
                              v-if="step.lines?.length > 1" 
                              type="text"
                              rightIcon="arrow-down"
                              :text="step.lines?.length > 1 ? `可搭乘 ${step.lines[0].title} 等 ${step.lines?.length} 条线路` : ''"
                              @click="(step as any).open=true"
                            />
                          </FlexRow>
                          <FlexCol v-for="(line, lineIdx) in step.lines" :key="lineIdx" :gap="10" :padding="[0,0,0,50]">
                            <FlexRow :gap="8" align="center">
                              <template v-if="line.vehicle === 'BUS'">
                                <Icon v-if="line.vehicle === 'BUS'" icon="bus" :size="40" />
                                <Text color="text.second">公交</Text>
                              </template>
                              <template v-else-if="line.vehicle === 'SUBWAY'">
                                <Icon icon="subway" :size="40" />
                                <Text color="text.second">地铁</Text>
                              </template>
                              <template v-else-if="line.vehicle === 'RAIL'">
                                <Icon icon="rail" :size="40" />
                                <Text color="text.second">火车</Text>
                              </template>
                              <Text bold :color="(line as any).line_color || '#000'">{{ line.title }}</Text>
                              <Text color="text.second" :margin="[0,0,0,8]">{{ line.geton?.title }} → {{ line.getoff?.title }}</Text>
                            </FlexRow>
                            <Text color="text.second">约 {{ formatDuration(line.duration) }} · {{ line.station_count || 0 }} 站</Text>
                          </FlexCol>
                        </template>
                      </FlexCol>
                    </FlexCol>
                  </template>
                </NextBestWay>
              </FlexCol>
            </FlexCol>
            <Height :height="100" />
          </FlexCol>
          <!-- 路线介绍 -->
          <FlexCol v-if="currentTabIndex === 1">
            <Parse :content="travalDetail.content" />
            <Height :height="100" />
          </FlexCol>
        </FlexCol>
      </template>
    </BottomSheet>
  </FlexCol>
</template>

<script setup lang="ts">
import type { GetContentDetailItem } from '@/api/CommonContent';
import { RequestApiError, waitTimeOut } from '@imengyu/imengyu-utils';
import { onMounted, ref, watch } from 'vue';
import { useLoadQuerys } from '@/common/composeabe/LoadQuerys';
import TravalContent from '@/api/traval/TravalContent';
import AppCofig from '@/common/config/AppCofig';
import Text from '@/components/basic/Text.vue';
import H2 from '@/components/typography/H2.vue';
import BottomSheet, { type BottomSheetExpose } from '@/components/dialog/BottomSheet.vue';
import BackgroundBox from '@/components/display/block/BackgroundBox.vue';
import FlexCol from '@/components/layout/FlexCol.vue';
import StatusBarSpace from '@/components/layout/space/StatusBarSpace.vue';
import NavBar from '@/components/nav/NavBar.vue';
import FlexRow from '@/components/layout/FlexRow.vue';
import Image from '@/components/basic/Image.vue';
import RouteApi, {formatDistance, formatDuration, getRouteToNextBestWayText, type RouteInfo, type RouteToNextBestWay } from '@/api/traval/RouteApi';
import Tag from '@/components/display/Tag.vue';
import Button from '@/components/basic/Button.vue';
import Touchable from '@/components/feedback/Touchable.vue';
import Parse from '@/components/display/parse/Parse.vue';
import IconButton from '@/components/basic/IconButton.vue';
import { alert } from '@/components/utils/DialogAction';
import Tabs from '@/components/nav/Tabs.vue';
import Icon from '@/components/basic/Icon.vue';
import CollapseBox from '@/components/display/CollapseBox.vue';
import NextBestWay from './components/NextBestWay.vue';
import Height from '@/components/layout/space/Height.vue';
import { navTo } from '@/components/utils/PageAction';

const markers = ref<any[]>([]);
/** 地图折线：每条 toNextRoute 一段，points 来自 toNextRoute.xxx.polyline (number[] 为 经度,纬度 交替) */
/** 地图折线项，支持微信小程序 map 的 segmentTexts / textStyle 在折线上显示文字 */
const polyline = ref<Array<{
  points: { longitude: number; latitude: number }[];
  color?: string;
  width?: number;
  segmentTexts?: { name: string; startIndex: number; endIndex: number }[];
  textStyle?: { textColor?: string; strokeColor?: string; fontSize?: number };
}>>([]);
const circles = ref<any[]>([]);

const currentTabIndex = ref(0);
const mapCtx = uni.createMapContext('map');
const myLocation = ref<[number, number]>([0, 0]);
const currentLocation = ref<[number, number]>([0, 0]);
const currentLocationGeted = ref(false);
const travalDetail = ref<GetContentDetailItem>();
const routeInfo = ref<RouteInfo>();
const userPreferredWay = ref<RouteToNextBestWay|''>('');
const bottomSheetRef = ref<BottomSheetExpose>();

const { querys } = useLoadQuerys({
  id: 8768,
}, () => {
  loadRoute();
});

const routeColors = [ '#22ac38', '#00a0e9', '#8957a1', '#eb6877', '#f39800', '#e60012' ];
const preferredWays = ['', 'driving', 'walking', 'bicycling', 'ebicycling', 'transit'];
function getMakerImage(day: number) {
  return `https://mncdn.wenlvti.net/app_static/minnan/images/IcoMaker${(day + 1)}.png`;
}

/** 根据两点经纬度计算直线距离（米），Haversine 公式 */
function getDistanceMeters(
  lon1: number, lat1: number,
  lon2: number, lat2: number
): number {
  const R = 6371000; // 地球半径 米
  const dLat = (lat2 - lat1) * Math.PI / 180;
  const dLon = (lon2 - lon1) * Math.PI / 180;
  const a =
    Math.sin(dLat / 2) * Math.sin(dLat / 2) +
    Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
    Math.sin(dLon / 2) * Math.sin(dLon / 2);
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  return R * c;
}

function goToCurrentLocation() {
  uni.showLoading({
    title: '获取位置中...',
  });
  uni.getLocation({
    type: 'wgs84',
    success: (res) => {
      uni.hideLoading();
      myLocation.value = [res.longitude, res.latitude];
      currentLocation.value = myLocation.value;
      mapCtx.moveToLocation({
        latitude: myLocation.value[1],
        longitude: myLocation.value[0],
      });
    },
    fail: (err) => {
      uni.hideLoading();
      console.log(err);
      alert({
        title: '获取位置失败',
        content: '请检查是否开启定位权限',
      });
    },
  });
}
function getDistance(item: RouteInfo['items'][number]): string {
  const [lng, lat] = myLocation.value;
  const meters = getDistanceMeters(lng, lat, item.scenicSpot.longitude, item.scenicSpot.latitude);
  if (meters < 100) return '一百米内';
  if (meters < 1000) return `${Math.round(meters / 100) * 100}米`;
  return `${Math.round(meters / 1000)}km`;
}
function openLocation(item: RouteInfo['items'][number]) {
  uni.openLocation({
    latitude: item.scenicSpot.latitude,
    longitude: item.scenicSpot.longitude,
  });
}

/**
 * 腾讯地图 polyline 解压并转为地图组件 points
 * 文档：https://lbs.qq.com/service/webService/webServiceGuide/route/webServiceRoute#8
 * 格式：[坐标1纬度, 坐标1经度, 坐标2纬度, 坐标2经度, ...]，首点为原始坐标，后续为前向差分压缩
 */
function polylineToPoints(encoded: number[]): { longitude: number; latitude: number }[] {
  if (!encoded?.length) return [];
  const coors = encoded.slice();
  for (let i = 2; i < coors.length; i++) {
    coors[i] = coors[i - 2] + coors[i] / 1000000;
  }
  const points: { longitude: number; latitude: number }[] = [];
  for (let i = 0; i + 1 < coors.length; i += 2) {
    points.push({ latitude: coors[i], longitude: coors[i + 1] });
  }
  return points;
}
/** 从 transit 的 steps 中收集所有 polyline（步行段 + 每条公交/地铁线路的 polyline） */
function collectTransitPolylines(transitData: RouteInfo['items'][0]['toNextRoute']['transit']): number[][] {
  const result: number[][] = [];
  if (!transitData?.steps?.length) return result;
  for (const step of transitData.steps) {
    if (step.mode === 'WALKING' && step.polyline?.length) {
      result.push(step.polyline);
    } else if (step.mode === 'TRANSIT' && step.lines?.length) {
      for (const line of step.lines) {
        if (line.polyline?.length) result.push(line.polyline);
      }
    }
  }
  return result;
}
/** 折线说明文案（用于地图 segmentTexts，不含 emoji） */
function getSegmentLabel(way: RouteToNextBestWay, atDay: number, duration?: number): string {
  const wayName = { driving: '驾车', walking: '步行', bicycling: '骑行', ebicycling: '电动车', transit: '公交' }[way];
  const dur = duration != null ? ` 约${formatDuration(duration)}` : '';
  return `第${atDay}天 ${wayName}${dur}`;
}
function getSegmentTransitLabel(transitData: RouteInfo['items'][0]['toNextRoute']['transit'], index: number): string {
  if (!transitData?.steps?.length) return `公交路段${index + 1}`;

  let segIndex = 0;
  for (const step of transitData.steps) {
    if (step.mode === 'WALKING') {
      if (!step.polyline?.length) continue;
      const current = segIndex++;
      if (current !== index) continue;

      const d = step.distance != null ? formatDistance(step.distance) : '';
      const t = step.duration != null ? formatDuration(step.duration) : '';
      if (d && t) return `步行 ${d}·约${t}`;
      if (d) return `步行 ${d}`;
      if (t) return `步行 约${t}`;
      return '步行';
    }

    if (step.mode === 'TRANSIT') {
      for (const line of (step.lines || [])) {
        if (!line.polyline?.length) continue;
        const current = segIndex++;
        if (current !== index) continue;

        const vehicle = (line.vehicle || '').toUpperCase();
        const vehicleName =
          vehicle === 'BUS' ? '公交' :
          vehicle === 'SUBWAY' ? '地铁' :
          vehicle === 'RAIL' ? '火车' :
          '线路';

        const title = line.title ? `${vehicleName} ${line.title}` : vehicleName;
        const fromTo = (line.geton?.title && line.getoff?.title) ? ` ${line.geton.title}→${line.getoff.title}` : '';
        const stations = line.station_count != null ? `·${line.station_count}站` : '';
        const d = line.distance != null ? `·${formatDistance(line.distance)}` : '';
        const t = line.duration != null ? `·约${formatDuration(line.duration)}` : '';
        return `${title}${fromTo}${stations}${d}${t}`.trim();
      }
    }
  }

  return `公交路段${index + 1}`;
}
/** 根据 toNextRoute 与 toNextBestWay 生成地图 polyline 数组（含 segmentTexts 折线说明） */
function buildPolylineFromRouteInfo(info: RouteInfo) {
  const segments: Array<{
    points: { longitude: number; latitude: number }[];
    color: string;
    width: number;
    level: string;
    segmentTexts?: { name: string; startIndex: number; endIndex: number }[];
    textStyle?: { textColor: string; strokeColor: string; fontSize: number };
  }> = [];
  const items = info.items;
  const textStyle = { textColor: '#ffffff', strokeColor: '#000000', fontSize: 12 };

  for (let i = 0; i < items.length - 1; i++) {
    const item = items[i];
    const way: RouteToNextBestWay = (userPreferredWay.value || item.toNextBestWay || 'driving') as RouteToNextBestWay;
    const routeData = item.toNextRoute?.[way];
    const color = routeColors[i]; //如果显示天数则用 item.atDay
    const width = 6;

    if (way === 'transit') {
      const transitData = item.toNextRoute?.transit;
      const polylines = collectTransitPolylines(transitData!);
      const label = getSegmentLabel('transit', item.atDay, transitData?.duration);
      for (let k = 0; k < polylines.length; k++) {
        const points = polylineToPoints(polylines[k]);
        if (points.length < 2) continue;
        const segmentTexts = k === 0 ? [
          { name: label, startIndex: 0, endIndex: points.length - 1 }
        ] : [
          { name: getSegmentTransitLabel(transitData!, k), startIndex: 0, endIndex: points.length - 1 }
        ];
        segments.push({ 
          points, 
          color, 
          width, 
          level: 'aboveroads', 
          segmentTexts, 
          textStyle: segmentTexts ? textStyle : undefined 
        });
      }
    } else {
      const encoded = (routeData as { polyline?: number[]; duration?: number })?.polyline;
      if (!encoded?.length) continue;
      const points = polylineToPoints(encoded);
      if (points.length < 2) continue;
      const duration = (routeData as { duration?: number })?.duration;
      const segmentTexts = [{ name: getSegmentLabel(way, item.atDay, duration), startIndex: 0, endIndex: points.length - 1 }];
      segments.push({ 
        points, 
        color, 
        width, 
        level: 'aboveroads',
        segmentTexts, 
        textStyle 
      });
    }
  }
  polyline.value = segments;
}

function onMarkerClick(item: any) {
  console.log(item);
}
function onItemClick(item: RouteInfo['items'][number]) {
  currentLocation.value = [item.scenicSpot.longitude, item.scenicSpot.latitude];
  uni.setStorageSync('travelRouteItem', item.scenicSpot);
  navTo('./details');
}
function focusRoute(item: RouteInfo['items'][number]) {
  bottomSheetRef.value?.setDragHeightToMin();
  currentLocation.value = [item.scenicSpot.longitude, item.scenicSpot.latitude];
}
async function loadRoute() {
  await waitTimeOut(500);
  travalDetail.value = await TravalContent.getTravalList(querys.value.id);  
  try {
    routeInfo.value = await RouteApi.getRouteInfo(querys.value.id);
  } catch (error) {
    if (error instanceof RequestApiError) {
      if (error.code == 404) {
        alert({
          title: '路线不存在',
          content: '路线未生成，请在服务器端生成路线，ID: ' + querys.value.id,
        });
        return;
      }
    }
  }
  await loadMap();
}
async function loadMap() {
  if (!routeInfo.value) return;

  // 生成标记点
  const tempMarkers = routeInfo.value.items
    .map((p, index) => ({
      latitude: p.scenicSpot.latitude,
      longitude: p.scenicSpot.longitude,
      iconPath: getMakerImage(index),
      callout: {
        content: p.scenicSpot.name,
        color: "#ffffff",
        fontSize: 15,
        borderRadius: 15,
        padding: "10",
        bgColor: routeColors[index],
        display: "ALWAYS",
      },
      width: 40,
      height: 40,
    }));

  // 根据 toNextRoute 绘制路线
  buildPolylineFromRouteInfo(routeInfo.value);

  await waitTimeOut(500);

  markers.value = tempMarkers;

  mapCtx.includePoints({
    points: tempMarkers.map(p => ({
      latitude: p.latitude,
      longitude: p.longitude,
    })),
    padding: [40, 40, 120, 40],
  });
}

watch(userPreferredWay, () => {
  loadMap()
});
onMounted(() => {
  currentLocation.value = [AppCofig.defaultLonLat[0], AppCofig.defaultLonLat[1]];
  uni.getLocation({
    type: 'wgs84',
    success: (res) => {
      myLocation.value = [res.longitude, res.latitude];
      currentLocation.value = [res.longitude, res.latitude];
      currentLocationGeted.value = true;
    },
    fail: (err) => {
      console.log(err);
    },
  });
});

</script>

<style lang="scss">
.travel-route {
  position: relative;
  width: 100%;
  height: 100vh;

  map {
    width: 100%;
    height: 100%;
  }
}
</style>