package cli

import (
	"bufio"
	"fmt"
	"net"
	"os"
	"strings"

	"drip/internal/shared/ui"
	"drip/pkg/config"
	"github.com/spf13/cobra"
)

var configCmd = &cobra.Command{
	Use:   "config",
	Short: "Manage configuration",
	Long:  "Manage Drip client configuration (server, token, etc.)",
}

var configInitCmd = &cobra.Command{
	Use:   "init",
	Short: "Initialize configuration interactively",
	Long:  "Initialize Drip configuration with interactive prompts",
	RunE:  runConfigInit,
}

var configShowCmd = &cobra.Command{
	Use:   "show",
	Short: "Show current configuration",
	Long:  "Display the current Drip configuration",
	RunE:  runConfigShow,
}

var configSetCmd = &cobra.Command{
	Use:   "set",
	Short: "Set configuration values",
	Long:  "Set specific configuration values (server, token)",
	RunE:  runConfigSet,
}

var configResetCmd = &cobra.Command{
	Use:   "reset",
	Short: "Reset configuration",
	Long:  "Delete the configuration file",
	RunE:  runConfigReset,
}

var configValidateCmd = &cobra.Command{
	Use:   "validate",
	Short: "Validate configuration",
	Long:  "Validate the configuration file",
	RunE:  runConfigValidate,
}

var (
	configFull   bool
	configForce  bool
	configServer string
	configToken  string
)

func init() {
	configCmd.AddCommand(configInitCmd)
	configCmd.AddCommand(configShowCmd)
	configCmd.AddCommand(configSetCmd)
	configCmd.AddCommand(configResetCmd)
	configCmd.AddCommand(configValidateCmd)

	configShowCmd.Flags().BoolVar(&configFull, "full", false, "Show full token (not hidden)")

	configSetCmd.Flags().StringVar(&configServer, "server", "", "Server address (e.g., tunnel.example.com:443)")
	configSetCmd.Flags().StringVar(&configToken, "token", "", "Authentication token")

	configResetCmd.Flags().BoolVar(&configForce, "force", false, "Force reset without confirmation")

	rootCmd.AddCommand(configCmd)
}

func runConfigInit(_ *cobra.Command, _ []string) error {
	fmt.Print(ui.RenderConfigInit())

	reader := bufio.NewReader(os.Stdin)

	fmt.Print(ui.Muted("Server address (e.g., tunnel.example.com:443): "))
	serverAddr, _ := reader.ReadString('\n')
	serverAddr = strings.TrimSpace(serverAddr)

	if serverAddr == "" {
		return fmt.Errorf("server address is required")
	}

	fmt.Print(ui.Muted("Authentication token (leave empty to skip): "))
	token, _ := reader.ReadString('\n')
	token = strings.TrimSpace(token)

	cfg := &config.ClientConfig{
		Server: serverAddr,
		Token:  token,
		TLS:    true,
	}

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

	fmt.Println(ui.RenderConfigSaved(config.DefaultClientConfigPath()))

	return nil
}

func runConfigShow(_ *cobra.Command, _ []string) error {
	cfg, err := config.LoadClientConfig("")
	if err != nil {
		return err
	}

	var displayToken string
	if cfg.Token != "" {
		tokenLen := len(cfg.Token)
		if tokenLen <= 3 {
			// For very short tokens, just show asterisks
			displayToken = "***"
		} else if tokenLen > 10 {
			// For long tokens, show first 3 and last 3 characters
			displayToken = cfg.Token[:3] + "***" + cfg.Token[tokenLen-3:]
		} else {
			// For medium tokens (4-10 chars), show first 3 characters
			displayToken = cfg.Token[:3] + "***"
		}
	} else {
		displayToken = ""
	}

	fmt.Println(ui.RenderConfigShow(cfg.Server, displayToken, !configFull, cfg.TLS, config.DefaultClientConfigPath()))

	return nil
}

func runConfigSet(_ *cobra.Command, _ []string) error {
	cfg, err := config.LoadClientConfig("")
	if err != nil {
		cfg = &config.ClientConfig{
			TLS: true,
		}
	}

	modified := false
	var updates []string

	if configServer != "" {
		cfg.Server = configServer
		modified = true
		updates = append(updates, "Server updated: "+configServer)
	}

	if configToken != "" {
		cfg.Token = configToken
		modified = true
		updates = append(updates, "Token updated")
	}

	if !modified {
		return fmt.Errorf("no changes specified. Use --server or --token")
	}

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

	fmt.Println(ui.RenderConfigUpdated(updates))

	return nil
}

func runConfigReset(_ *cobra.Command, _ []string) error {
	configPath := config.DefaultClientConfigPath()

	if !config.ConfigExists("") {
		fmt.Println("No configuration file found")
		return nil
	}

	if !configForce {
		fmt.Print("Are you sure you want to delete the configuration? (y/N): ")
		reader := bufio.NewReader(os.Stdin)
		response, _ := reader.ReadString('\n')
		response = strings.ToLower(strings.TrimSpace(response))

		if response != "y" && response != "yes" {
			fmt.Println("Cancelled")
			return nil
		}
	}

	if err := os.Remove(configPath); err != nil {
		return fmt.Errorf("failed to delete configuration: %w", err)
	}

	fmt.Println(ui.RenderConfigDeleted())

	return nil
}

func runConfigValidate(_ *cobra.Command, _ []string) error {
	cfg, err := config.LoadClientConfig("")
	if err != nil {
		fmt.Println(ui.Error("Failed to load configuration"))
		return err
	}

	serverValid, serverMsg := validateServerAddress(cfg.Server)
	tokenSet := cfg.Token != ""
	tlsEnabled := cfg.TLS

	tokenMsg := "Token is set"
	if !tokenSet {
		tokenMsg = "Token is not set (authentication may fail)"
	}

	fmt.Println(ui.RenderConfigValidation(serverValid, serverMsg, tokenSet, tokenMsg, tlsEnabled))

	if !serverValid {
		return fmt.Errorf("invalid configuration: %s", serverMsg)
	}

	return nil
}

func validateServerAddress(addr string) (bool, string) {
	addr = strings.TrimSpace(addr)
	if addr == "" {
		return false, "Server address is not set"
	}

	host, port, err := net.SplitHostPort(addr)
	if err != nil {
		return false, fmt.Sprintf("Server address must include host and port (e.g., tunnel.example.com:443): %v", err)
	}

	if host == "" {
		return false, "Server host is empty"
	}

	if port == "" {
		return false, "Server port is empty"
	}

	return true, fmt.Sprintf("Server address is valid (%s:%s)", host, port)
}
