package radar

import (
	"context"
	"fmt"
	"os"
	"path"
	"regexp"
	"strconv"
	"strings"
	"time"
	"weatherstation/internal/database"
)

var (
	// Matches .../<PRODUCT>/<YYYYMMDD>/<HH>/<mm>/<z>/<y>/<x>.bin
	tileRE = regexp.MustCompile(`(?i)/tiles/.+?/([^/]+)/([0-9]{8})/([0-9]{2})/([0-9]{2})/([0-9]+)/([0-9]+)/([0-9]+)\.bin$`)
)

// TileRef references a CMA radar tile.
type TileRef struct {
	Product string
	DT      time.Time // nominal time in Asia/Shanghai
	Z, Y, X int
}

// ParseCMATileURL parses a CMA tile URL or path and extracts product, time, z/y/x.
// Accepts full URL or path that ends with /tiles/.../x.bin.
func ParseCMATileURL(u string) (TileRef, error) {
	// Normalize path part
	p := u
	// Optionally strip query/hash
	if i := strings.IndexAny(p, "?#"); i >= 0 {
		p = p[:i]
	}
	p = path.Clean(p)
	m := tileRE.FindStringSubmatch(p)
	if len(m) == 0 {
		return TileRef{}, fmt.Errorf("unrecognized CMA tile path: %s", u)
	}

	product := m[1]
	yyyymmdd := m[2]
	hh := m[3]
	mm := m[4]
	z := mustAtoi(m[5])
	y := mustAtoi(m[6])
	x := mustAtoi(m[7])

	loc, _ := time.LoadLocation("Asia/Shanghai")
	if loc == nil {
		loc = time.FixedZone("CST", 8*3600)
	}
	dt, err := time.ParseInLocation("20060102 15 04", fmt.Sprintf("%s %s %s", yyyymmdd, hh, mm), loc)
	if err != nil {
		return TileRef{}, fmt.Errorf("parse time: %w", err)
	}

	return TileRef{Product: product, DT: dt, Z: z, Y: y, X: x}, nil
}

func mustAtoi(s string) int {
	n, _ := strconv.Atoi(s)
	return n
}

// StoreTileBytes parses the URL, computes metadata and upserts into radar_tiles.
func StoreTileBytes(ctx context.Context, urlOrPath string, data []byte) error {
	ref, err := ParseCMATileURL(urlOrPath)
	if err != nil {
		return err
	}
	db := database.GetDB()
	return database.UpsertRadarTile(ctx, db, ref.Product, ref.DT, ref.Z, ref.Y, ref.X, 256, 256, data)
}

// ImportTileFile reads the file and stores it into DB using the URL for metadata.
func ImportTileFile(ctx context.Context, urlOrPath, filePath string) error {
	b, err := os.ReadFile(filePath)
	if err != nil {
		return fmt.Errorf("read file: %w", err)
	}
	return StoreTileBytes(ctx, urlOrPath, b)
}
