package cmd
import (
"context"
"flag"
"fmt"
"os"
"strconv"
"skraak/db"
"skraak/tools"
)
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)
}
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)
}
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)
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)
}
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)
}
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)
eventLogPath := *dbPath + ".events.jsonl"
db.SetEventLogConfig(db.EventLogConfig{
Enabled: true,
Path: eventLogPath,
})
defer db.CloseEventLog()
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)
}