package cmd

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"os/exec"
	"strings"
)

func isRepoValid(name string, exclude []string) bool {
	for _, str := range exclude {
		if strings.Contains(name, str) {
			return false
		}
	}
	return true
}

func deleteFolderIfExists(path string) error {
	// Check if the path exists
	if _, err := os.Stat(path); os.IsNotExist(err) {
		// Path does not exist, nothing to do
		return nil
	}
	// Path exists, attempt to delete it
	err := os.RemoveAll(path)
	if err != nil {
		return fmt.Errorf("failed to delete repository: %w", err)
	}
	return nil
}

type Repository struct {
	Name     string `json:"name"`
	CloneURL string `json:"clone_url"`
}

func getRepositories(server, username string) ([]Repository, error) {
	url := fmt.Sprintf("https://%s/api/v1/users/%s/repos", server, username)

	// Create a new request using http
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}

	// Send the request via a client
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	// Read the response body
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	// Check if the response code is OK (200)
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("failed to retrieve repositories: %s", resp.Status)
	}

	// Unmarshal the JSON response into a slice of Repository structs
	var repos []Repository
	err = json.Unmarshal(body, &repos)
	if err != nil {
		return nil, err
	}

	return repos, nil
}

func fileExists(filename string) bool {
	info, err := os.Stat(filename)
	if os.IsNotExist(err) {
		return false
	}
	return !info.IsDir()
}

// runCommand runs a given command with arguments and streams stdout and stderr in real time.
func runCommand(cmdName string, args ...string) error {
	cmd := exec.Command(cmdName, args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

// processFolder takes a folder path, changes to that directory, runs a series of commands, and returns to the initial directory.
func processFolder(folder string, commands [][]string) error {

	// Store the initial directory
	initialDir, err := os.Getwd()
	if err != nil {
		return fmt.Errorf("failed to get current directory: %w", err)
	}

	// Change to the target directory
	err = os.Chdir(folder)
	if err != nil {
		return fmt.Errorf("failed to change directory to %s: %w", folder, err)
	}

	// Run the specified commands in the folder
	for _, command := range commands {
		if len(command) == 0 {
			continue
		}
		cmdName := command[0]
		cmdArgs := command[1:]
		fmt.Printf("Running command: %s %v in folder %s\n", cmdName, cmdArgs, folder)
		if err := runCommand(cmdName, cmdArgs...); err != nil {
			fmt.Printf("Command %s failed with error: %v\n", cmdName, err)
		}
	}

	// Change back to the initial directory
	err = os.Chdir(initialDir)
	if err != nil {
		return fmt.Errorf("failed to return to initial directory %s: %w", initialDir, err)
	}

	return nil
}

func updatePortInJSONFile(inputFile string, outputFile string, newPort int) (bool, error) {
	// Read the JSON file
	file, err := os.ReadFile(inputFile)
	if err != nil {
		return false, err
	}

	// Unmarshal the JSON into a map[string]interface{}
	var data map[string]interface{}
	err = json.Unmarshal(file, &data)
	if err != nil {
		return false, err
	}

	// Check if the "port" key exists
	if _, exists := data["port"]; exists {
		// Update the "port" key with the new value
		data["port"] = newPort

		// Marshal the updated map back to JSON
		updatedJSON, err := json.MarshalIndent(data, "", "  ")
		if err != nil {
			return false, err
		}

		// Write the updated JSON back to the file
		err = os.WriteFile(outputFile, updatedJSON, os.ModePerm)
		if err != nil {
			return false, err
		}

		// Return true indicating the "port" key was found and updated
		return true, nil
	}

	// Return false if the "port" key was not found
	return false, nil
}

func writeCaddyfile(routes map[string]int, filename string) error {
	// Create or open the file
	file, err := os.Create(filename)
	if err != nil {
		return fmt.Errorf("failed to create or open file: %w", err)
	}
	defer file.Close()

	// Write the global options or any other required headers
	_, err = file.WriteString(`{
	# Global options
	auto_https off
}

:8080 {
	root * ./web
	file_server
	route {
`)
	if err != nil {
		return fmt.Errorf("failed to write to file: %w", err)
	}

	// Iterate over the map and generate the routes
	for path, port := range routes {
		routeConfig := fmt.Sprintf(`
		handle_path /%s/* {
			rewrite * /oc{path}
			reverse_proxy localhost:%d
		}
		`, path, port)

		_, err = file.WriteString(routeConfig)
		if err != nil {
			return fmt.Errorf("failed to write route to file: %w", err)
		}
	}

	// Write the closing braces
	_, err = file.WriteString(`
	}
}
`)
	if err != nil {
		return fmt.Errorf("failed to write closing braces to file: %w", err)
	}

	return nil
}
