package cmd

import (
	"axolotl/models"
	"axolotl/service"
	"axolotl/store"
	"fmt"
	"os"
	"strings"

	"github.com/spf13/cobra"
)

func getNodeService() (service.NodeService, error) {
	user := cfg.GetUser()
	if user == "" {
		return nil, fmt.Errorf("no user configured: run 'ax user set <username>' first")
	}
	if rc, ok := cfg.GetRemoteConfig(); ok {
		base := fmt.Sprintf("http://%s:%d", rc.Host, rc.Port)
		return service.NewRemoteNodeService(base, user), nil
	}
	st, err := store.FindAndOpenSQLiteStore()
	if err != nil {
		return nil, err
	}
	return service.NewLocalNodeService(st, user), nil
}

var jsonFlag bool
var cfg *store.Config
var rootCmd = &cobra.Command{Use: "ax", Short: "The axolotl issue tracker"}

func Execute() {
	var err error
	cfg, err = store.LoadConfigFile()
	if err != nil {
		fmt.Fprintln(os.Stderr, "failed to load config:", err)
		os.Exit(1)
	}
	RegisterAliasCommands()
	if err := rootCmd.Execute(); err != nil {
		os.Exit(1)
	}
}

func init() {
	rootCmd.PersistentFlags().BoolVar(&jsonFlag, "json", false, "")
}

func RegisterAliasCommands() {
	rootCmd.AddGroup(&cobra.Group{ID: "aliases", Title: "Aliases:"})
	aliases, _ := cfg.ListAliases()
	for _, a := range aliases {
		rootCmd.AddCommand(&cobra.Command{
			Use:                a.Name,
			Short:              a.Description,
			GroupID:            "aliases",
			DisableFlagParsing: true,
			Run: func(ccmd *cobra.Command, args []string) {
				acmd := a.Command
				acmd = strings.ReplaceAll(acmd, "$me", cfg.GetUser())
				parts := strings.Fields(acmd)
				var expanded []string
				usedArgs := make([]bool, len(args))
				for _, part := range parts {
					if part == "$@" {
						expanded = append(expanded, args...)
						for i := range usedArgs {
							usedArgs[i] = true
						}
						continue
					}
					hasCatchAll := strings.Contains(part, "$@")
					replaced := part
					if hasCatchAll {
						replaced = strings.ReplaceAll(replaced, "$@", strings.Join(args, " "))
						for i := range usedArgs {
							usedArgs[i] = true
						}
					}
					for i := len(args) - 1; i >= 0; i-- {
						placeholder := fmt.Sprintf("$%d", i+1)
						if strings.Contains(replaced, placeholder) {
							replaced = strings.ReplaceAll(replaced, placeholder, args[i])
							usedArgs[i] = true
						}
					}
					expanded = append(expanded, replaced)
				}
				// Forward any unconsumed args (e.g. --json flag).
				for i, arg := range args {
					if !usedArgs[i] {
						expanded = append(expanded, arg)
					}
				}
				rootCmd.SetArgs(expanded)
				if err := rootCmd.Execute(); err != nil {
					os.Exit(1)
				}
			},
		})
	}
}

// parseRelInput parses a rel string into a RelInput.
// Formats:
//   - "prefix::value"  → property rel with no target (tag)
//   - "relname:target" → edge rel with a target node
//   - "tagname"        → simple label rel with no target (alias for --tag)
func parseRelInput(s string) (service.RelInput, error) {
	if strings.Contains(s, "::") {
		// Property: name::value — no target node.
		return service.RelInput{Type: models.RelType(s), Target: ""}, nil
	}
	if idx := strings.Index(s, ":"); idx >= 0 {
		// Edge rel: relname:target.
		return service.RelInput{Type: models.RelType(s[:idx]), Target: s[idx+1:]}, nil
	}
	// Simple label tag — no target node.
	return service.RelInput{Type: models.RelType(s), Target: ""}, nil
}
