package sandbox

import (
	"bufio"
	"fmt"
	"os"
	"os/exec"
	"strings"
	"sync"

	"github.com/DeBrosOfficial/network/pkg/cli"
)

// Destroy tears down a sandbox cluster.
func Destroy(name string, force bool) error {
	cfg, err := LoadConfig()
	if err != nil {
		return err
	}

	// Resolve sandbox name
	state, err := resolveSandbox(name)
	if err != nil {
		return err
	}

	// Confirm destruction
	if !force {
		reader := bufio.NewReader(os.Stdin)
		fmt.Printf("Destroy sandbox %q? This deletes %d servers. [y/N]: ", state.Name, len(state.Servers))
		choice, _ := reader.ReadString('\n')
		choice = strings.TrimSpace(strings.ToLower(choice))
		if choice != "y" && choice != "yes" {
			fmt.Println("Aborted.")
			return nil
		}
	}

	state.Status = StatusDestroying
	SaveState(state) // best-effort status update

	client := NewHetznerClient(cfg.HetznerAPIToken)

	// Step 1: Unassign floating IPs from nameserver nodes
	fmt.Println("Unassigning floating IPs...")
	for _, srv := range state.NameserverNodes() {
		if srv.FloatingIP == "" {
			continue
		}
		// Find the floating IP ID from config
		for _, fip := range cfg.FloatingIPs {
			if fip.IP == srv.FloatingIP {
				if err := client.UnassignFloatingIP(fip.ID); err != nil {
					fmt.Fprintf(os.Stderr, "  Warning: could not unassign floating IP %s: %v\n", fip.IP, err)
				} else {
					fmt.Printf("  Unassigned %s from %s\n", fip.IP, srv.Name)
				}
				break
			}
		}
	}

	// Step 2: Delete all servers in parallel
	fmt.Printf("Deleting %d servers...\n", len(state.Servers))
	var wg sync.WaitGroup
	var mu sync.Mutex
	var failed []string

	for _, srv := range state.Servers {
		wg.Add(1)
		go func(srv ServerState) {
			defer wg.Done()
			if err := client.DeleteServer(srv.ID); err != nil {
				// Treat 404 as already deleted (idempotent)
				if strings.Contains(err.Error(), "404") || strings.Contains(err.Error(), "not found") {
					fmt.Printf("  %s (ID %d): already deleted\n", srv.Name, srv.ID)
				} else {
					mu.Lock()
					failed = append(failed, fmt.Sprintf("%s (ID %d): %v", srv.Name, srv.ID, err))
					mu.Unlock()
					fmt.Fprintf(os.Stderr, "  Warning: failed to delete %s: %v\n", srv.Name, err)
				}
			} else {
				fmt.Printf("  Deleted %s (ID %d)\n", srv.Name, srv.ID)
			}
		}(srv)
	}
	wg.Wait()

	if len(failed) > 0 {
		fmt.Fprintf(os.Stderr, "\nFailed to delete %d server(s):\n", len(failed))
		for _, f := range failed {
			fmt.Fprintf(os.Stderr, "  %s\n", f)
		}
		fmt.Fprintf(os.Stderr, "\nManual cleanup: delete servers at https://console.hetzner.cloud\n")
		state.Status = StatusError
		SaveState(state)
		return fmt.Errorf("failed to delete %d server(s)", len(failed))
	}

	// Step 3: Remove state file
	if err := DeleteState(state.Name); err != nil {
		return fmt.Errorf("delete state: %w", err)
	}

	// Remove sandbox environment entry, fall back to devnet
	if err := cli.RemoveEnvironment("sandbox"); err != nil {
		fmt.Fprintf(os.Stderr, "Warning: failed to remove sandbox environment: %v\n", err)
	}

	// Clean up SSH known_hosts entries for destroyed server IPs.
	// This prevents "REMOTE HOST IDENTIFICATION HAS CHANGED" errors
	// when the same IPs are reused by a new sandbox.
	cleanupKnownHosts(state)

	fmt.Printf("\nSandbox %q destroyed (%d servers deleted)\n", state.Name, len(state.Servers))
	return nil
}

// cleanupKnownHosts removes SSH known_hosts entries for all sandbox server IPs.
func cleanupKnownHosts(state *SandboxState) {
	for _, srv := range state.Servers {
		cmd := exec.Command("ssh-keygen", "-R", srv.IP)
		cmd.Stdout = nil
		cmd.Stderr = nil
		cmd.Run() // best-effort, ignore errors
	}
}

// resolveSandbox finds a sandbox by name or returns the active one.
func resolveSandbox(name string) (*SandboxState, error) {
	if name != "" {
		return LoadState(name)
	}

	// Find the active sandbox
	active, err := FindActiveSandbox()
	if err != nil {
		return nil, err
	}
	if active == nil {
		return nil, fmt.Errorf("no active sandbox found, specify --name")
	}
	return active, nil
}
