package main

import (
	"context"
	"fmt"
	"os"
	"strings"

	v1alpha1 "github.com/pfeifferj/container-mom-go/pkg/apis/containermom/v1alpha1"
	"github.com/pfeifferj/container-mom-go/pkg/billing"
	"github.com/pfeifferj/container-mom-go/pkg/config"
	"github.com/pfeifferj/container-mom-go/pkg/forgejo"
	"github.com/pfeifferj/container-mom-go/pkg/operator"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"sigs.k8s.io/controller-runtime/pkg/client"
	ctrlconfig "sigs.k8s.io/controller-runtime/pkg/client/config"
)

func main() {
	if len(os.Args) < 2 {
		fmt.Println("Usage: instantiate_template <template-name> [param1=value1 param2=value2 ...] [--git-push]")
		os.Exit(1)
	}

	// Check if we should push to git
	pushToGit := false
	for i, arg := range os.Args {
		if arg == "--git-push" {
			pushToGit = true
			// Remove this flag from args
			os.Args = append(os.Args[:i], os.Args[i+1:]...)
			break
		}
	}

	templateName := os.Args[1]
	namespace := "default"
	if len(os.Args) > 2 && strings.HasPrefix(os.Args[2], "namespace=") {
		namespace = strings.TrimPrefix(os.Args[2], "namespace=")
		os.Args = append(os.Args[:2], os.Args[3:]...)
	}

	// Extract customer ID
	customerID := ""
	for i, arg := range os.Args {
		if strings.HasPrefix(arg, "customer-id=") {
			customerID = strings.TrimPrefix(arg, "customer-id=")
			// Remove from args
			os.Args = append(os.Args[:i], os.Args[i+1:]...)
			break
		}
	}

	// Extract app name
	appName := ""
	for i, arg := range os.Args {
		if strings.HasPrefix(arg, "app-name=") {
			appName = strings.TrimPrefix(arg, "app-name=")
			// Remove from args
			os.Args = append(os.Args[:i], os.Args[i+1:]...)
			break
		}
	}

	// Parse parameters
	params := make(map[string]string)
	for i := 2; i < len(os.Args); i++ {
		parts := strings.SplitN(os.Args[i], "=", 2)
		if len(parts) == 2 {
			params[parts[0]] = parts[1]
		}
	}

	// If customer ID is provided, add it to params for template processing
	if customerID != "" {
		params["customer_id"] = customerID
	}

	// Setup k8s client
	kubeConfig, err := ctrlconfig.GetConfig()
	if err != nil {
		fmt.Printf("Error getting kubeconfig: %v\n", err)
		os.Exit(1)
	}

	k8sClient, err := client.New(kubeConfig, client.Options{})
	if err != nil {
		fmt.Printf("Error creating kubernetes client: %v\n", err)
		os.Exit(1)
	}

	// Create config
	cfg := &config.Config{
		ListenAddr: ":8081",
	}

	// Create billing service
	billingService := billing.NewService("", "")

	// Create operator
	op, err := operator.New(cfg, billingService)
	if err != nil {
		fmt.Printf("Error creating operator: %v\n", err)
		os.Exit(1)
	}

	// Print what we're doing
	fmt.Printf("Instantiating template '%s' in namespace '%s' with parameters:\n", templateName, namespace)
	for k, v := range params {
		fmt.Printf("  %s: %s\n", k, v)
	}

	// Instantiate the template in Kubernetes
	err = op.InstantiateTemplate(context.Background(), templateName, namespace, params)
	if err != nil {
		fmt.Printf("Error instantiating template: %v\n", err)
		os.Exit(1)
	}

	fmt.Printf("Template '%s' instantiated successfully in namespace '%s'\n", templateName, namespace)

	// If not pushing to git, we're done
	if !pushToGit {
		return
	}

	// Configure Forgejo client
	forgejoBaseURL := os.Getenv("FORGEJO_BASE_URL")
	if forgejoBaseURL == "" {
		forgejoBaseURL = os.Getenv("GITEA_BASE_URL") // Fallback for backward compatibility
		if forgejoBaseURL == "" {
			forgejoBaseURL = "https://git.container.mom"
		}
	}

	forgejoToken := os.Getenv("FORGEJO_TOKEN")
	if forgejoToken == "" {
		forgejoToken = os.Getenv("GITEA_TOKEN") // Fallback for backward compatibility
	}

	forgejoUsername := os.Getenv("FORGEJO_USERNAME")
	if forgejoUsername == "" {
		forgejoUsername = os.Getenv("GITEA_USERNAME") // Fallback for backward compatibility
	}

	forgejoPassword := os.Getenv("FORGEJO_PASSWORD")
	if forgejoPassword == "" {
		forgejoPassword = os.Getenv("GITEA_PASSWORD") // Fallback for backward compatibility
	}

	forgejoOrg := os.Getenv("FORGEJO_ORG")
	if forgejoOrg == "" {
		forgejoOrg = os.Getenv("GITEA_ORG") // Fallback for backward compatibility
	}

	if forgejoToken == "" && (forgejoUsername == "" || forgejoPassword == "") {
		fmt.Println("Warning: No Forgejo credentials provided. Set FORGEJO_TOKEN or FORGEJO_USERNAME/FORGEJO_PASSWORD. Skipping git operations.")
		return
	}

	// Create Forgejo service
	forgejoService, err := forgejo.NewService(&forgejo.Config{
		BaseURL:      forgejoBaseURL,
		Token:        forgejoToken,
		Username:     forgejoUsername,
		Password:     forgejoPassword,
		Organization: forgejoOrg,
	})
	if err != nil {
		fmt.Printf("Error creating Forgejo service: %v\n", err)
		os.Exit(1)
	}

	// Get the customer repo name (use customer ID if available, otherwise template name)
	repoName := ""
	if customerID != "" {
		repoName = fmt.Sprintf("customer-%s", customerID)
	} else {
		repoName = fmt.Sprintf("template-%s", templateName)
	}

	// Get template object to pass to Forgejo
	ctx := context.Background()
	templateObj := &v1alpha1.Template{}
	err = k8sClient.Get(ctx, client.ObjectKey{Name: templateName, Namespace: namespace}, templateObj)
	if err != nil {
		fmt.Printf("Error getting template object: %v\n", err)
		os.Exit(1)
	}

	// Create or get customer repository
	repoOwner := forgejoOrg
	if repoOwner == "" {
		// If no org specified, the service will use the authenticated user
		repoOwner = forgejoUsername
	}

	fmt.Printf("Creating/updating repository %s/%s...\n", repoOwner, repoName)
	repoFullName, err := forgejoService.CreateCustomerRepo(ctx, customerID, repoName)
	if err != nil {
		fmt.Printf("Error creating/getting repository: %v\n", err)
		os.Exit(1)
	}

	// Create app-of-apps chart if it doesn't exist
	fmt.Printf("Creating/updating app-of-apps Helm chart in %s...\n", repoFullName)
	repoParts := strings.Split(repoFullName, "/")
	if len(repoParts) != 2 {
		fmt.Printf("Error: Invalid repository name format: %s\n", repoFullName)
		os.Exit(1)
	}

	// Create or update the app-of-apps chart
	err = forgejoService.CreateAppOfAppsChart(ctx, repoParts[0], repoParts[1])
	if err != nil {
		fmt.Printf("Error creating app-of-apps chart: %v\n", err)
		os.Exit(1)
	}

	// Push template values to git
	if appName == "" {
		if templateName != "" {
			appName = templateName
		} else {
			appName = fmt.Sprintf("app-%d", metav1.Now().Unix())
		}
	}

	fmt.Printf("Pushing template values for app %s to repository...\n", appName)
	err = forgejoService.PushTemplateValues(ctx, repoParts[0], repoParts[1], templateObj, params, appName)
	if err != nil {
		fmt.Printf("Error pushing template values: %v\n", err)
		os.Exit(1)
	}

	fmt.Printf("Successfully added application '%s' to app-of-apps values.yaml in repository %s\n", appName, repoFullName)
	fmt.Printf("ArgoCD will automatically sync this application\n")
}
