package tool

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"time"
)

// tiupBinaryPath returns the absolute path to the tiup binary, based on the
// current user's home directory (with a sensible fallback for containers).
func tiupBinaryPath() string {
	// First check if tiup is in PATH
	if path, err := exec.LookPath("tiup"); err == nil {
		return path
	}

	// Fallback to default tiup path
	homeDir, err := os.UserHomeDir()
	if err != nil || homeDir == "" {
		homeDir = "/root"
	}
	return filepath.Join(homeDir, ".tiup", "bin", "tiup")
}

// tiupCmd constructs a command that invokes tiup via its absolute path so we
// don't depend on PATH inside containers.
func tiupCmd(args ...string) *exec.Cmd {
	return exec.Command(tiupBinaryPath(), args...)
}

// InstallTiupTools verifies tiup, dumpling and tidb-lightning are installed
// In production, these tools should be installed during the Docker build phase
func InstallTiupTools() error {
	fmt.Println("Verifying tiup tools...")

	// Check if tiup is installed
	if err := checkTiupInstallation(); err != nil {
		return fmt.Errorf("tiup is not installed: %w", err)
	}

	// Check if components are installed
	if err := checkComponents(); err != nil {
		return fmt.Errorf("required components are not installed: %w", err)
	}

	// Verify installation
	if err := verifyInstallation(); err != nil {
		return fmt.Errorf("failed to verify installation: %w", err)
	}

	fmt.Println("Tiup tools verification completed successfully")
	return nil
}

// checkTiupInstallation checks if tiup is installed
func checkTiupInstallation() error {
	cmd := tiupCmd("--version")
	_, err := cmd.CombinedOutput()
	return err
}

// checkComponents checks if dumpling and tidb-lightning are installed
func checkComponents() error {
	cmd := tiupCmd("list", "dumpling")
	_, err := cmd.CombinedOutput()
	if err != nil {
		return err
	}

	cmd = tiupCmd("list", "tidb-lightning")
	_, err = cmd.CombinedOutput()
	return err
}

// installTiup installs tiup
func installTiup() error {
	fmt.Println("Installing tiup...")

	// Decide HOME explicitly so installer and our PATH logic are consistent,
	// even in container environments where $HOME may be empty or unusual.
	homeDir, err := os.UserHomeDir()
	if err != nil || homeDir == "" {
		// Fallback for common container root home
		homeDir = "/root"
	}

	// Create tiup directory if it doesn't exist
	tiupDir := filepath.Join(homeDir, ".tiup")
	if err := os.MkdirAll(tiupDir, 0755); err != nil {
		return fmt.Errorf("failed to create tiup directory: %w", err)
	}

	// Download and run tiup installer with a well-defined HOME
	cmd := exec.Command("sh", "-c", "curl --proto '=https' --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh")
	cmd.Env = append(os.Environ(), fmt.Sprintf("HOME=%s", homeDir))
	output, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("failed to install tiup: %w, output: %s", err, string(output))
	}

	// Add tiup to PATH. Prefer os.UserHomeDir so it works even when $HOME is empty
	tiupPath := filepath.Join(homeDir, ".tiup", "bin")
	os.Setenv("PATH", fmt.Sprintf("%s:%s", tiupPath, os.Getenv("PATH")))

	// Wait for tiup to be available
	time.Sleep(2 * time.Second)

	fmt.Println("Tiup installed successfully")
	return nil
}

// setTiupMirror sets tiup mirror to pingcap's official mirror
func setTiupMirror() error {
	fmt.Println("Setting tiup mirror...")

	cmd := tiupCmd("mirror", "set", "https://tiup-mirrors.pingcap.com")
	output, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("failed to set tiup mirror: %w, output: %s", err, string(output))
	}

	fmt.Println("Tiup mirror set successfully")
	return nil
}

// installComponents installs dumpling and tidb-lightning
func installComponents() error {
	fmt.Println("Installing dumpling and tidb-lightning...")

	// Install dumpling
	cmd := tiupCmd("install", "dumpling:v8.5.5")
	output, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("failed to install dumpling: %w, output: %s", err, string(output))
	}

	// Install tidb-lightning
	cmd = tiupCmd("install", "tidb-lightning:v8.5.5")
	output, err = cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("failed to install tidb-lightning: %w, output: %s", err, string(output))
	}

	fmt.Println("Components installed successfully")
	return nil
}

// verifyInstallation verifies that all tools are installed correctly
func verifyInstallation() error {
	fmt.Println("Verifying installation...")

	// Verify tiup
	cmd := tiupCmd("--version")
	output, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("tiup verification failed: %w, output: %s", err, string(output))
	}
	fmt.Printf("Tiup version: %s", string(output))

	// Verify dumpling is available
	cmd = tiupCmd("list", "dumpling")
	output, err = cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("dumpling verification failed: %w, output: %s", err, string(output))
	}
	fmt.Println("Dumpling is available")

	// Verify tidb-lightning is available
	cmd = tiupCmd("list", "tidb-lightning")
	output, err = cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("tidb-lightning verification failed: %w, output: %s", err, string(output))
	}
	fmt.Println("Tidb-lightning is available")

	// Try to directly execute dumpling using tiup (without run component)
	cmd = tiupCmd("dumpling", "--version")
	output, err = cmd.CombinedOutput()
	if err != nil {
		fmt.Printf("Warning: Could not run dumpling directly: %v, output: %s\n", err, string(output))
		// Don't fail the verification, just warn
	} else {
		fmt.Printf("Dumpling version: %s", string(output))
	}

	fmt.Println("Installation verification passed")
	return nil
}
