package cmd

import (
	"context"
	"flag"
	"fmt"
	"os"
	"strconv"

	"skraak/db"
	"skraak/tools"
)

// RunLocation handles the "location" subcommand
func RunLocation(args []string) {
	if len(args) < 1 {
		printLocationUsage()
		os.Exit(1)
	}

	switch args[0] {
	case "create":
		RunLocationCreate(args[1:])
	case "update":
		RunLocationUpdate(args[1:])
	default:
		fmt.Fprintf(os.Stderr, "Unknown location subcommand: %s\n\n", args[0])
		printLocationUsage()
		os.Exit(1)
	}
}

func printLocationUsage() {
	fmt.Fprintf(os.Stderr, "Usage: skraak location <subcommand> [options]\n\n")
	fmt.Fprintf(os.Stderr, "Subcommands:\n")
	fmt.Fprintf(os.Stderr, "  create    Create a new location\n")
	fmt.Fprintf(os.Stderr, "  update    Update an existing location\n")
	fmt.Fprintf(os.Stderr, "\nExamples:\n")
	fmt.Fprintf(os.Stderr, "  skraak location create --db ./db/skraak.duckdb --dataset abc123 --name \"Site A\" --lat -36.85 --lon 174.76 --timezone Pacific/Auckland\n")
	fmt.Fprintf(os.Stderr, "  skraak location update --db ./db/skraak.duckdb --id loc123 --name \"Updated Name\"\n")
}

func RunLocationCreate(args []string) {
	fs := flag.NewFlagSet("location create", flag.ExitOnError)
	dbPath := fs.String("db", "", "Path to DuckDB database (required)")
	datasetID := fs.String("dataset", "", "Dataset ID (required)")
	name := fs.String("name", "", "Location name (required)")
	lat := fs.String("lat", "", "Latitude in decimal degrees (required)")
	lon := fs.String("lon", "", "Longitude in decimal degrees (required)")
	tz := fs.String("timezone", "", "IANA timezone ID (required, e.g. Pacific/Auckland)")
	description := fs.String("description", "", "Location description (optional)")

	fs.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: skraak location create [options]\n\n")
		fmt.Fprintf(os.Stderr, "Create a new location with GPS coordinates.\n\n")
		fmt.Fprintf(os.Stderr, "Options:\n")
		fs.PrintDefaults()
		fmt.Fprintf(os.Stderr, "\nExamples:\n")
		fmt.Fprintf(os.Stderr, "  skraak location create --db ./db/skraak.duckdb --dataset abc123 --name \"Site A\" --lat -36.85 --lon 174.76 --timezone Pacific/Auckland\n")
	}

	if err := fs.Parse(args); err != nil {
		os.Exit(1)
	}

	// Validate required flags
	missing := []string{}
	if *dbPath == "" {
		missing = append(missing, "--db")
	}
	if *datasetID == "" {
		missing = append(missing, "--dataset")
	}
	if *name == "" {
		missing = append(missing, "--name")
	}
	if *lat == "" {
		missing = append(missing, "--lat")
	}
	if *lon == "" {
		missing = append(missing, "--lon")
	}
	if *tz == "" {
		missing = append(missing, "--timezone")
	}
	if len(missing) > 0 {
		fmt.Fprintf(os.Stderr, "Error: missing required flags: %v\n\n", missing)
		fs.Usage()
		os.Exit(1)
	}

	// Parse floats
	latitude, err := strconv.ParseFloat(*lat, 64)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: invalid latitude: %v\n", err)
		os.Exit(1)
	}
	longitude, err := strconv.ParseFloat(*lon, 64)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: invalid longitude: %v\n", err)
		os.Exit(1)
	}

	tools.SetDBPath(*dbPath)

	// Initialize event log
	eventLogPath := *dbPath + ".events.jsonl"
	db.SetEventLogConfig(db.EventLogConfig{
		Enabled: true,
		Path:    eventLogPath,
	})
	defer db.CloseEventLog()

	input := tools.LocationInput{
		DatasetID:   datasetID,
		Name:        name,
		Latitude:    &latitude,
		Longitude:   &longitude,
		TimezoneID:  tz,
		Description: description,
	}

	output, err := tools.CreateOrUpdateLocation(context.Background(), input)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %v\n", err)
		os.Exit(1)
	}

	printJSON(output)
}

func RunLocationUpdate(args []string) {
	fs := flag.NewFlagSet("location update", flag.ExitOnError)
	dbPath := fs.String("db", "", "Path to DuckDB database (required)")
	id := fs.String("id", "", "Location ID (required)")
	name := fs.String("name", "", "New location name (optional)")
	lat := fs.String("lat", "", "New latitude (optional)")
	lon := fs.String("lon", "", "New longitude (optional)")
	tz := fs.String("timezone", "", "New IANA timezone ID (optional)")
	description := fs.String("description", "", "New location description (optional)")

	fs.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: skraak location update [options]\n\n")
		fmt.Fprintf(os.Stderr, "Update an existing location. Only provided fields are updated.\n\n")
		fmt.Fprintf(os.Stderr, "Options:\n")
		fs.PrintDefaults()
		fmt.Fprintf(os.Stderr, "\nExamples:\n")
		fmt.Fprintf(os.Stderr, "  skraak location update --db ./db/skraak.duckdb --id loc123 --name \"New Name\"\n")
	}

	if err := fs.Parse(args); err != nil {
		os.Exit(1)
	}

	// Validate required flags
	missing := []string{}
	if *dbPath == "" {
		missing = append(missing, "--db")
	}
	if *id == "" {
		missing = append(missing, "--id")
	}
	if len(missing) > 0 {
		fmt.Fprintf(os.Stderr, "Error: missing required flags: %v\n\n", missing)
		fs.Usage()
		os.Exit(1)
	}

	// Parse optional floats
	var latitude, longitude *float64
	if *lat != "" {
		latVal, err := strconv.ParseFloat(*lat, 64)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: invalid latitude: %v\n", err)
			os.Exit(1)
		}
		latitude = &latVal
	}
	if *lon != "" {
		lonVal, err := strconv.ParseFloat(*lon, 64)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: invalid longitude: %v\n", err)
			os.Exit(1)
		}
		longitude = &lonVal
	}

	tools.SetDBPath(*dbPath)

	// Initialize event log
	eventLogPath := *dbPath + ".events.jsonl"
	db.SetEventLogConfig(db.EventLogConfig{
		Enabled: true,
		Path:    eventLogPath,
	})
	defer db.CloseEventLog()

	// Build input - only set fields that were provided (non-empty)
	input := tools.LocationInput{
		ID: id,
	}
	if *name != "" {
		input.Name = name
	}
	if latitude != nil {
		input.Latitude = latitude
	}
	if longitude != nil {
		input.Longitude = longitude
	}
	if *tz != "" {
		input.TimezoneID = tz
	}
	if *description != "" {
		input.Description = description
	}

	output, err := tools.CreateOrUpdateLocation(context.Background(), input)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %v\n", err)
		os.Exit(1)
	}

	printJSON(output)
}