package producer

import (
	"encoding/xml"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/duke-git/lancet/v2/mathutil"
)

// 定义与XML结构对应的Go结构体
type ProductMeta struct {
	XMLName         xml.Name `xml:"ProductMeta"`
	Satellite       string   `xml:"Satellite"`
	Sensor          string   `xml:"Sensor"`
	ProductID       string   `xml:"ProductID"`
	ProductLevel    string   `xml:"ProductLevel"`
	OutputFormat    string   `xml:"OutputFormat"`
	ProductGenTime  string   `xml:"ProductGenTime"`
	StartTime       string   `xml:"StartTime"`
	EndTime         string   `xml:"EndTime"`
	CentreTime      string   `xml:"CentreTime"`
	Bands           int      `xml:"Bands"`
	CentreLocation  Location `xml:"CentreLocation"`
	Corners         Corners  `xml:"Corners"`
	SunAzimuth      float64  `xml:"SunAzimuth"`
	SunElevation    float64  `xml:"SunElevation"`
	SatAzimuth      float64  `xml:"SatAzimuth"`
	SatElevation    float64  `xml:"SatElevation"`
	Gsd             float64  `xml:"Gsd"`
	CloudRate       float64  `xml:"CloudRate"`
	Roll            float64  `xml:"Roll"`
	Pitch           float64  `xml:"Pitch"`
	Yaw             float64  `xml:"Yaw"`
	SatPosX         float64  `xml:"SatPosX"`
	SatPosY         float64  `xml:"SatPosY"`
	SatPosZ         float64  `xml:"SatPosZ"`
	Width           int      `xml:"Width"`
	Height          int      `xml:"Height"`
	DataSize        int64    `xml:"DataSize"`
	MapProjection   string   `xml:"MapProjection"`
	EarthEllipsoid  string   `xml:"EarthEllipsoid"`
	UtmZone         int      `xml:"UtmZone"`
	GainLevel       int      `xml:"GainLevel"`
	IntegratedLevel int      `xml:"IntegratedLevel"`
	IntegratedTime  float64  `xml:"IntegratedTime"`
}

type Location struct {
	Longitude float64 `xml:"Longitude"`
	Latitude  float64 `xml:"Latitude"`
}

type Corners struct {
	UpperLeft  Location `xml:"UpperLeft"`
	UpperRight Location `xml:"UpperRight"`
	LowerRight Location `xml:"LowerRight"`
	LowerLeft  Location `xml:"LowerLeft"`
}

func (corners Corners) Extend() (lng1, lat1, lng2, lat2 float64) {
	lng1 = mathutil.Min(corners.UpperLeft.Longitude, corners.LowerLeft.Longitude,
		corners.UpperRight.Longitude, corners.LowerRight.Longitude)
	lng2 = mathutil.Max(corners.UpperLeft.Longitude, corners.LowerLeft.Longitude,
		corners.UpperRight.Longitude, corners.LowerRight.Longitude)
	lat1 = mathutil.Max(corners.UpperLeft.Latitude, corners.LowerLeft.Latitude,
		corners.UpperRight.Latitude, corners.LowerRight.Latitude)
	lat2 = mathutil.Min(corners.UpperLeft.Latitude, corners.LowerLeft.Latitude,
		corners.UpperRight.Latitude, corners.LowerRight.Latitude)
	return
}

func (r *Registrator) makeProductMeta(scene *Scene) *ProductMeta {
	meta := &ProductMeta{
		Satellite:      "SJY01",
		Sensor:         "PMS",
		OutputFormat:   "GTiff",
		ProductGenTime: time.Now().Format("2006-01-02T15:04:05"),
		Width:          scene.Width,
		Height:         scene.Height,
		MapProjection:  "GEOGRAPHIC",
		EarthEllipsoid: "WGS_84",
		ProductLevel:   "L1A",
		UtmZone:        -1,
		GainLevel:      6,
	}

	switch scene.Type {
	case "PAN":
		meta.Gsd = 1.3
		meta.Bands = 1
	case "MSS":
		meta.Gsd = 5.2
		meta.Bands = 4
	}

	meta.ProductID = filepath.Base(strings.TrimSuffix(scene.Tiff, ".tiff"))
	startTime, centerTime, endTime := r.SceneImageTime(scene)
	meta.StartTime = startTime.Format("2006-01-02T15:04:05.000")
	meta.EndTime = endTime.Format("2006-01-02T15:04:05.000")
	meta.CentreTime = centerTime.Format("2006-01-02T15:04:05.000")

	return meta
}

func writeProductMeta(productMeta *ProductMeta, filename string) error {
	output, err := xml.MarshalIndent(productMeta, "", "    ")
	if err != nil {
		return err
	}

	err = os.WriteFile(filename, output, 0644)
	if err != nil {
		return err
	}

	return nil
}

func ParseProductMeta(filename string) (*ProductMeta, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	var meta ProductMeta
	err = xml.NewDecoder(f).Decode(&meta)
	if err != nil {
		return nil, err
	}

	return &meta, nil
}
