package main

import (
	"context"
	"encoding/json"
	"log"
	"time"

	"github.com/google/uuid"
	faasclient "github.com/RyanCopley/skybridge/faas-client"
)

func main() {
	// Create FaaS client
	client := faasclient.NewClient(
		"http://localhost:8080",
		faasclient.WithUserEmail("admin@example.com"),
	)

	ctx := context.Background()

	// Create a simple Node.js function
	log.Println("Creating function...")
	createReq := &faasclient.CreateFunctionRequest{
		Name:    "hello-world-example",
		AppID:   "example-app",
		Runtime: faasclient.RuntimeNodeJS18,
		Handler: "index.handler",
		Code:    "exports.handler = async (event) => { return { message: 'Hello, ' + (event.name || 'World') + '!' }; }",
		Environment: map[string]string{
			"NODE_ENV": "production",
		},
		Timeout: faasclient.Duration(30 * time.Second),
		Memory:  256,
		Owner: faasclient.Owner{
			Type:  faasclient.OwnerTypeIndividual,
			Name:  "Example User",
			Owner: "admin@example.com",
		},
	}

	function, err := client.CreateFunction(ctx, createReq)
	if err != nil {
		log.Fatalf("Failed to create function: %v", err)
	}
	log.Printf("Created function: %s (ID: %s)", function.Name, function.ID)

	// Deploy the function
	log.Println("Deploying function...")
	deployResp, err := client.DeployFunction(ctx, function.ID, nil)
	if err != nil {
		log.Fatalf("Failed to deploy function: %v", err)
	}
	log.Printf("Deployment status: %s - %s", deployResp.Status, deployResp.Message)

	// Execute function synchronously
	log.Println("Executing function synchronously...")
	input := json.RawMessage(`{"name": "Skybridge"}`)
	executeReq := &faasclient.ExecuteFunctionRequest{
		FunctionID: function.ID,
		Input:      input,
		Async:      false,
	}

	execResp, err := client.ExecuteFunction(ctx, executeReq)
	if err != nil {
		log.Fatalf("Failed to execute function: %v", err)
	}
	log.Printf("Sync execution result: %s", string(execResp.Output))
	log.Printf("Duration: %v, Memory used: %d MB", execResp.Duration, execResp.MemoryUsed)

	// Execute function asynchronously
	log.Println("Invoking function asynchronously...")
	asyncResp, err := client.InvokeFunction(ctx, function.ID, input)
	if err != nil {
		log.Fatalf("Failed to invoke function: %v", err)
	}
	log.Printf("Async execution ID: %s, Status: %s", asyncResp.ExecutionID, asyncResp.Status)

	// Wait a moment for async execution to complete
	time.Sleep(2 * time.Second)

	// Get execution details
	log.Println("Getting execution details...")
	execution, err := client.GetExecution(ctx, asyncResp.ExecutionID)
	if err != nil {
		log.Fatalf("Failed to get execution: %v", err)
	}
	log.Printf("Execution status: %s", execution.Status)
	if execution.Status == faasclient.StatusCompleted {
		log.Printf("Async execution result: %s", string(execution.Output))
		log.Printf("Duration: %v, Memory used: %d MB", execution.Duration, execution.MemoryUsed)
	}

	// Get execution logs
	log.Println("Getting execution logs...")
	logs, err := client.GetExecutionLogs(ctx, asyncResp.ExecutionID)
	if err != nil {
		log.Printf("Failed to get logs: %v", err)
	} else {
		log.Printf("Logs (%d entries):", len(logs.Logs))
		for _, logLine := range logs.Logs {
			log.Printf("  %s", logLine)
		}
	}

	// List functions
	log.Println("Listing functions...")
	listResp, err := client.ListFunctions(ctx, "example-app", 10, 0)
	if err != nil {
		log.Fatalf("Failed to list functions: %v", err)
	}
	log.Printf("Found %d functions:", len(listResp.Functions))
	for _, fn := range listResp.Functions {
		log.Printf("  - %s (%s) - Runtime: %s", fn.Name, fn.ID, fn.Runtime)
	}

	// List executions for this function
	log.Println("Listing executions...")
	execListResp, err := client.ListExecutions(ctx, &function.ID, 10, 0)
	if err != nil {
		log.Fatalf("Failed to list executions: %v", err)
	}
	log.Printf("Found %d executions:", len(execListResp.Executions))
	for _, exec := range execListResp.Executions {
		status := string(exec.Status)
		log.Printf("  - %s: %s (Duration: %v)", exec.ID, status, exec.Duration)
	}

	// Clean up - delete the function
	log.Println("Cleaning up...")
	err = client.DeleteFunction(ctx, function.ID)
	if err != nil {
		log.Fatalf("Failed to delete function: %v", err)
	}
	log.Printf("Deleted function: %s", function.ID)

	log.Println("Example completed successfully!")
}

// Helper function to create a UUID from string (for testing)
func mustParseUUID(s string) uuid.UUID {
	id, err := uuid.Parse(s)
	if err != nil {
		panic(err)
	}
	return id
}