import * as Cesium from 'cesium';
import { type Viewer } from 'cesium';
import { eciToEcf, gstime, propagate, twoline2satrec } from 'satellite.js';

/**
 * 未来2小时内每30秒的位置
 */
export async function demo_02_Track(
  viewer: Viewer,
  tle = `DEMO [测试]
1 62879U 25024A   25062.93300820  .00003305  00000+0  21841-4 0  9995
2 62879  42.9977 257.3937 0001725 269.2925  90.7748 15.77864921  5143`,
) {
  // 解析TLE数据
  const lines = tle.split('\n') as [string, string, string];
  const satelliteName = lines[0]?.trim();
  const satrec = twoline2satrec(lines[1], lines[2]);

  // 生成随机颜色
  const satelliteColor = Cesium.Color.fromRandom({ alpha: 1 });
  const pathColor = Cesium.Color.fromRandom({ alpha: 1 });
  const orbitColor = Cesium.Color.fromRandom({ alpha: 1 });
  const coverageColor = Cesium.Color.fromRandom({ alpha: 1 });

  // 创建卫星实体
  const satelliteEntity = viewer.entities.add({
    id: `${satelliteName}-satellite`,
    label: {
      fillColor: Cesium.Color.WHITE,
      font: '14pt sans-serif',
      outlineColor: Cesium.Color.BLACK,
      outlineWidth: 2,
      pixelOffset: new Cesium.Cartesian2(0, -10),
      style: Cesium.LabelStyle.FILL_AND_OUTLINE,
      text: satelliteName,
      verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
    },
    name: `${satelliteName} Satellite`,
    // 卫星轨迹
    path: {
      material: new Cesium.PolylineGlowMaterialProperty({
        color: pathColor,
        glowPower: 0.2,
      }),
      resolution: 1,
      width: 2,
    },
    // 使用简单点图形表示卫星
    point: {
      color: satelliteColor,
      outlineColor: Cesium.Color.WHITE,
      outlineWidth: 2,
      pixelSize: 10,
    },
  });

  // 计算并绘制卫星轨迹
  const totalSeconds = 60 * 60 * 2; // 2小时的轨迹
  const timeStepInSeconds = 30; // 每30秒一个点
  const startTime = Cesium.JulianDate.fromDate(new Date());
  const endTime = Cesium.JulianDate.addSeconds(startTime, totalSeconds, new Cesium.JulianDate());

  // 设置时钟范围
  viewer.clock.startTime = startTime.clone();
  viewer.clock.stopTime = endTime.clone();
  viewer.clock.currentTime = startTime.clone();
  viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP;
  viewer.clock.multiplier = 30; // 30倍速播放

  // 设置时间轴范围
  viewer.timeline.zoomTo(startTime, endTime);

  // 用于存储卫星位置的样本集合
  const positionProperty = new Cesium.SampledPositionProperty();

  // 用于存储轨道点的数组（用于显示完整轨道）
  const orbitPositions: Cesium.Cartesian3[] = [];

  // 保存卫星高度数据，用于覆盖范围计算
  // const satelliteAltitude = 550_000; // 默认高度为550公里

  // 计算轨道上的点
  for (let index = 0; index <= totalSeconds; index += timeStepInSeconds) {
    const time = Cesium.JulianDate.addSeconds(startTime, index, new Cesium.JulianDate());
    const jsDate = Cesium.JulianDate.toDate(time);

    // 计算卫星位置
    const positionAndVelocity = propagate(satrec, jsDate);
    if (positionAndVelocity === null) {
      console.error('Error calculating satellite position');
    } else {
      const gmst = gstime(jsDate);
      const position = eciToEcf(positionAndVelocity.position, gmst);

      // 转换为Cesium坐标（单位：米）
      const cesiumPosition = new Cesium.Cartesian3(position.x * 1000, position.y * 1000, position.z * 1000);

      // 计算卫星高度
      // const cartographic = Cesium.Cartographic.fromCartesian(cesiumPosition);
      // satelliteAltitude = cartographic.height;

      // 保存位置用于绘制完整轨道
      orbitPositions.push(cesiumPosition);

      // 添加位置样本
      positionProperty.addSample(time, cesiumPosition);
    }
  }

  // 添加完整轨道线
  viewer.entities.add({
    id: `${satelliteName}-orbit`,
    name: `${satelliteName} Full Orbit`,
    polyline: {
      clampToGround: false,
      material: new Cesium.PolylineDashMaterialProperty({
        color: orbitColor,
        dashLength: 8,
      }),
      positions: orbitPositions,
      width: 1,
    },
  });

  // 设置卫星的位置
  satelliteEntity.position = positionProperty;
  satelliteEntity.orientation = new Cesium.VelocityOrientationProperty(positionProperty);

  // 添加卫星覆盖范围
  // Starlink 卫星通常覆盖范围以锥形方式向地面投射
  // 创建一个椭球体来表示卫星的覆盖范围
  const coverageAngle = 45; // 覆盖角度（度）

  // satelliteAltitude * Math.tan(Cesium.Math.toRadians(coverageAngle));

  // 创建覆盖范围实体
  viewer.entities.add({
    ellipsoid: {
      material: coverageColor.withAlpha(0.2),
      outline: true,
      outlineColor: coverageColor.withAlpha(0.8),
      radii: new Cesium.CallbackProperty(() => {
        const position = satelliteEntity.position?.getValue(viewer.clock.currentTime);
        if (!position) return new Cesium.Cartesian3(10_000, 10_000, 10_000);

        // 获取当前卫星高度
        const cartographic = Cesium.Cartographic.fromCartesian(position);
        const height = cartographic.height;

        // 计算覆盖范围半径 (基于锥角)
        const coverageRadius = height * Math.tan(Cesium.Math.toRadians(coverageAngle));

        // 椭球体形状: xy平面为圆形基底，z轴方向为高度
        return new Cesium.Cartesian3(coverageRadius, coverageRadius, height / 2);
      }, false),
      slicePartitions: 24,
      stackPartitions: 16,
    },
    id: `${satelliteName}-coverage`,
    name: `${satelliteName} Coverage`,
    orientation: new Cesium.CallbackProperty(() => {
      // 确保椭球体始终指向地球中心
      const position = satelliteEntity.position?.getValue(viewer.clock.currentTime);
      if (!position) return Cesium.Transforms.eastNorthUpToFixedFrame(new Cesium.Cartesian3());

      // 计算从卫星到地球中心的方向
      Cesium.Cartesian3.normalize(Cesium.Cartesian3.negate(position, new Cesium.Cartesian3()), new Cesium.Cartesian3());

      return Cesium.Transforms.headingPitchRollQuaternion(position, new Cesium.HeadingPitchRoll(0, Math.PI, 0));
    }, false),
    position: positionProperty,
  });

  // 添加地面覆盖范围投影
  viewer.entities.add({
    ellipse: {
      granularity: Cesium.Math.toRadians(1),
      height: 0,
      material: coverageColor.withAlpha(0.2),
      outline: true,
      outlineColor: coverageColor.withAlpha(0.8),
      outlineWidth: 2,
      semiMajorAxis: new Cesium.CallbackProperty(() => {
        const satPosition = satelliteEntity.position?.getValue(viewer.clock.currentTime);
        if (!satPosition) return 10_000;

        // 计算卫星高度
        const cartographic = Cesium.Cartographic.fromCartesian(satPosition);
        // 根据高度和覆盖角度计算地面覆盖半径
        return cartographic.height * Math.tan(Cesium.Math.toRadians(coverageAngle));
      }, false),
      semiMinorAxis: new Cesium.CallbackProperty(() => {
        const satPosition = satelliteEntity.position?.getValue(viewer.clock.currentTime);
        if (!satPosition) return 10_000;

        // 计算卫星高度
        const cartographic = Cesium.Cartographic.fromCartesian(satPosition);
        // 根据高度和覆盖角度计算地面覆盖半径
        return cartographic.height * Math.tan(Cesium.Math.toRadians(coverageAngle));
      }, false),
    },
    id: `${satelliteName}-coverage-ground`,
    name: `${satelliteName} Ground Coverage`,
    position: new Cesium.CallbackPositionProperty(() => {
      const satPosition = satelliteEntity.position?.getValue(viewer.clock.currentTime);
      if (!satPosition) return new Cesium.Cartesian3();

      // 计算卫星在地表的投影点
      const cartographic = Cesium.Cartographic.fromCartesian(satPosition);
      return Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, 0);
    }, false),
  });

  // - https://community.cesium.com/t/entity-viewfrom-property-example/2299/3
  // - https://github.com/CesiumGS/cesium/issues/8900#issuecomment-638114149
  //   - which is normal from a bird's eye view. But after setting it as the trackedEntity, it behaves abnormally.
  // 设置相机自动跟踪卫星
  // viewer.trackedEntity = satelliteEntity;

  // 开始动画
  viewer.clock.shouldAnimate = true;
}
