package planet

import (
	. "b612.me/astro/tools"
	"math"
)

// WherePlanet returns the full VSOP result for the selected body and coordinate.
func WherePlanet(xt, zn int, jd float64) float64 {
	return WherePlanetN(xt, zn, jd, -1)
}

// WherePlanetN returns the VSOP result for the selected body and coordinate.
// When n < 0, all terms are used. Otherwise n follows the original eph0.js
// truncation semantics: keep roughly n principal terms from the 0th order
// series and scale higher-order series proportionally.
func WherePlanetN(xt, zn int, jd float64, n int) float64 {
	sata := 0
	if xt == -1 {
		xt = 0
		sata = 1
	}

	rad := 180.0000 * 3600.0000 / math.Pi
	t := (jd - 2451545) / 36525.0000
	t /= 10 // 转为儒略千年数

	body := planetViews()[xt]
	coord := body.coords[zn]
	baseOrderTerms := len(coord.orders[0])

	tn := float64(1)
	var v float64
	for i, series := range coord.orders {
		seriesLength := len(series)
		if seriesLength == 0 {
			continue
		}

		termLimit := seriesLength
		if n >= 0 {
			termLimit = int(math.Floor(3*float64(n)*float64(seriesLength)/float64(baseOrderTerms) + 0.5))
			if i != 0 {
				termLimit += 3
			}
			if termLimit > seriesLength {
				termLimit = seriesLength
			}
		}

		var c float64
		for j := 0; j < termLimit; j += 3 {
			c += series[j] * math.Cos(series[j+1]+t*series[j+2])
		}
		v += c * tn
		tn *= t
	}
	v /= body.scale

	if xt == 0 { // 地球
		t2 := t * t
		t3 := t2 * t // 千年数的各次方
		if zn == 0 {
			v += (-0.0728 - 2.7702*t - 1.1019*t2 - 0.0996*t3) / rad
		} else if zn == 1 {
			v += (+0.0000 + 0.0004*t + 0.0004*t2 - 0.0026*t3) / rad
		} else if zn == 2 {
			v += (-0.0020 + 0.0044*t + 0.0213*t2 - 0.0250*t3) / 1000000
		}
	} else { // 其它行星
		planetCorrections := []float64{
			// 经(角秒), 纬(角秒), 距(10-6AU)
			-0.08631, +0.00039, -0.00008, // 水星
			-0.07447, +0.00006, +0.00017, // 金星
			-0.07135, -0.00026, -0.00176, // 火星
			-0.20239, +0.00273, -0.00347, // 木星
			-0.25486, +0.00276, +0.42926, // 土星
			+0.24588, +0.00345, -14.46266, // 天王星
			-0.95116, +0.02481, +58.30651, // 海王星
		}
		dv := planetCorrections[(xt-1)*3+zn]
		if zn == 0 {
			v += -3 * t / rad
		}
		if zn == 2 {
			v += dv / 1000000
		} else {
			v += dv / rad
		}
	}

	if zn == 0 && xt == 0 {
		if sata != 0 {
			return Limit360(v * 180 / math.Pi)
		}
		return Limit360(v*180/math.Pi + 180)
	}
	if zn == 1 && xt == 0 {
		if sata != 0 {
			return v * 180 / math.Pi
		}
		return -(v * 180 / math.Pi)
	}
	if xt > 0 && zn == 1 {
		return v * 180 / math.Pi
	}
	if xt > 0 && zn == 0 {
		return Limit360(v * 180 / math.Pi)
	}
	return v
}
