package cmd

import (
	"fmt"
	"os"
	"strconv"
	"strings"

	"forgejo.zerova.net/public/fj/internal/git"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var cfgFile string
var jsonErrors bool

var rootCmd = &cobra.Command{
	Use:   "fj",
	Short: "Forgejo CLI tool - work seamlessly with Forgejo from the command line",
	Long: `fj is a command line tool for Forgejo instances (including Codeberg).
It brings pull requests, issues, and other Forgejo concepts to the terminal.`,
	Version:       "0.3.1",
	SilenceErrors: true,
}

// JSONErrors reports whether the --json-errors flag is set.
func JSONErrors() bool {
	return jsonErrors
}

func Execute() error {
	return rootCmd.Execute()
}

func init() {
	cobra.OnInitialize(initConfig)

	rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.config/fj/config.yaml)")
	rootCmd.PersistentFlags().BoolVar(&jsonErrors, "json-errors", false, "output errors as structured JSON to stderr")
	rootCmd.PersistentFlags().String("hostname", "", "Forgejo instance hostname")
	_ = viper.BindPFlag("hostname", rootCmd.PersistentFlags().Lookup("hostname"))
}

func initConfig() {
	if cfgFile != "" {
		viper.SetConfigFile(cfgFile)
	} else {
		home, err := os.UserHomeDir()
		if err != nil {
			fmt.Fprintln(ios.ErrOut, err)
			os.Exit(1)
		}

		configDir := home + "/.config/fj"
		_ = os.MkdirAll(configDir, 0755)

		viper.AddConfigPath(configDir)
		viper.SetConfigType("yaml")
		viper.SetConfigName("config")
	}

	viper.AutomaticEnv()
	viper.SetEnvPrefix("FGJ")

	_ = viper.ReadInConfig()
}

// parseRepo parses the repository string in the format "owner/name".
// If not provided, it attempts to auto-detect from the git repository.
func parseRepo(repo string) (string, string, error) {
	// If repo flag is provided, use it
	if repo != "" {
		parts := strings.Split(repo, "/")
		if len(parts) != 2 {
			return "", "", fmt.Errorf("invalid repository format: %s (expected: owner/name)", repo)
		}
		return parts[0], parts[1], nil
	}

	// Try to auto-detect from git
	owner, name, err := git.DetectRepo()
	if err != nil {
		return "", "", fmt.Errorf("repository flag is required (use -R owner/name) or run from a git repository: %w", err)
	}

	return owner, name, nil
}

// getDetectedHost attempts to auto-detect the Forgejo instance hostname.
// Returns empty string if detection fails, which will fall back to other methods.
func getDetectedHost() string {
	host, err := git.DetectHost()
	if err != nil {
		return ""
	}
	return host
}

// getCwd returns the current working directory, or "" on error.
func getCwd() string {
	cwd, err := os.Getwd()
	if err != nil {
		return ""
	}
	return cwd
}

// promptLine prints a prompt to stderr and reads a line from stdin.
func promptLine(prompt string) (string, error) {
	fmt.Fprint(ios.ErrOut, prompt)
	var buf [1024]byte
	n, err := ios.In.Read(buf[:])
	if err != nil {
		return "", fmt.Errorf("reading input: %w", err)
	}
	return strings.TrimSpace(string(buf[:n])), nil
}

// parseIssueArg parses an issue/PR number from various formats:
// "123", "#123", "https://host/owner/repo/pulls/123", "https://host/owner/repo/issues/123"
func parseIssueArg(arg string) (int64, error) {
	arg = strings.TrimPrefix(arg, "#")
	// Try URL format
	if strings.HasPrefix(arg, "http") {
		parts := strings.Split(strings.TrimRight(arg, "/"), "/")
		arg = parts[len(parts)-1]
	}
	return strconv.ParseInt(arg, 10, 64)
}
