package cmd

import (
	"context"
	"fmt"
	"strings"
	"time"

	"github.com/giantswarm/muster/internal/api"
	"github.com/giantswarm/muster/internal/cli"

	"github.com/spf13/cobra"
)

var (
	eventsFlags        cli.CommandFlags
	eventsResourceType string
	eventsResourceName string
	eventsNamespace    string
	eventsEventType    string
	eventsSince        string
	eventsUntil        string
	eventsLimit        int
	eventsFollow       bool
)

// eventsCmd represents the events command
var eventsCmd = &cobra.Command{
	Use:   "events",
	Short: "List events for muster resources",
	Long: `List and filter events for muster resources in both Kubernetes and filesystem modes.

This command provides access to event history for muster components including
MCPServers and Workflows. Events are automatically generated during resource
lifecycle operations and can be queried with various filters.

Filtering Options:
  --resource-type     Filter by resource type (mcpserver, workflow)
  --resource-name     Filter by specific resource name
  --namespace         Filter by namespace (default: all namespaces)
  --type              Filter by event type (Normal, Warning)
  --since             Show events after this time (1h, 30m, 2024-01-15T10:00:00Z)
  --until             Show events before this time (2024-01-15T18:00:00Z)
  --limit             Limit number of events returned (default: 50)
  --follow, -f        Stream new events as they occur (follow mode)

Examples:
  # List all recent events
  muster events

  # Filter by resource type
  muster events --resource-type mcpserver
  muster events --resource-type workflow

  # Filter by specific resource
  muster events --resource-type mcpserver --resource-name prometheus

  # Filter by namespace
  muster events --namespace default
  muster events --namespace muster-system

  # Filter by time range
  muster events --since 1h
  muster events --since 2024-01-15T10:00:00Z --until 2024-01-15T18:00:00Z

  # Filter by event type
  muster events --type Warning
  muster events --type Normal

  # Combine filters and change output format
  muster events --resource-type mcpserver --namespace default --limit 20 --output json

  # Stream new events (follow mode)
  muster events --follow
  muster events --resource-type mcpserver --follow

  # Stream events with filters
  muster events --namespace default --type Warning --follow

Note: The aggregator server must be running (use 'muster serve') before using this command.`,
	Args:                  cobra.NoArgs,
	DisableFlagsInUseLine: true,
	RunE:                  runEvents,
}

func init() {
	rootCmd.AddCommand(eventsCmd)
	cli.RegisterCommonFlags(eventsCmd, &eventsFlags)

	// Filtering flags
	eventsCmd.PersistentFlags().StringVar(&eventsResourceType, "resource-type", "", "Filter by resource type (mcpserver, workflow)")
	eventsCmd.PersistentFlags().StringVar(&eventsResourceName, "resource-name", "", "Filter by resource name")
	eventsCmd.PersistentFlags().StringVar(&eventsNamespace, "namespace", "", "Filter by namespace")
	eventsCmd.PersistentFlags().StringVar(&eventsEventType, "type", "", "Filter by event type (Normal, Warning)")
	eventsCmd.PersistentFlags().StringVar(&eventsSince, "since", "", "Show events after this time (e.g., 1h, 30m, 2024-01-15T10:00:00Z)")
	eventsCmd.PersistentFlags().StringVar(&eventsUntil, "until", "", "Show events before this time (e.g., 2024-01-15T18:00:00Z)")
	eventsCmd.PersistentFlags().IntVar(&eventsLimit, "limit", 50, "Limit number of events returned")
	eventsCmd.PersistentFlags().BoolVarP(&eventsFollow, "follow", "f", false, "Stream new events as they occur")

	// Add shell completion for resource types
	_ = eventsCmd.PersistentFlags().SetAnnotation("resource-type", cobra.BashCompCustom, []string{"__muster_events_resource_types"})
}

func runEvents(cmd *cobra.Command, args []string) error {
	// Validate resource type if provided
	if eventsResourceType != "" {
		validTypes := []string{api.ResourceTypeMCPServer, api.ResourceTypeWorkflow}
		if !contains(validTypes, strings.ToLower(eventsResourceType)) {
			return fmt.Errorf("invalid resource type '%s'. Valid types: %s", eventsResourceType, strings.Join(validTypes, ", "))
		}
		// Normalize the resource type for consistency
		eventsResourceType = strings.ToLower(eventsResourceType)
		// Convert to the expected CRD Kind format
		switch eventsResourceType {
		case api.ResourceTypeMCPServer:
			eventsResourceType = "MCPServer"
		case api.ResourceTypeWorkflow:
			eventsResourceType = "Workflow"
		}
	}

	// Validate and normalize event type if provided
	if eventsEventType != "" {
		switch strings.ToLower(eventsEventType) {
		case "normal":
			eventsEventType = "Normal"
		case "warning":
			eventsEventType = "Warning"
		default:
			return fmt.Errorf("invalid event type '%s'. Valid types: Normal, Warning", eventsEventType)
		}
	}

	// Parse time filters
	var sinceTime, untilTime *time.Time
	if eventsSince != "" {
		since, err := cli.ParseTimeFilter(eventsSince)
		if err != nil {
			return fmt.Errorf("invalid --since value '%s': %w", eventsSince, err)
		}
		sinceTime = &since
	}

	if eventsUntil != "" {
		until, err := cli.ParseTimeFilter(eventsUntil)
		if err != nil {
			return fmt.Errorf("invalid --until value '%s': %w", eventsUntil, err)
		}
		untilTime = &until
	}

	// Validate limit
	if eventsLimit < 0 {
		return fmt.Errorf("limit must be a positive number, got %d", eventsLimit)
	}

	opts, err := eventsFlags.ToExecutorOptions()
	if err != nil {
		return err
	}

	executor, err := cli.NewToolExecutor(opts)
	if err != nil {
		return err
	}
	defer func() { _ = executor.Close() }()

	ctx := cmd.Context()
	if err := executor.Connect(ctx); err != nil {
		return err
	}

	// Build tool arguments for the core_events tool
	toolArgs := make(map[string]interface{})

	if eventsResourceType != "" {
		toolArgs["resourceType"] = eventsResourceType
	}
	if eventsResourceName != "" {
		toolArgs["resourceName"] = eventsResourceName
	}
	if eventsNamespace != "" {
		toolArgs["namespace"] = eventsNamespace
	}
	if eventsEventType != "" {
		toolArgs["eventType"] = eventsEventType
	}
	if sinceTime != nil {
		toolArgs["since"] = sinceTime.Format(time.RFC3339)
	}
	if untilTime != nil {
		toolArgs["until"] = untilTime.Format(time.RFC3339)
	}
	if eventsLimit > 0 {
		toolArgs["limit"] = eventsLimit
	}
	// Handle follow mode with notifications
	if eventsFollow {
		toolArgs["follow"] = true
		return followEventsWithNotifications(ctx, executor, toolArgs)
	}

	return executor.Execute(ctx, "core_events", toolArgs)
}

// followEventsWithNotifications implements streaming via MCP notifications for the --follow flag
func followEventsWithNotifications(ctx context.Context, executor *cli.ToolExecutor, baseArgs map[string]interface{}) error {
	fmt.Printf("Streaming events (Press Ctrl+C to stop)...\n\n")

	// Get the agent client to access notification channel
	client := executor.GetClient()
	if client == nil {
		return fmt.Errorf("failed to get MCP client for streaming")
	}

	// Execute the core_events tool with follow=true - this will start the streaming on the server side
	if err := executor.Execute(ctx, "core_events", baseArgs); err != nil {
		return fmt.Errorf("failed to start event streaming: %w", err)
	}

	fmt.Printf("\n--- Following new events ---\n")

	// Listen for event notifications from the server
	for {
		select {
		case <-ctx.Done():
			fmt.Printf("\nStopped following events.\n")
			return nil
		case notification := <-client.NotificationChan:
			// Handle event notifications
			if notification.Method == "events/new_event" {
				// Parse the event from the notification params
				displayStreamedEvent(notification.Params)
			}
		}
	}
}

// displayStreamedEvent formats and displays a single streamed event
func displayStreamedEvent(params interface{}) {
	// For now, just print the notification as-is since we don't have the proper MCP notification mechanism working yet
	fmt.Printf("New event notification: %+v\n", params)
}

// contains checks if a string slice contains a specific string
func contains(slice []string, item string) bool {
	for _, s := range slice {
		if s == item {
			return true
		}
	}
	return false
}
