package webui

import (
	"ewdetect/comms"
	"ewdetect/config"
	"ewdetect/stations"
	"ewdetect/utils"
	"fmt"
	"slices"
	"time"

	sm "github.com/flopp/go-staticmaps"
	"github.com/fogleman/gg"
	"github.com/gofiber/fiber/v3"
	"github.com/golang/geo/s2"
	"github.com/rs/zerolog/log"

	"github.com/go-echarts/go-echarts/v2/charts"
	"github.com/go-echarts/go-echarts/v2/opts"
	"github.com/go-echarts/go-echarts/v2/types"
)

// generate random data for line chart
func generateTimeSeries(connection, key string) []string {
	head := (*comms.Connections[connection].Heads)[key]
	headLoops := (*comms.Connections[connection].HeadLoops)[key]
	items := make([]string, 0)
	sampleRate := float64((*stations.Stations[connection])[key].SampleRate)
	var startTime time.Time
	for i := range config.BufferSize {
		startTime = (*comms.Connections[connection].StartTime)
		startTime = startTime.Add(time.Duration(1e9 * float64(i) / sampleRate))
		startTime = startTime.Add(time.Duration(1e9 * float64((headLoops-1)*config.BufferSize) / sampleRate))
		if i <= head {
			startTime = startTime.Add(time.Duration(1e9 * float64(config.BufferSize) / sampleRate))
		}
		items = append(items, startTime.Format("2006-01-02T15:04:05.000"))
	}
	return items
}

func generateLineItems(connection, key string) []opts.LineData {
	items := make([]opts.LineData, 0)
	//fmt.Println(comms.Buffers["MHGZ"])
	for _, b := range *(*comms.Connections[connection].Buffers)[key] {
		curr_b := b

		if _, ok := stations.Stations[connection]; ok {
			if (*stations.Stations[connection])[key].Calibrated {
				curr_b = curr_b - (*stations.Stations[connection])[key].DC
				curr_b = curr_b * 1024 / (*stations.Stations[connection])[key].NoiseFloor
			}
		}
		items = append(items, opts.LineData{Value: b})
	}
	return items
}

func chart(c fiber.Ctx) error {
	log.Debug().Msg("Generating chart view")
	c.Type(".html")
	count := 0
	for connection := range comms.Connections {
		for _ = range *comms.Connections[connection].Buffers {
			count++
		}
	}
	if config.Debug {
		log.Debug().Msg("Generating debug station map")
		ctx := sm.NewContext()
		ctx.SetSize(config.DebugResolution, config.DebugResolution)
		for connection := range comms.Connections {
			if _, ok := stations.Stations[connection]; ok {
				for key := range *comms.Connections[connection].Buffers {
					ctx.AddObject(
						sm.NewMarker(
							s2.LatLngFromDegrees((*stations.Stations[connection])[key].Lat, (*stations.Stations[connection])[key].Lon),
							utils.ColorFromHash(connection),
							16.0,
						),
					)
				}
			} else {
				log.Warn().Str("connection", connection).Msg("Missing station metadata")
			}
		}
		ctx.OverrideAttribution(fmt.Sprintf("%s - EWDetect - Louis \"OnTake\" Dalibard - 2025.", ctx.Attribution()))

		img, err := ctx.Render()
		if err != nil {
			log.Fatal().Err(err).Msg("Failed to render debug map")
		}

		if err := gg.SavePNG("debug/station-map/stations.png", img); err != nil {
			log.Fatal().Err(err).Msg("Failed to save debug map")
		}
	}
	c.WriteString(fmt.Sprintf("<h1> Tracking %d stations</h1>", count))
	for connection := range comms.Connections {
		for key := range *comms.Connections[connection].Buffers {
			if slices.Contains(config.WebUITrackedStations, key) {
				// create a new line instance
				line := charts.NewLine()
				// set some global options like Title/Legend/ToolTip or anything else
				line.SetGlobalOptions(
					charts.WithInitializationOpts(opts.Initialization{Theme: types.ThemeWesteros}),
					charts.WithTitleOpts(opts.Title{
						Title:    fmt.Sprintf("%s (%s)", (*stations.Stations[connection])[key].Name, key),
						Subtitle: fmt.Sprintf("%0.4f, %0.4f", (*stations.Stations[connection])[key].Lat, (*stations.Stations[connection])[key].Lon),
					}))

				// Put data into instance
				line.SetXAxis(generateTimeSeries(connection, key))
				line.AddSeries(key, generateLineItems(connection, key))
				line.SetSeriesOptions(charts.WithLineChartOpts(opts.LineChart{Smooth: opts.Bool(false)}))
				line.Render(c)
			}
		}
	}
	return nil
}

func Init() {
	log.Info().Msg("Initializing WebUI")
	// Initialize a new Fiber app
	app := fiber.New()

	// Define a route for the GET method on the root path '/'
	app.Get("/", chart)

	// Start the server on port 3000
	log.Info().Msg("Starting WebUI server on port 3000")
	if err := app.Listen(":3000"); err != nil {
		log.Fatal().Err(err).Msg("Failed to start WebUI server")
	}
}
