// SPDX-License-Identifier: GPL-3.0-or-later

// Package cli provides the config command.
package cli

import (
	"fmt"
	"os"
	"os/exec"

	"github.com/spf13/cobra"
)

// newConfigCommand creates the config command.
func (c *CLI) newConfigCommand() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "config",
		Short: "View and edit configuration",
		Long: `View and manage CLI configuration.

Configuration is stored in ~/.config/privatebackup/cli.yaml`,
		Example: `  # Show config
  privatebackup config show

  # Set value
  privatebackup config set backup.exclude_caches true

  # Edit in $EDITOR
  privatebackup config edit`,
		RunE: func(cmd *cobra.Command, args []string) error {
			return c.runConfigShow()
		},
	}

	// Add subcommands
	cmd.AddCommand(c.newConfigShowCommand())
	cmd.AddCommand(c.newConfigSetCommand())
	cmd.AddCommand(c.newConfigEditCommand())

	return cmd
}

// newConfigShowCommand creates the config show subcommand.
func (c *CLI) newConfigShowCommand() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "show",
		Short: "Show current configuration",
		RunE: func(cmd *cobra.Command, args []string) error {
			return c.runConfigShow()
		},
	}

	return cmd
}

// runConfigShow displays the current configuration.
func (c *CLI) runConfigShow() error {
	cfg, err := c.configMgr.Load()
	if err != nil {
		return fmt.Errorf("failed to load config: %w", err)
	}

	configPath := c.configMgr.GetConfigDir() + "/cli.yaml"

	c.renderer.Output(cfg, func() {
		c.renderer.Heading(fmt.Sprintf("Configuration (%s)", configPath))
		c.renderer.Newline()

		c.renderer.Section("Output")
		c.renderer.KeyValue("color", cfg.Output.Color)
		c.renderer.KeyValue("progress_style", cfg.Output.ProgressStyle)
		c.renderer.KeyValue("date_format", cfg.Output.DateFormat)
		c.renderer.KeyValue("size_units", cfg.Output.SizeUnits)
		c.renderer.Newline()

		c.renderer.Section("Backend")
		c.renderer.KeyValue("url", cfg.Backend.URL)
		c.renderer.KeyValue("timeout", cfg.Backend.Timeout.String())
		c.renderer.KeyValue("auto_start_daemon", fmt.Sprintf("%v", cfg.Backend.AutoStartDaemon))
		c.renderer.Newline()

		c.renderer.Section("Backup Defaults")
		c.renderer.KeyValue("exclude_caches", fmt.Sprintf("%v", cfg.Defaults.Backup.ExcludeCaches))
		c.renderer.KeyValue("one_file_system", fmt.Sprintf("%v", cfg.Defaults.Backup.OneFileSystem))
		c.renderer.Newline()

		c.renderer.Section("Forget Defaults")
		c.renderer.KeyValue("keep_last", fmt.Sprintf("%d", cfg.Defaults.Forget.KeepLast))
		c.renderer.KeyValue("keep_daily", fmt.Sprintf("%d", cfg.Defaults.Forget.KeepDaily))
		c.renderer.KeyValue("keep_weekly", fmt.Sprintf("%d", cfg.Defaults.Forget.KeepWeekly))
		c.renderer.KeyValue("keep_monthly", fmt.Sprintf("%d", cfg.Defaults.Forget.KeepMonthly))
		c.renderer.KeyValue("keep_yearly", fmt.Sprintf("%d", cfg.Defaults.Forget.KeepYearly))
	})

	return nil
}

// newConfigSetCommand creates the config set subcommand.
func (c *CLI) newConfigSetCommand() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "set <key> <value>",
		Short: "Set a configuration value",
		Long: `Set a configuration value.

Keys use dot notation (e.g., backup.exclude_caches).`,
		Example: `  privatebackup config set backup.exclude_caches true
  privatebackup config set output.color never
  privatebackup config set defaults.forget.keep_daily 7`,
		Args: cobra.ExactArgs(2),
		RunE: func(cmd *cobra.Command, args []string) error {
			return c.runConfigSet(args[0], args[1])
		},
	}

	return cmd
}

// runConfigSet sets a configuration value.
func (c *CLI) runConfigSet(key, value string) error {
	// Load current config
	cfg, err := c.configMgr.Load()
	if err != nil {
		return fmt.Errorf("failed to load config: %w", err)
	}

	// Set the value using viper's Set method
	c.configMgr.Set(key, value)

	// Reload and save
	cfg, err = c.configMgr.Load()
	if err != nil {
		return fmt.Errorf("failed to reload config: %w", err)
	}

	if err := c.configMgr.Save(cfg); err != nil {
		return fmt.Errorf("failed to save config: %w", err)
	}

	c.renderer.Success(fmt.Sprintf("Set %s = %s", key, value))

	return nil
}

// newConfigEditCommand creates the config edit subcommand.
func (c *CLI) newConfigEditCommand() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "edit",
		Short: "Open config file in editor",
		Long:  `Open the configuration file in your default editor ($EDITOR or vi).`,
		RunE: func(cmd *cobra.Command, args []string) error {
			return c.runConfigEdit()
		},
	}

	return cmd
}

// runConfigEdit opens the config file in an editor.
func (c *CLI) runConfigEdit() error {
	configPath := c.configMgr.GetConfigDir() + "/cli.yaml"

	// Ensure config file exists
	if _, err := os.Stat(configPath); os.IsNotExist(err) {
		// Create default config
		cfg, err := c.configMgr.Load()
		if err != nil {
			return fmt.Errorf("failed to load config: %w", err)
		}
		if err := c.configMgr.Save(cfg); err != nil {
			return fmt.Errorf("failed to create config file: %w", err)
		}
	}

	// Find editor
	editor := os.Getenv("EDITOR")
	if editor == "" {
		editor = os.Getenv("VISUAL")
	}
	if editor == "" {
		// Default to vi on Unix
		editor = "vi"
	}

	// Open editor
	cmd := exec.Command(editor, configPath)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	return cmd.Run()
}
