package main

import (
	"encoding/json"
	"fmt"
	"os"
	"os/signal"
	"os/user"
	"path/filepath"
	"syscall"
	"time"
)

type Stopwatches map[string]time.Time

var configPath string

func main() {
	args := os.Args[1:]

	if len(args) == 0 {
		// Quick stop watch
		stopwatchUI(time.Now())
	} else if len(args) == 1 && (args[0] == "help" || args[0] == "-h" || args[0] == "--help") {
		printHelp()
	} else if len(args) == 1 {
		namedStopwatch(args[0])
	} else if len(args) == 2 && (args[0] == "clear" || args[0] == "-c" || args[0] == "--clear") {
		clearStopwatch(args[1])
	} else if len(args) == 2 && (args[0] == "timer" || args[0] == "-t" || args[0] == "--timer") {
		d, err := time.ParseDuration(args[1])
		if err != nil {
			fmt.Println("Error parsing duration:", err)
		}
		timerUI(time.Now().Add(d))
	}
}

func namedStopwatch(name string) {
	stopwatches, err := loadStopwatches()
	if err != nil {
		fmt.Println("Error loading stopwatches:", err)
		return
	}

	startTime, exists := stopwatches[name]
	if !exists {
		stopwatches[name] = time.Now()
		saveStopwatches(stopwatches)
	} else {
		stopwatchUI(startTime)
	}
}

func clearStopwatch(name string) {
	stopwatches, err := loadStopwatches()
	if err != nil {
		fmt.Println("Error loading stopwatches:", err)
		return
	}

	if _, exists := stopwatches[name]; exists {
		delete(stopwatches, name)
		err := saveStopwatches(stopwatches)
		if err != nil {
			fmt.Println("Error saving stopwatches:", err)
			return
		}
	} else {
		fmt.Printf("Stopwatch '%s' does not exist.\n", name)
	}
}

func init() {
	usr, err := user.Current()
	if err != nil {
		fmt.Println("Error getting user home directory:", err)
		os.Exit(1)
	}
	configDir := filepath.Join(usr.HomeDir, ".config")
	configPath = filepath.Join(configDir, ".stopwatches")

	if _, err := os.Stat(configDir); os.IsNotExist(err) {
		os.MkdirAll(configDir, 0755)
	}
}

func loadStopwatches() (Stopwatches, error) {
	stopwatches := Stopwatches{}

	if _, err := os.Stat(configPath); err == nil {
		data, err := os.ReadFile(configPath)
		if err != nil {
			return stopwatches, err
		}
		err = json.Unmarshal(data, &stopwatches)
		if err != nil {
			return stopwatches, err
		}
	}

	return stopwatches, nil
}

func saveStopwatches(stopwatches Stopwatches) error {
	data, err := json.MarshalIndent(stopwatches, "", "  ")
	if err != nil {
		return err
	}
	return os.WriteFile(configPath, data, 0644)
}

func stopwatchUI(startTime time.Time) {
	stop := make(chan os.Signal, 1)
	signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM)

	go func() {
		<-stop
		os.Exit(0)
	}()

	for {
		elapsed := time.Since(startTime)
		fmt.Printf("\r%02dd %02dh %02dm %02ds %03dms",
			elapsed/(24*time.Hour),
			(elapsed%(24*time.Hour))/time.Hour,
			(elapsed%time.Hour)/time.Minute,
			(elapsed%time.Minute)/time.Second,
			(elapsed%time.Second)/time.Millisecond)
		time.Sleep(10 * time.Millisecond)
	}
}

func timerUI(startTime time.Time) {
	stop := make(chan os.Signal, 1)
	signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM)

	go func() {
		<-stop
		os.Exit(0)
	}()

	for {
		elapsed := time.Until(startTime)
		if elapsed.Milliseconds() == 0 {
			break
		}
		fmt.Printf("\r%02dd %02dh %02dm %02ds %03dms",
			elapsed/(24*time.Hour),
			(elapsed%(24*time.Hour))/time.Hour,
			(elapsed%time.Hour)/time.Minute,
			(elapsed%time.Minute)/time.Second,
			(elapsed%time.Second)/time.Millisecond)
		time.Sleep(1 * time.Millisecond)
	}
}

func printHelp() {
	fmt.Println("Usage:")
	fmt.Println("  stopwatch             - Start a quick stopwatch")
	fmt.Println("  stopwatch [name]      - Start or view a named stopwatch")
	fmt.Println("  stopwatch -t [time]   - Start a quick timer")
	fmt.Println("  stopwatch -c [name]   - Remove a named stopwatch")
	fmt.Println("  stopwatch -h          - View help menu")
}
