package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"os"

	"github.com/niveus/cloud-build-go/cloudbuild"
	"github.com/niveus/cloud-build-go/config"
)

func main() {
	// Define command-line flags
	configPath := flag.String("config", "config/config.json", "Path to config file")
	action := flag.String("action", "list-connections", "Action to perform: list-connections, create-gitlab, delete-connection, list-linkable-repos, inspect")
	connectionName := flag.String("name", "", "Name for the connection")
	flag.Parse()

	// Project ID, location, connection type will come from config file
	var projectIDValue, locationValue, connTypeValue string
	
	// Load config file
	cfg, err := config.LoadConfig(*configPath)
	if err != nil {
		log.Fatalf("Failed to load config file: %v", err)
	}
	// Set values from config file
	projectIDValue = cfg.ProjectID
	locationValue = cfg.Location
	connTypeValue = cfg.DefaultConnType
	
	// Log the values that will be used
	log.Printf("Config values set to: Project=%s, Location=%s, Type=%s", 
		projectIDValue, locationValue, connTypeValue)
	
	// Check for required values after loading from config
	if projectIDValue == "" {
		log.Fatal("project ID is required in the config file")
	}

	// We no longer need this validation because each case will handle missing connection names by
	// automatically using values from the config file
	// Validation still happens in each case for more specific handling

	ctx := context.Background()

	// Create a Cloud Build client using our package
	var client *cloudbuild.Client
	
	// Authentication approach Application Default Credentials
	client, err = cloudbuild.NewClient(ctx)
	if err != nil {
		log.Fatalf("Failed to create Cloud Build client: %v", err)
	}

	// Perform the requested action
	switch *action {

	case "create-gitlab":
		// Find the connection config for the given name
		var connConfig *config.ConnectionConfig
		for _, conn := range cfg.Connections {
			if conn.Name == *connectionName || *connectionName == "" && len(cfg.Connections) == 1 {
				connConfig = &conn
				break
			}
		}
		
		if connConfig == nil {
			if *connectionName == "" {
				log.Fatalf("No connection configuration found in config file. Please add connections to your config file.")
			} else {
				log.Fatalf("No connection configuration found for name '%s' in config file", *connectionName)
			}
		}
		
		// Check if the connection config has GitLab configuration
		if connConfig.GitlabConfig == nil {
			log.Fatalf("Connection '%s' does not have GitLab configuration", connConfig.Name)
		}
		
		log.Printf("Creating GitLab connection using config: ProjectID=%s, Location=%s, Name=%s", 
			projectIDValue, locationValue, connConfig.Name)
		
		fmt.Printf("Creating GitLab connection '%s' in project '%s' (location: '%s')\n", 
			connConfig.Name, projectIDValue, locationValue)
		
		// Create the GitLab connection using the Cloud Build SDK
		err = client.CreateGitLabConnection(
			projectIDValue, 
			locationValue, 
			connConfig.Name, 
			connConfig.GitlabConfig,
			connConfig.Annotations,
		)
		if err != nil {
			log.Fatalf("Failed to create GitLab connection: %v", err)
		}
		
		fmt.Printf("Successfully created GitLab connection: %s\n", 
			fmt.Sprintf("projects/%s/locations/%s/connections/%s", projectIDValue, locationValue, connConfig.Name))

	case "list-connections":
		// Use project ID and location from config
		log.Printf("Listing connections in project %s (location: %s)", projectIDValue, locationValue)
		
		connections, err := client.ListConnections(projectIDValue, locationValue)
		if err != nil {
			log.Fatalf("Failed to list connections: %v", err)
		}
		fmt.Printf("Found %d connections in project %s (location: %s):\n", 
			len(connections), projectIDValue, locationValue)
		for i, conn := range connections {
			// Determine connection type based on config
			connType := "Unknown"
			if conn.GithubConfig != nil {
				connType = "GitHub"
			} else if conn.GitlabConfig != nil {
				connType = "GitLab"
			}
			fmt.Printf("%d. %s (Type: %s)\n", i+1, conn.Name, connType)
		}

	case "delete-connection":
		// If connection name not provided via command line, get it from config
		connNameToDelete := *connectionName
		if connNameToDelete == "" {
			// If there's only one connection in config, use that
			if len(cfg.Connections) == 1 {
				connNameToDelete = cfg.Connections[0].Name
				fmt.Printf("Using connection name from config: %s\n", connNameToDelete)
			} else if len(cfg.Connections) > 1 {
				// If multiple connections, show the available options
				fmt.Println("Multiple connections found in config. Please specify which one to delete with --name flag:")
				for i, conn := range cfg.Connections {
					fmt.Printf("%d. %s\n", i+1, conn.Name)
				}
				os.Exit(1)
			} else {
				log.Fatalf("No connections found in config file")
			}
		}
		
		log.Printf("Deleting connection %s in project %s (location: %s)", 
			connNameToDelete, projectIDValue, locationValue)
		
		err := client.DeleteConnection(projectIDValue, locationValue, connNameToDelete)
		if err != nil {
			log.Fatalf("Failed to delete connection: %v", err)
		}
		fmt.Printf("Successfully deleted connection: %s\n", connNameToDelete)

	case "list-linkable-repos":
		// If connection name not provided via command line, get it from config
		connNameToList := *connectionName
		if connNameToList == "" {
			// If there's only one connection in config, use that
			if len(cfg.Connections) == 1 {
				connNameToList = cfg.Connections[0].Name
				fmt.Printf("Using connection name from config: %s\n", connNameToList)
			} else if len(cfg.Connections) > 1 {
				// If multiple connections, show the available options
				fmt.Println("Multiple connections found in config. Please specify which one to use with --name flag:")
				for i, conn := range cfg.Connections {
					fmt.Printf("%d. %s\n", i+1, conn.Name)
				}
				os.Exit(1)
			} else {
				log.Fatalf("No connections found in config file")
			}
		}
		
		log.Printf("Listing linkable repositories for connection %s in project %s (location: %s)", 
			connNameToList, projectIDValue, locationValue)
		
		repositories, err := client.ListLinkableRepositories(projectIDValue, locationValue, connNameToList)
		if err != nil {
			log.Fatalf("Failed to list linkable repositories: %v", err)
		}
		fmt.Printf("Found %d linkable repositories for connection %s:\n", 
			len(repositories), connNameToList)
		for i, repo := range repositories {
			fmt.Printf("%d. %s\n", i+1, repo.Name)
			if repo.RemoteUri != "" {
				fmt.Printf("   URI: %s\n", repo.RemoteUri)
			}
			// Add a blank line between repositories for better readability
			if i < len(repositories)-1 {
				fmt.Println()
			}
		}
	
	case "inspect":
		// This action provides detailed inspection of a connection's configuration and status
		// If connection name not provided via command line, get it from config
		connNameToInspect := *connectionName
		if connNameToInspect == "" {
			// If there's only one connection in config, use that
			if len(cfg.Connections) == 1 {
				connNameToInspect = cfg.Connections[0].Name
				fmt.Printf("Using connection name from config: %s\n", connNameToInspect)
			} else if len(cfg.Connections) > 1 {
				// If multiple connections, show the available options
				fmt.Println("Multiple connections found in config. Please specify which one to inspect with --name flag:")
				for i, conn := range cfg.Connections {
					fmt.Printf("%d. %s\n", i+1, conn.Name)
				}
				os.Exit(1)
			} else {
				log.Fatalf("No connections found in config file")
			}
		}
		
		log.Printf("Inspecting connection %s in project %s (location: %s)", 
			connNameToInspect, projectIDValue, locationValue)
		
		fmt.Printf("Inspecting connection %s in project %s (location: %s)...\n\n", 
			connNameToInspect, projectIDValue, locationValue)
		err := client.InspectConnection(projectIDValue, locationValue, connNameToInspect)
		if err != nil {
			log.Fatalf("Failed to inspect connection: %v", err)
		}
		
	default:
		log.Fatalf("Unknown action: %s. Supported actions are: list-connections, create-gitlab, delete-connection, list-linkable-repos, inspect", *action)
	}
}
