package main

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"

	"github.com/sstent/go-garth/config"
)

var (
	cfgFile      string
	userConfigDir string
	cfg          *config.Config
)

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
	Use:   "garth",
	Short: "Garmin Connect CLI tool",
	Long: `A comprehensive CLI tool for interacting with Garmin Connect.

Garth allows you to fetch your Garmin Connect data, including activities,
health stats, and more, directly from your terminal.`,
	PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
		// Ensure config is loaded before any command runs
		if cfg == nil {
			return fmt.Errorf("configuration not loaded")
		}
		return nil
	},
}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	err := rootCmd.Execute()
	if err != nil {
		os.Exit(1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)

	// Global flags
	rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.config/garth/config.yaml)")
	rootCmd.PersistentFlags().StringVar(&userConfigDir, "config-dir", "", "config directory (default is $HOME/.config/garth)")

	rootCmd.PersistentFlags().String("output", "table", "output format (json, table, csv)")
	rootCmd.PersistentFlags().Bool("verbose", false, "enable verbose output")
	rootCmd.PersistentFlags().String("date-from", "", "start date for data fetching (YYYY-MM-DD)")
	rootCmd.PersistentFlags().String("date-to", "", "end date for data fetching (YYYY-MM-DD)")

	// Bind flags to viper
	_ = viper.BindPFlag("output.format", rootCmd.PersistentFlags().Lookup("output"))
	_ = viper.BindPFlag("verbose", rootCmd.PersistentFlags().Lookup("verbose"))
	_ = viper.BindPFlag("dateFrom", rootCmd.PersistentFlags().Lookup("date-from"))
	_ = viper.BindPFlag("dateTo", rootCmd.PersistentFlags().Lookup("date-to"))
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if userConfigDir == "" {
		userConfigDir = config.UserConfigDir()
	}

	if cfgFile != "" {
		// Use config file from the flag.
		viper.SetConfigFile(cfgFile)
	} else {
		// Search config in user's config directory with name "config" (without extension).
		viper.AddConfigPath(userConfigDir)
		viper.SetConfigName("config")
		viper.SetConfigType("yaml")
	}

	viper.AutomaticEnv() // read in environment variables that match

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed())
	} else {
		// If config file not found, try to initialize a default one
		defaultConfigPath := filepath.Join(userConfigDir, "config.yaml")
		if _, statErr := os.Stat(defaultConfigPath); os.IsNotExist(statErr) {
			fmt.Fprintln(os.Stderr, "No config file found. Initializing default config at:", defaultConfigPath)
			var initErr error
			cfg, initErr = config.InitConfig(defaultConfigPath)
			if initErr != nil {
				fmt.Fprintln(os.Stderr, "Error initializing default config:", initErr)
				os.Exit(1)
			}
		} else if statErr != nil {
			fmt.Fprintln(os.Stderr, "Error checking for config file:", statErr)
			os.Exit(1)
		}
	}

	// Unmarshal config into our struct
	if cfg == nil { // Only unmarshal if not already initialized by InitConfig
		cfg = config.DefaultConfig() // Start with defaults
		if err := viper.Unmarshal(cfg); err != nil {
			fmt.Fprintln(os.Stderr, "Error unmarshaling config:", err)
			os.Exit(1)
		}
	}

	// Override config with flag values
	if rootCmd.PersistentFlags().Lookup("output").Changed {
		cfg.Output.Format = viper.GetString("output.format")
	}
	// Add other flag overrides as needed
}
