// ABOUTME: Example demonstrating EdgeXR SDK usage for app deployment workflow
// ABOUTME: Shows app creation, querying, and cleanup using the typed SDK APIs

package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"os"
	"time"

	"edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/adapters/driven/edgeconnect"
	"edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/domain"
)

func main() {
	// Configure SDK client
	baseURL := getEnvOrDefault("EDGEXR_BASE_URL", "https://hub.apps.edge.platform.mg3.mdb.osc.live")

	// Support both token-based and username/password authentication
	token := getEnvOrDefault("EDGEXR_TOKEN", "")
	username := getEnvOrDefault("EDGEXR_USERNAME", "")
	password := getEnvOrDefault("EDGEXR_PASSWORD", "")

	var edgeClient *edgeconnect.Client

	if token != "" {
		// Use static token authentication
		fmt.Println("🔐 Using Bearer token authentication")
		edgeClient = edgeconnect.NewClient(baseURL,
			edgeconnect.WithHTTPClient(&http.Client{Timeout: 30 * time.Second}),
			edgeconnect.WithAuthProvider(edgeconnect.NewStaticTokenProvider(token)),
			edgeconnect.WithLogger(log.Default()),
		)
	} else if username != "" && password != "" {
		// Use username/password authentication (matches existing client pattern)
		fmt.Println("🔐 Using username/password authentication")
		edgeClient = edgeconnect.NewClientWithCredentials(baseURL, username, password,
			edgeconnect.WithHTTPClient(&http.Client{Timeout: 30 * time.Second}),
			edgeconnect.WithLogger(log.Default()),
		)
	} else {
		log.Fatal("Authentication required: Set either EDGEXR_TOKEN or both EDGEXR_USERNAME and EDGEXR_PASSWORD")
	}

	ctx := context.Background()

	// Example application to deploy
	app := &edgeconnect.NewAppInput{
		Region: "EU",
		App: edgeconnect.App{
			Key: edgeconnect.AppKey{
				Organization: "edp2",
				Name:         "my-edge-app",
				Version:      "1.0.0",
			},
			Deployment:       "docker",
			ImageType:        "ImageTypeDocker",
			ImagePath:        "https://registry-1.docker.io/library/nginx:latest",
			DefaultFlavor:    edgeconnect.Flavor{Name: "EU.small"},
			ServerlessConfig: struct{}{},
			AllowServerless:  false,
		},
	}

	// Demonstrate app lifecycle
	if err := demonstrateAppLifecycle(ctx, edgeClient, app); err != nil {
		log.Fatalf("App lifecycle demonstration failed: %v", err)
	}

	fmt.Println("✅ SDK example completed successfully!")
}

func demonstrateAppLifecycle(ctx context.Context, edgeClient *edgeconnect.Client, input *edgeconnect.NewAppInput) error {
	appKey := input.App.Key
	region := input.Region
	var domainAppKey domain.AppKey

	fmt.Printf("🚀 Demonstrating EdgeXR SDK with app: %s/%s v%s\n",
		appKey.Organization, appKey.Name, appKey.Version)

	// Step 1: Create the application
	fmt.Println("\n1. Creating application...")
	domainApp := &domain.App{
		Key: domain.AppKey{
			Organization: input.App.Key.Organization,
			Name:         input.App.Key.Name,
			Version:      input.App.Key.Version,
		},
		Deployment:       input.App.Deployment,
		ImageType:        input.App.ImageType,
		ImagePath:        input.App.ImagePath,
		DefaultFlavor:    domain.Flavor{Name: input.App.DefaultFlavor.Name},
		ServerlessConfig: input.App.ServerlessConfig,
		AllowServerless:  input.App.AllowServerless,
	}
	if err := edgeClient.CreateApp(ctx, input.Region, domainApp); err != nil {
		return fmt.Errorf("failed to create app: %+v", err)
	}
	fmt.Printf("✅ App created: %s/%s v%s\n", appKey.Organization, appKey.Name, appKey.Version)

	// Step 2: Query the application
	fmt.Println("\n2. Querying application...")
	domainAppKey = domain.AppKey{
		Organization: appKey.Organization,
		Name:         appKey.Name,
		Version:      appKey.Version,
	}
	app, err := edgeClient.ShowApp(ctx, region, domainAppKey)
	if err != nil {
		return fmt.Errorf("failed to show app: %w", err)
	}
	fmt.Printf("✅ App found: %s/%s v%s (deployment: %s)\n",
		app.Key.Organization, app.Key.Name, app.Key.Version, app.Deployment)

	// Step 3: List applications in the organization
	fmt.Println("\n3. Listing applications...")
	filter := domain.AppKey{Organization: appKey.Organization}
	apps, err := edgeClient.ShowApps(ctx, region, filter)
	if err != nil {
		return fmt.Errorf("failed to list apps: %w", err)
	}
	fmt.Printf("✅ Found %d applications in organization '%s'\n", len(apps), appKey.Organization)

	// Step 4: Clean up - delete the application
	fmt.Println("\n4. Cleaning up...")
	domainAppKey = domain.AppKey{
		Organization: appKey.Organization,
		Name:         appKey.Name,
		Version:      appKey.Version,
	}
	if err := edgeClient.DeleteApp(ctx, region, domainAppKey); err != nil {
		return fmt.Errorf("failed to delete app: %w", err)
	}
	fmt.Printf("✅ App deleted: %s/%s v%s\n", appKey.Organization, appKey.Name, appKey.Version)

	// Step 5: Verify deletion
	fmt.Println("\n5. Verifying deletion...")
	domainAppKey = domain.AppKey{
		Organization: appKey.Organization,
		Name:         appKey.Name,
		Version:      appKey.Version,
	}
	_, err = edgeClient.ShowApp(ctx, region, domainAppKey)
	if err != nil {
		if domain.IsNotFoundError(err) {
			fmt.Printf("✅ App successfully deleted (not found)\n")
		} else {
			return fmt.Errorf("unexpected error verifying deletion: %w", err)
		}
	} else {
		return fmt.Errorf("app still exists after deletion")
	}

	return nil
}

func getEnvOrDefault(key, defaultValue string) string {
	if value := os.Getenv(key); value != "" {
		return value
	}
	return defaultValue
}
