// ABOUTME: CLI command for deleting EdgeConnect applications from YAML configuration
// ABOUTME: Removes applications and their instances based on configuration file specification
package cmd

import (
	"context"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"

	"edp.buildth.ing/DevFW-CICD/edge-connect-client/v2/internal/config"
	deletev1 "edp.buildth.ing/DevFW-CICD/edge-connect-client/v2/internal/delete/v1"
	deletev2 "edp.buildth.ing/DevFW-CICD/edge-connect-client/v2/internal/delete/v2"
	"github.com/spf13/cobra"
)

var (
	deleteConfigFile  string
	deleteDryRun      bool
	deleteAutoApprove bool
)

var deleteCmd = &cobra.Command{
	Use:   "delete",
	Short: "Delete EdgeConnect applications from configuration files",
	Long: `Delete EdgeConnect applications and their instances based on YAML configuration files.
This command reads a configuration file, finds matching resources, and deletes them.
Instances are always deleted before the application.`,
	Run: func(cmd *cobra.Command, args []string) {
		if deleteConfigFile == "" {
			fmt.Fprintf(os.Stderr, "Error: configuration file is required\n")
			_ = cmd.Usage()
			os.Exit(1)
		}

		if err := runDelete(deleteConfigFile, deleteDryRun, deleteAutoApprove); err != nil {
			fmt.Fprintf(os.Stderr, "Error: %v\n", err)
			os.Exit(1)
		}
	},
}

func runDelete(configPath string, isDryRun bool, autoApprove bool) error {
	// Step 1: Validate and resolve config file path
	absPath, err := filepath.Abs(configPath)
	if err != nil {
		return fmt.Errorf("failed to resolve config file path: %w", err)
	}

	if _, err := os.Stat(absPath); os.IsNotExist(err) {
		return fmt.Errorf("configuration file not found: %s", absPath)
	}

	fmt.Printf("📄 Loading configuration from: %s\n", absPath)

	// Step 2: Parse and validate configuration
	parser := config.NewParser()
	cfg, _, err := parser.ParseFile(absPath)
	if err != nil {
		return fmt.Errorf("failed to parse configuration: %w", err)
	}

	if err := parser.Validate(cfg); err != nil {
		return fmt.Errorf("configuration validation failed: %w", err)
	}

	fmt.Printf("✅ Configuration loaded successfully: %s\n", cfg.Metadata.Name)

	// Step 3: Determine API version and create appropriate client
	apiVersion := getAPIVersion()

	// Step 4: Execute deletion based on API version
	if apiVersion == "v1" {
		return runDeleteV1(cfg, isDryRun, autoApprove)
	}
	return runDeleteV2(cfg, isDryRun, autoApprove)
}

func runDeleteV1(cfg *config.EdgeConnectConfig, isDryRun bool, autoApprove bool) error {
	// Create v1 client
	client := newSDKClientV1()

	// Create deletion planner
	planner := deletev1.NewPlanner(client)

	// Generate deletion plan
	fmt.Println("🔍 Analyzing current state and generating deletion plan...")

	planOptions := deletev1.DefaultPlanOptions()
	planOptions.DryRun = isDryRun

	result, err := planner.PlanWithOptions(context.Background(), cfg, planOptions)
	if err != nil {
		return fmt.Errorf("failed to generate deletion plan: %w", err)
	}

	// Display plan summary
	fmt.Println("\n📋 Deletion Plan:")
	fmt.Println(strings.Repeat("=", 50))
	fmt.Println(result.Plan.Summary)
	fmt.Println(strings.Repeat("=", 50))

	// Display warnings if any
	if len(result.Warnings) > 0 {
		fmt.Println("\n⚠️  Warnings:")
		for _, warning := range result.Warnings {
			fmt.Printf("   • %s\n", warning)
		}
	}

	// If dry-run, stop here
	if isDryRun {
		fmt.Println("\n🔍 Dry-run complete. No changes were made.")
		return nil
	}

	// Check if there's anything to delete
	if result.Plan.TotalActions == 0 {
		fmt.Println("\n✅ No resources found to delete.")
		return nil
	}

	fmt.Printf("\nThis will delete %d resource(s). Estimated time: %v\n",
		result.Plan.TotalActions, result.Plan.EstimatedDuration)

	if !autoApprove && !confirmDeletion() {
		fmt.Println("Deletion cancelled.")
		return nil
	}

	// Execute deletion
	fmt.Println("\n🗑️  Starting deletion...")

	manager := deletev1.NewResourceManager(client, deletev1.WithLogger(log.Default()))
	deleteResult, err := manager.ExecuteDeletion(context.Background(), result.Plan)
	if err != nil {
		return fmt.Errorf("deletion failed: %w", err)
	}

	// Display results
	return displayDeletionResults(deleteResult)
}

func runDeleteV2(cfg *config.EdgeConnectConfig, isDryRun bool, autoApprove bool) error {
	// Create v2 client
	client := newSDKClientV2()

	// Create deletion planner
	planner := deletev2.NewPlanner(client)

	// Generate deletion plan
	fmt.Println("🔍 Analyzing current state and generating deletion plan...")

	planOptions := deletev2.DefaultPlanOptions()
	planOptions.DryRun = isDryRun

	result, err := planner.PlanWithOptions(context.Background(), cfg, planOptions)
	if err != nil {
		return fmt.Errorf("failed to generate deletion plan: %w", err)
	}

	// Display plan summary
	fmt.Println("\n📋 Deletion Plan:")
	fmt.Println(strings.Repeat("=", 50))
	fmt.Println(result.Plan.Summary)
	fmt.Println(strings.Repeat("=", 50))

	// Display warnings if any
	if len(result.Warnings) > 0 {
		fmt.Println("\n⚠️  Warnings:")
		for _, warning := range result.Warnings {
			fmt.Printf("   • %s\n", warning)
		}
	}

	// If dry-run, stop here
	if isDryRun {
		fmt.Println("\n🔍 Dry-run complete. No changes were made.")
		return nil
	}

	// Check if there's anything to delete
	if result.Plan.TotalActions == 0 {
		fmt.Println("\n✅ No resources found to delete.")
		return nil
	}

	fmt.Printf("\nThis will delete %d resource(s). Estimated time: %v\n",
		result.Plan.TotalActions, result.Plan.EstimatedDuration)

	if !autoApprove && !confirmDeletion() {
		fmt.Println("Deletion cancelled.")
		return nil
	}

	// Execute deletion
	fmt.Println("\n🗑️  Starting deletion...")

	manager := deletev2.NewResourceManager(client, deletev2.WithLogger(log.Default()))
	deleteResult, err := manager.ExecuteDeletion(context.Background(), result.Plan)
	if err != nil {
		return fmt.Errorf("deletion failed: %w", err)
	}

	// Display results
	return displayDeletionResults(deleteResult)
}

func displayDeletionResults(result interface{}) error {
	// Use type assertion to handle both v1 and v2 result types
	switch r := result.(type) {
	case *deletev1.DeletionResult:
		return displayDeletionResultsV1(r)
	case *deletev2.DeletionResult:
		return displayDeletionResultsV2(r)
	default:
		return fmt.Errorf("unknown deletion result type")
	}
}

func displayDeletionResultsV1(deleteResult *deletev1.DeletionResult) error {
	if deleteResult.Success {
		fmt.Printf("\n✅ Deletion completed successfully in %v\n", deleteResult.Duration)
		if len(deleteResult.CompletedActions) > 0 {
			fmt.Println("\nDeleted resources:")
			for _, action := range deleteResult.CompletedActions {
				fmt.Printf("   ✅ %s %s\n", action.Type, action.Target)
			}
		}
	} else {
		fmt.Printf("\n❌ Deletion failed after %v\n", deleteResult.Duration)
		if deleteResult.Error != nil {
			fmt.Printf("Error: %v\n", deleteResult.Error)
		}
		if len(deleteResult.FailedActions) > 0 {
			fmt.Println("\nFailed actions:")
			for _, action := range deleteResult.FailedActions {
				fmt.Printf("   ❌ %s %s: %v\n", action.Type, action.Target, action.Error)
			}
		}
		return fmt.Errorf("deletion failed with %d failed actions", len(deleteResult.FailedActions))
	}
	return nil
}

func displayDeletionResultsV2(deleteResult *deletev2.DeletionResult) error {
	if deleteResult.Success {
		fmt.Printf("\n✅ Deletion completed successfully in %v\n", deleteResult.Duration)
		if len(deleteResult.CompletedActions) > 0 {
			fmt.Println("\nDeleted resources:")
			for _, action := range deleteResult.CompletedActions {
				fmt.Printf("   ✅ %s %s\n", action.Type, action.Target)
			}
		}
	} else {
		fmt.Printf("\n❌ Deletion failed after %v\n", deleteResult.Duration)
		if deleteResult.Error != nil {
			fmt.Printf("Error: %v\n", deleteResult.Error)
		}
		if len(deleteResult.FailedActions) > 0 {
			fmt.Println("\nFailed actions:")
			for _, action := range deleteResult.FailedActions {
				fmt.Printf("   ❌ %s %s: %v\n", action.Type, action.Target, action.Error)
			}
		}
		return fmt.Errorf("deletion failed with %d failed actions", len(deleteResult.FailedActions))
	}
	return nil
}

func confirmDeletion() bool {
	fmt.Print("Do you want to proceed with deletion? (yes/no): ")
	var response string
	_, _ = fmt.Scanln(&response)

	switch response {
	case "yes", "y", "YES", "Y":
		return true
	default:
		return false
	}
}

func init() {
	rootCmd.AddCommand(deleteCmd)

	deleteCmd.Flags().StringVarP(&deleteConfigFile, "file", "f", "", "configuration file path (required)")
	deleteCmd.Flags().BoolVar(&deleteDryRun, "dry-run", false, "preview deletion without actually deleting resources")
	deleteCmd.Flags().BoolVar(&deleteAutoApprove, "auto-approve", false, "automatically approve the deletion plan")

	if err := deleteCmd.MarkFlagRequired("file"); err != nil {
		panic(err)
	}
}
