package server

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"time"
	"weatherstation/internal/config"
	"weatherstation/internal/database"
	"weatherstation/pkg/types"

	"github.com/gin-gonic/gin"
)

// newGinEngine 统一创建和配置 Gin 引擎（模板/静态/路由）
func newGinEngine() *gin.Engine {
	// 设置Gin模式
	gin.SetMode(gin.ReleaseMode)

	// 创建Gin引擎
	r := gin.Default()

	// 以可执行文件所在目录为基准查找资源（优先），其次回退到相对路径
	exe, _ := os.Executable()
	exeDir := filepath.Dir(exe)

	// 模板目录
	candidatesTpl := []string{
		filepath.Join(exeDir, "templates", "*"),
		filepath.Join(exeDir, "..", "templates", "*"),
		filepath.Join("templates", "*"),
		filepath.Join("..", "templates", "*"),
	}
	var tplGlob string
	for _, c := range candidatesTpl {
		base := filepath.Dir(c)
		if st, err := os.Stat(base); err == nil && st.IsDir() {
			tplGlob = c
			break
		}
	}
	if tplGlob == "" {
		tplGlob = filepath.Join("templates", "*")
	}
	r.LoadHTMLGlob(tplGlob)

	// 静态目录
	candidatesStatic := []string{
		filepath.Join(exeDir, "static"),
		filepath.Join(exeDir, "..", "static"),
		"./static",
		"../static",
	}
	staticDir := candidatesStatic[0]
	for _, c := range candidatesStatic {
		if st, err := os.Stat(c); err == nil && st.IsDir() {
			staticDir = c
			break
		}
	}
	r.Static("/static", staticDir)

	// 前端SPA（Angular）静态资源与路由回退
	// 构建产物目录（可执行目录优先）
	r.GET("/ui/*filepath", func(c *gin.Context) {
		// 物理文件优先，否则回退到 index.html（支持前端路由）
		requested := c.Param("filepath")
		if requested == "" || requested == "/" {
			// index.html
			candidates := []string{
				filepath.Join(exeDir, "core/frontend/dist/ui/index.html"),
				filepath.Join(exeDir, "..", "core/frontend/dist/ui/index.html"),
				"./core/frontend/dist/ui/index.html",
				"../core/frontend/dist/ui/index.html",
			}
			for _, p := range candidates {
				if _, err := os.Stat(p); err == nil {
					c.File(p)
					return
				}
			}
			c.String(http.StatusNotFound, "ui not found")
			return
		}
		// 选择 baseDir
		baseDirCandidates := []string{
			filepath.Join(exeDir, "core/frontend/dist/ui"),
			filepath.Join(exeDir, "..", "core/frontend/dist/ui"),
			"./core/frontend/dist/ui",
			"../core/frontend/dist/ui",
		}
		baseDir := baseDirCandidates[0]
		for _, d := range baseDirCandidates {
			if st, err := os.Stat(d); err == nil && st.IsDir() {
				baseDir = d
				break
			}
		}
		full := baseDir + requested
		if _, err := os.Stat(full); err == nil {
			c.File(full)
			return
		}
		c.File(filepath.Join(baseDir, "index.html"))
	})

	// 路由设置
	r.GET("/", indexHandler)
	r.GET("/bigscreen", bigscreenHandler)
	r.GET("/radar/nanning", radarNanningHandler)
	r.GET("/radar/guangzhou", radarGuangzhouHandler)
	r.GET("/radar/panyu", radarPanyuHandler)
	r.GET("/radar/haizhu", radarHaizhuHandler)
	r.GET("/radar/imdroid", imdroidRadarHandler)

	// API路由组
	api := r.Group("/api")
	{
		api.GET("/system/status", systemStatusHandler)
		api.GET("/stations", getStationsHandler)
		api.GET("/data", getDataHandler)
		api.GET("/forecast", getForecastHandler)
		api.GET("/radar/latest", latestRadarTileHandler)
		api.GET("/radar/at", radarTileAtHandler)
		api.GET("/radar/nearest", nearestRadarTileHandler)
		api.GET("/radar/times", radarTileTimesHandler)
		// multi-tiles at same dt
		api.GET("/radar/tiles_at", radarTilesAtHandler)
		api.GET("/radar/weather_latest", latestRadarWeatherHandler)
		api.GET("/radar/weather_at", radarWeatherAtHandler)
		api.GET("/radar/weather_aliases", radarWeatherAliasesHandler)
		api.GET("/radar/aliases", radarConfigAliasesHandler)
		api.GET("/radar/weather_nearest", radarWeatherNearestHandler)
		// Rain CMPA hourly tiles
		api.GET("/rain/latest", latestRainTileHandler)
		api.GET("/rain/at", rainTileAtHandler)
		api.GET("/rain/nearest", nearestRainTileHandler)
		api.GET("/rain/times", rainTileTimesHandler)
		api.GET("/rain/tiles_at", rainTilesAtHandler)
	}
	return r
}

// StartGinServer 启动Gin Web服务器（配置端口）
func StartGinServer() error {
	r := newGinEngine()
	// 获取配置的Web端口
	port := config.GetConfig().Server.WebPort
	if port == 0 {
		port = 10003 // 默认端口
	}
	fmt.Printf("Gin Web服务器启动，监听端口 %d...\n", port)
	return r.Run(fmt.Sprintf(":%d", port))
}

// StartGinServerOn 在指定端口启动一个独立的 Gin 实例
func StartGinServerOn(port int) error {
	r := newGinEngine()
	if port <= 0 {
		port = 10008
	}
	fmt.Printf("Gin Web服务器启动，监听端口 %d...\n", port)
	return r.Run(fmt.Sprintf(":%d", port))
}

// StartBigscreenServerOn 在指定端口启动以大屏为根路径的 Gin 实例（/ -> bigscreen）
func StartBigscreenServerOn(port int) error {
	// 独立构建一个以大屏为根路径的引擎，避免与普通引擎重复注册根路由
	gin.SetMode(gin.ReleaseMode)
	r := gin.Default()

	exe, _ := os.Executable()
	exeDir := filepath.Dir(exe)

	// 模板
	candidatesTpl := []string{
		filepath.Join(exeDir, "templates", "*"),
		filepath.Join(exeDir, "..", "templates", "*"),
		filepath.Join("templates", "*"),
		filepath.Join("..", "templates", "*"),
	}
	var tplGlob string
	for _, c := range candidatesTpl {
		base := filepath.Dir(c)
		if st, err := os.Stat(base); err == nil && st.IsDir() {
			tplGlob = c
			break
		}
	}
	if tplGlob == "" {
		tplGlob = filepath.Join("templates", "*")
	}
	r.LoadHTMLGlob(tplGlob)

	// 静态资源
	candidatesStatic := []string{
		filepath.Join(exeDir, "static"),
		filepath.Join(exeDir, "..", "static"),
		"./static",
		"../static",
	}
	staticDir := candidatesStatic[0]
	for _, c := range candidatesStatic {
		if st, err := os.Stat(c); err == nil && st.IsDir() {
			staticDir = c
			break
		}
	}
	r.Static("/static", staticDir)

	// SPA 资源
	r.GET("/ui/*filepath", func(c *gin.Context) {
		requested := c.Param("filepath")
		if requested == "" || requested == "/" {
			candidates := []string{
				filepath.Join(exeDir, "core/frontend/dist/ui/index.html"),
				filepath.Join(exeDir, "..", "core/frontend/dist/ui/index.html"),
				"./core/frontend/dist/ui/index.html",
				"../core/frontend/dist/ui/index.html",
			}
			for _, p := range candidates {
				if _, err := os.Stat(p); err == nil {
					c.File(p)
					return
				}
			}
			c.String(http.StatusNotFound, "ui not found")
			return
		}
		baseDirCandidates := []string{
			filepath.Join(exeDir, "core/frontend/dist/ui"),
			filepath.Join(exeDir, "..", "core/frontend/dist/ui"),
			"./core/frontend/dist/ui",
			"../core/frontend/dist/ui",
		}
		baseDir := baseDirCandidates[0]
		for _, d := range baseDirCandidates {
			if st, err := os.Stat(d); err == nil && st.IsDir() {
				baseDir = d
				break
			}
		}
		full := baseDir + requested
		if _, err := os.Stat(full); err == nil {
			c.File(full)
			return
		}
		c.File(filepath.Join(baseDir, "index.html"))
	})

	// 根路径 -> 大屏
	r.GET("/", bigscreenHandler)

	// API 路由
	api := r.Group("/api")
	{
		api.GET("/system/status", systemStatusHandler)
		api.GET("/stations", getStationsHandler)
		api.GET("/data", getDataHandler)
		api.GET("/forecast", getForecastHandler)
		api.GET("/radar/latest", latestRadarTileHandler)
		api.GET("/radar/at", radarTileAtHandler)
		api.GET("/radar/nearest", nearestRadarTileHandler)
		api.GET("/radar/times", radarTileTimesHandler)
		api.GET("/radar/tiles_at", radarTilesAtHandler)
		api.GET("/radar/weather_latest", latestRadarWeatherHandler)
		api.GET("/radar/weather_at", radarWeatherAtHandler)
		api.GET("/radar/weather_aliases", radarWeatherAliasesHandler)
		api.GET("/radar/aliases", radarConfigAliasesHandler)
		api.GET("/radar/weather_nearest", radarWeatherNearestHandler)
		api.GET("/rain/latest", latestRainTileHandler)
		api.GET("/rain/at", rainTileAtHandler)
		api.GET("/rain/nearest", nearestRainTileHandler)
		api.GET("/rain/times", rainTileTimesHandler)
		api.GET("/rain/tiles_at", rainTilesAtHandler)
	}

	if port <= 0 {
		port = 10008
	}
	fmt.Printf("Gin Bigscreen 服务器启动，监听端口 %d...\n", port)
	return r.Run(fmt.Sprintf(":%d", port))
}

// indexHandler 处理主页请求
func indexHandler(c *gin.Context) {
	data := types.PageData{
		Title:         "英卓气象站",
		ServerTime:    time.Now().Format("2006-01-02 15:04:05"),
		OnlineDevices: database.GetOnlineDevicesCount(database.GetDB()),
		TiandituKey:   "0c260b8a094a4e0bc507808812cefdac",
	}
	c.HTML(http.StatusOK, "index.html", data)
}

// bigscreenHandler 大屏演示页
func bigscreenHandler(c *gin.Context) {
	data := types.PageData{
		Title:         "英卓大屏",
		ServerTime:    time.Now().Format("2006-01-02 15:04:05"),
		OnlineDevices: database.GetOnlineDevicesCount(database.GetDB()),
		TiandituKey:   "0c260b8a094a4e0bc507808812cefdac",
	}
	c.HTML(http.StatusOK, "bigscreen.html", data)
}

// radarNanningHandler 南宁雷达站占位页
func radarNanningHandler(c *gin.Context) {
	data := types.PageData{
		Title:         "雷达页面",
		ServerTime:    time.Now().Format("2006-01-02 15:04:05"),
		OnlineDevices: database.GetOnlineDevicesCount(database.GetDB()),
		TiandituKey:   "0c260b8a094a4e0bc507808812cefdac",
	}
	c.HTML(http.StatusOK, "imdroid_radar.html", data)
}

// radarGuangzhouHandler 广州雷达站占位页
func radarGuangzhouHandler(c *gin.Context) {
	data := types.PageData{
		Title:         "雷达页面",
		ServerTime:    time.Now().Format("2006-01-02 15:04:05"),
		OnlineDevices: database.GetOnlineDevicesCount(database.GetDB()),
		TiandituKey:   "0c260b8a094a4e0bc507808812cefdac",
	}
	c.HTML(http.StatusOK, "imdroid_radar.html", data)
}

// radarHaizhuHandler 海珠雷达站占位页
func radarHaizhuHandler(c *gin.Context) {
	data := types.PageData{
		Title:         "雷达页面",
		ServerTime:    time.Now().Format("2006-01-02 15:04:05"),
		OnlineDevices: database.GetOnlineDevicesCount(database.GetDB()),
		TiandituKey:   "0c260b8a094a4e0bc507808812cefdac",
	}
	c.HTML(http.StatusOK, "imdroid_radar.html", data)
}

// radarPanyuHandler 番禺雷达站占位页
func radarPanyuHandler(c *gin.Context) {
	data := types.PageData{
		Title:         "雷达页面",
		ServerTime:    time.Now().Format("2006-01-02 15:04:05"),
		OnlineDevices: database.GetOnlineDevicesCount(database.GetDB()),
		TiandituKey:   "0c260b8a094a4e0bc507808812cefdac",
	}
	c.HTML(http.StatusOK, "imdroid_radar.html", data)
}

func imdroidRadarHandler(c *gin.Context) {
	data := types.PageData{
		Title:         "英卓雷达站",
		ServerTime:    time.Now().Format("2006-01-02 15:04:05"),
		OnlineDevices: database.GetOnlineDevicesCount(database.GetDB()),
		TiandituKey:   "0c260b8a094a4e0bc507808812cefdac",
	}
	c.HTML(http.StatusOK, "imdroid_radar.html", data)
}

// systemStatusHandler 处理系统状态API请求
func systemStatusHandler(c *gin.Context) {
	status := types.SystemStatus{
		OnlineDevices: database.GetOnlineDevicesCount(database.GetDB()),
		ServerTime:    time.Now().Format("2006-01-02 15:04:05"),
	}
	c.JSON(http.StatusOK, status)
}

// getStationsHandler 处理获取站点列表API请求
func getStationsHandler(c *gin.Context) {
	stations, err := database.GetStations(database.GetDB())
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "查询站点失败"})
		return
	}

	// 为每个站点计算十进制ID
	for i := range stations {
		if len(stations[i].StationID) > 6 {
			hexID := stations[i].StationID[len(stations[i].StationID)-6:]
			if decimalID, err := strconv.ParseInt(hexID, 16, 64); err == nil {
				stations[i].DecimalID = strconv.FormatInt(decimalID, 10)
			}
		}
	}

	c.JSON(http.StatusOK, stations)
}

// getDataHandler 处理获取历史数据API请求
func getDataHandler(c *gin.Context) {
	// 获取查询参数
	decimalID := c.Query("decimal_id")
	startTime := c.Query("start_time")
	endTime := c.Query("end_time")
	interval := c.Query("interval")

	// 将十进制ID转换为十六进制（补足6位）
	decimalNum, err := strconv.ParseInt(decimalID, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无效的站点编号"})
		return
	}
	hexID := fmt.Sprintf("%06X", decimalNum)
	stationID := fmt.Sprintf("RS485-%s", hexID)

	// 解析时间（按本地CST解析，避免被当作UTC）
	loc, _ := time.LoadLocation("Asia/Shanghai")
	if loc == nil {
		loc = time.FixedZone("CST", 8*3600)
	}
	start, err := time.ParseInLocation("2006-01-02 15:04:05", startTime, loc)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无效的开始时间"})
		return
	}

	end, err := time.ParseInLocation("2006-01-02 15:04:05", endTime, loc)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无效的结束时间"})
		return
	}

	// 获取数据（改为基于10分钟聚合表的再聚合）
	var points []types.WeatherPoint
	if interval == "raw" {
		points, err = database.GetSeriesRaw(database.GetDB(), stationID, start, end)
	} else {
		points, err = database.GetSeriesFrom10Min(database.GetDB(), stationID, start, end, interval)
	}
	if err != nil {
		log.Printf("查询数据失败: %v", err) // 记录具体错误到服务端日志
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": fmt.Sprintf("查询数据失败: %v", err),
		})
		return
	}

	c.JSON(http.StatusOK, points)
}

// getForecastHandler 处理获取预报数据API请求
func getForecastHandler(c *gin.Context) {
	// 获取查询参数
	stationID := c.Query("station_id")
	startTime := c.Query("from")
	endTime := c.Query("to")
	provider := c.Query("provider")
	versionsStr := c.DefaultQuery("versions", "1")
	versions, _ := strconv.Atoi(versionsStr)
	if versions <= 0 {
		versions = 1
	}

	if stationID == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "缺少station_id参数"})
		return
	}

	// 如果没有提供时间范围，则默认查询未来3小时
	loc, _ := time.LoadLocation("Asia/Shanghai")
	if loc == nil {
		loc = time.FixedZone("CST", 8*3600)
	}

	var start, end time.Time
	var err error

	if startTime == "" || endTime == "" {
		// 默认查询未来3小时
		now := time.Now().In(loc)
		start = now.Truncate(time.Hour).Add(1 * time.Hour) // 下一个整点开始
		end = start.Add(3 * time.Hour)                     // 未来3小时
	} else {
		// 解析用户提供的时间
		start, err = time.ParseInLocation("2006-01-02 15:04:05", startTime, loc)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "无效的开始时间格式"})
			return
		}

		end, err = time.ParseInLocation("2006-01-02 15:04:05", endTime, loc)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "无效的结束时间格式"})
			return
		}
	}

	// 获取预报数据
	log.Printf("查询预报数据: stationID=%s, provider=%s, versions=%d, start=%s, end=%s", stationID, provider, versions, start.Format("2006-01-02 15:04:05"), end.Format("2006-01-02 15:04:05"))
	points, err := database.GetForecastData(database.GetDB(), stationID, start, end, provider, versions)
	if err != nil {
		log.Printf("查询预报数据失败: %v", err)
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": fmt.Sprintf("查询预报数据失败: %v", err),
		})
		return
	}

	log.Printf("查询到预报数据: %d 条", len(points))
	c.JSON(http.StatusOK, points)
}
