package commands

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"datasmith/config"

	"github.com/fsnotify/fsnotify"
	"gopkg.in/yaml.v2"
)



// Load the datasmith.yaml file
func loadConfig(projectDir string) (config.DatasmithConfig, error) {
	configFilePath := filepath.Join(projectDir, "datasmith.yaml")
	file, err := os.Open(configFilePath)
	if err != nil {
		return config.DatasmithConfig{}, fmt.Errorf("error opening config file: %v", err)
	}
	defer file.Close()

	var cfg config.DatasmithConfig
	decoder := yaml.NewDecoder(file)
	if err := decoder.Decode(&cfg); err != nil {
		return config.DatasmithConfig{}, fmt.Errorf("error decoding config file: %v", err)
	}

	return cfg, nil
}

func Serve() {
	projectDir := "." // Assuming current directory is the project directory
	config, err := loadConfig(projectDir)
	if err != nil {
		fmt.Printf("Error loading config: %v\n", err)
		return
	}
	fmt.Println("Config loaded successfully.")

	// Determine which container tool to use (Docker or Podman)
	containerTool := "docker"
	if _, err := exec.LookPath("podman"); err == nil {
		containerTool = "podman"
	} else if _, err := exec.LookPath("docker"); err != nil {
		fmt.Println("Error: neither Docker nor Podman is installed.")
		return
	}

	// Build the Docker image
	fmt.Println("Building the Docker image...")
	if err := buildDockerImage(containerTool, config); err != nil {
		fmt.Printf("Error building Docker image: %v\n", err)
		return
	}
	fmt.Println("Docker image built successfully.")

	// Start the database container
	fmt.Println("Starting the database container...")
	if err := startDatabaseContainer(containerTool, config); err != nil {
		fmt.Printf("Error starting database container: %v\n", err)
		return
	}
	fmt.Println("Database container started successfully.")

	// Print connection information
	printConnectionInfo(config)

	fmt.Println("Watching for changes in the SQL files...")

	// Watch for changes in the SQL files
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		fmt.Printf("Error creating file watcher: %v\n", err)
		return
	}
	defer watcher.Close()

	done := make(chan bool)

	go func() {
		for {
			select {
			case event, ok := <-watcher.Events:
				if !ok {
					return
				}
				fmt.Println("Event:", event)
				if event.Op&fsnotify.Write == fsnotify.Write {
					fmt.Println("Modified file:", event.Name)
					if err := rebuildAndRestartContainer(containerTool, config); err != nil {
						fmt.Printf("Error rebuilding and restarting container: %v\n", err)
					} else {
						fmt.Println("Container rebuilt and restarted successfully.")
					}
				}
			case err, ok := <-watcher.Errors:
				if !ok {
					return
				}
				fmt.Println("Error:", err)
			}
		}
	}()

	err = watcher.Add("sql")
	if err != nil {
		fmt.Printf("Error adding watcher: %v\n", err)
		return
	}

	<-done
}

func buildDockerImage(containerTool string, config config.DatasmithConfig) error {
	imageName := fmt.Sprintf("ds_%s:%s", config.Name, config.Version)
	fmt.Printf("Building Docker image: %s\n", imageName)

	var buildCmd *exec.Cmd
	switch config.DbType {
	case "mysql":
		buildCmd = exec.Command(containerTool, "build",
			"-t", imageName,
			"--build-arg", "DB_USER=user",
			"--build-arg", "DB_PASSWORD=password",
			"--build-arg", fmt.Sprintf("DB_DATABASE=%s", config.Name),
			"--build-arg", "MARIADB_ROOT_PASSWORD=example",
			".")
	case "postgres":
		buildCmd = exec.Command(containerTool, "build",
			"-t", imageName,
			"--build-arg", "DB_USER=user",
			"--build-arg", "DB_PASSWORD=password",
			"--build-arg", fmt.Sprintf("DB_DATABASE=%s", config.Name),
			"--build-arg", "POSTGRES_PASSWORD=example",
			".")
	default:
		return fmt.Errorf("unsupported database type: %s", config.DbType)
	}

	buildCmd.Stdout = os.Stdout
	buildCmd.Stderr = os.Stderr
	return buildCmd.Run()
}

func startDatabaseContainer(containerTool string, config config.DatasmithConfig) error {
	var runCmd *exec.Cmd
	switch config.DbType {
	case "mysql":
		runCmd = exec.Command(containerTool, "run", "--rm", "-d",
			"-e", "MYSQL_ROOT_PASSWORD=example",
			"-e", fmt.Sprintf("DB_DATABASE=%s", config.Name),
			"-e", "DB_USER=user",
			"-e", "DB_PASSWORD=password",
			"-p", "3306:3306",
			"--name", "datasmith_db_container",
			"datasmith_db_image")
	case "postgres":
		runCmd = exec.Command(containerTool, "run", "--rm", "-d",
			"-e", "POSTGRES_PASSWORD=example",
			"-e", fmt.Sprintf("POSTGRES_DB=%s", config.Name),
			"-e", "POSTGRES_USER=user",
			"-p", "5432:5432",
			"--name", "datasmith_db_container",
			"datasmith_db_image")
	default:
		return fmt.Errorf("unsupported database type: %s", config.DbType)
	}

	runCmd.Stdout = os.Stdout
	runCmd.Stderr = os.Stderr
	return runCmd.Run()
}

func rebuildAndRestartContainer(containerTool string, config config.DatasmithConfig) error {
	fmt.Println("Stopping the current database container...")
	stopCmd := exec.Command(containerTool, "stop", "datasmith_db_container")
	stopCmd.Stdout = os.Stdout
	stopCmd.Stderr = os.Stderr
	if err := stopCmd.Run(); err != nil {
		return fmt.Errorf("error stopping database container: %v", err)
	}

	fmt.Println("Rebuilding the Docker image...")
	if err := buildDockerImage(containerTool, config); err != nil {
		return fmt.Errorf("error rebuilding Docker image: %v", err)
	}

	fmt.Println("Restarting the database container...")
	if err := startDatabaseContainer(containerTool, config); err != nil {
		return fmt.Errorf("error restarting database container: %v", err)
	}

	return nil
}

func printConnectionInfo(config config.DatasmithConfig) {
	fmt.Println("Connection Information:")
	switch config.DbType {
	case "mysql":
		fmt.Println("MySQL connection string:")
		fmt.Printf("Host: localhost\nPort: 3306\nDatabase: %s\nUser: user\nPassword: password\n", config.Name)
	case "postgres":
		fmt.Println("PostgreSQL connection string:")
		fmt.Printf("Host: localhost\nPort: 5432\nDatabase: %s\nUser: user\nPassword: password\n", config.Name)
	default:
		fmt.Printf("Unsupported database type: %s\n", config.DbType)
	}
}