package main

import (
	"context"
	"fmt"
	"os"
	"strings"
	"text/tabwriter"
	"time"

	"github.com/spf13/cobra"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/client/config"

	v1alpha1 "github.com/pfeifferj/container-mom-go/pkg/apis/containermom/v1alpha1"
)

var showTemplateCmd = &cobra.Command{
	Use:   "show [template-name]",
	Short: "Show template details",
	Long:  `Display detailed information about a specific template`,
	Args:  cobra.ExactArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		// Get template name from args
		templateName := args[0]

		// Get namespace
		namespace, _ := cmd.Flags().GetString("namespace")
		if namespace == "" {
			namespace = "container-mom-system"
		}

		// Show template details
		err := showTemplate(templateName, namespace)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error showing template: %v\n", err)
			os.Exit(1)
		}
	},
}

func init() {
	templateCmd.AddCommand(showTemplateCmd)

	// Add flags
	showTemplateCmd.Flags().StringP("namespace", "n", "container-mom-system", "Namespace to search for templates")
}

func showTemplate(templateName, namespace string) error {
	// Setup client
	cfg, err := config.GetConfig()
	if err != nil {
		return fmt.Errorf("failed to get kubeconfig: %w", err)
	}

	c, err := client.New(cfg, client.Options{})
	if err != nil {
		return fmt.Errorf("failed to create client: %w", err)
	}

	// Get the template
	template := &v1alpha1.Template{}
	if err := c.Get(context.Background(), client.ObjectKey{
		Name:      templateName,
		Namespace: namespace,
	}, template); err != nil {
		return fmt.Errorf("failed to get template: %w", err)
	}

	// Format and print template details
	if _, err := fmt.Fprintf(os.Stdout, "Name: %s\n", template.Name); err != nil {
		fmt.Fprintf(os.Stderr, "Error writing template name: %v\n", err)
		return fmt.Errorf("failed to write template details: %w", err)
	}
	if _, err := fmt.Fprintf(os.Stdout, "Namespace: %s\n", template.Namespace); err != nil {
		fmt.Fprintf(os.Stderr, "Error writing template namespace: %v\n", err)
		return fmt.Errorf("failed to write template details: %w", err)
	}
	if _, err := fmt.Fprintf(os.Stdout, "Created: %s\n", template.CreationTimestamp.Format(time.RFC3339)); err != nil {
		fmt.Fprintf(os.Stderr, "Error writing template creation timestamp: %v\n", err)
		return fmt.Errorf("failed to write template details: %w", err)
	}
	if _, err := fmt.Fprintf(os.Stdout, "Last Updated: %s\n", template.Status.LastUpdated.Format(time.RFC3339)); err != nil {
		fmt.Fprintf(os.Stderr, "Error writing template last updated timestamp: %v\n", err)
		return fmt.Errorf("failed to write template details: %w", err)
	}
	if _, err := fmt.Fprintf(os.Stdout, "Usage Count: %d\n", template.Status.UsageCount); err != nil {
		fmt.Fprintf(os.Stderr, "Error writing template usage count: %v\n", err)
		return fmt.Errorf("failed to write template details: %w", err)
	}

	if template.Spec.Description != "" {
		if _, err := fmt.Fprintf(os.Stdout, "\nDescription: %s\n", template.Spec.Description); err != nil {
			fmt.Fprintf(os.Stderr, "Error writing template description: %v\n", err)
			return fmt.Errorf("failed to write template details: %w", err)
		}
	}

	// Print parameters if any
	if len(template.Spec.Parameters) > 0 {
		if _, err := fmt.Fprintf(os.Stdout, "\nParameters:\n"); err != nil {
			fmt.Fprintf(os.Stderr, "Error writing parameters header: %v\n", err)
			return fmt.Errorf("failed to write parameters header: %w", err)
		}

		w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
		// Print header
		if _, err := fmt.Fprintf(w, "  NAME\tDESCRIPTION\tTYPE\tDEFAULT\tREQUIRED\n"); err != nil {
			fmt.Fprintf(os.Stderr, "Error writing parameter header: %v\n", err)
			return fmt.Errorf("failed to write parameter table header: %w", err)
		}

		// Print each parameter
		for _, param := range template.Spec.Parameters {
			paramType := "string"
			if param.Type != "" {
				paramType = param.Type
			}

			defaultValue := param.DefaultValue
			if defaultValue == "" {
				defaultValue = "-"
			}

			required := "no"
			if param.Required {
				required = "yes"
			}

			if _, err := fmt.Fprintf(w, "  %s\t%s\t%s\t%s\t%s\n",
				param.Name,
				param.Description,
				paramType,
				defaultValue,
				required); err != nil {
				fmt.Fprintf(os.Stderr, "Error writing parameter data: %v\n", err)
				return fmt.Errorf("failed to write parameter data: %w", err)
			}
		}

		if err := w.Flush(); err != nil {
			fmt.Fprintf(os.Stderr, "Error flushing parameter output: %v\n", err)
			return fmt.Errorf("failed to flush parameter output: %w", err)
		}
	}

	// Print components if any
	if len(template.Spec.Components) > 0 {
		if _, err := fmt.Fprintf(os.Stdout, "\nComponents:\n"); err != nil {
			fmt.Fprintf(os.Stderr, "Error writing components header: %v\n", err)
			return fmt.Errorf("failed to write components header: %w", err)
		}

		for _, comp := range template.Spec.Components {
			if _, err := fmt.Fprintf(os.Stdout, "- %s (%s)\n", comp.Name, comp.Type); err != nil {
				fmt.Fprintf(os.Stderr, "Error writing component name: %v\n", err)
				return fmt.Errorf("failed to write component details: %w", err)
			}

			if comp.Properties.Image != "" {
				if _, err := fmt.Fprintf(os.Stdout, "  Image: %s\n", comp.Properties.Image); err != nil {
					fmt.Fprintf(os.Stderr, "Error writing component image: %v\n", err)
					return fmt.Errorf("failed to write component details: %w", err)
				}
			}

			if comp.Properties.GitURL != "" {
				if _, err := fmt.Fprintf(os.Stdout, "  Git URL: %s\n", comp.Properties.GitURL); err != nil {
					fmt.Fprintf(os.Stderr, "Error writing component git URL: %v\n", err)
					return fmt.Errorf("failed to write component details: %w", err)
				}

				if comp.Properties.GitBranch != "" {
					if _, err := fmt.Fprintf(os.Stdout, "  Git Branch: %s\n", comp.Properties.GitBranch); err != nil {
						fmt.Fprintf(os.Stderr, "Error writing component git branch: %v\n", err)
						return fmt.Errorf("failed to write component details: %w", err)
					}
				}
			}

			if len(comp.Properties.Env) > 0 {
				if _, err := fmt.Fprintf(os.Stdout, "  Environment Variables:\n"); err != nil {
					fmt.Fprintf(os.Stderr, "Error writing environment variables header: %v\n", err)
					return fmt.Errorf("failed to write component environment variables header: %w", err)
				}
				for _, env := range comp.Properties.Env {
					if _, err := fmt.Fprintf(os.Stdout, "    %s: %s\n", env.Name, env.Value); err != nil {
						fmt.Fprintf(os.Stderr, "Error writing component environment variable: %v\n", err)
						return fmt.Errorf("failed to write component environment variables: %w", err)
					}
				}
			}

			if len(comp.Properties.Ports) > 0 {
				if _, err := fmt.Fprintf(os.Stdout, "  Ports:\n"); err != nil {
					fmt.Fprintf(os.Stderr, "Error writing ports header: %v\n", err)
					return fmt.Errorf("failed to write component ports header: %w", err)
				}
				for _, port := range comp.Properties.Ports {
					protocol := port.Protocol
					if protocol == "" {
						protocol = "TCP"
					}
					if _, err := fmt.Fprintf(os.Stdout, "    %s: %d->%d/%s\n", port.Name, port.Port, port.TargetPort, protocol); err != nil {
						fmt.Fprintf(os.Stderr, "Error writing component port: %v\n", err)
						return fmt.Errorf("failed to write component port details: %w", err)
					}
				}
			}

			if comp.Properties.Resources.CPU != "" || comp.Properties.Resources.Memory != "" {
				if _, err := fmt.Fprintf(os.Stdout, "  Resources:\n"); err != nil {
					fmt.Fprintf(os.Stderr, "Error writing resources header: %v\n", err)
					return fmt.Errorf("failed to write component resources header: %w", err)
				}
				if comp.Properties.Resources.CPU != "" {
					if _, err := fmt.Fprintf(os.Stdout, "    CPU: %s\n", comp.Properties.Resources.CPU); err != nil {
						fmt.Fprintf(os.Stderr, "Error writing component CPU resource: %v\n", err)
						return fmt.Errorf("failed to write component CPU resource: %w", err)
					}
				}
				if comp.Properties.Resources.Memory != "" {
					if _, err := fmt.Fprintf(os.Stdout, "    Memory: %s\n", comp.Properties.Resources.Memory); err != nil {
						fmt.Fprintf(os.Stderr, "Error writing component memory resource: %v\n", err)
						return fmt.Errorf("failed to write component memory resource: %w", err)
					}
				}
			}

			if len(comp.Properties.Dependencies) > 0 {
				if _, err := fmt.Fprintf(os.Stdout, "  Dependencies: %s\n", strings.Join(comp.Properties.Dependencies, ", ")); err != nil {
					fmt.Fprintf(os.Stderr, "Error writing component dependencies: %v\n", err)
					return fmt.Errorf("failed to write component dependencies: %w", err)
				}
			}
		}
	} else {
		if _, err := fmt.Fprintf(os.Stdout, "Components: None\n"); err != nil {
			fmt.Fprintf(os.Stderr, "Error writing no components message: %v\n", err)
			return fmt.Errorf("failed to write components information: %w", err)
		}
	}

	// Print networking configuration
	if template.Spec.NetworkConfig.Domain.DomainName != "" {
		if _, err := fmt.Fprintf(os.Stdout, "\nNetwork Configuration:\n"); err != nil {
			fmt.Fprintf(os.Stderr, "Error writing network configuration header: %v\n", err)
			return fmt.Errorf("failed to write network configuration header: %w", err)
		}
		if _, err := fmt.Fprintf(os.Stdout, "  Domain: %s\n", template.Spec.NetworkConfig.Domain.DomainName); err != nil {
			fmt.Fprintf(os.Stderr, "Error writing domain name: %v\n", err)
			return fmt.Errorf("failed to write domain information: %w", err)
		}
		if template.Spec.NetworkConfig.Domain.UseWildcard {
			if _, err := fmt.Fprintf(os.Stdout, "  Uses Wildcard: Yes\n"); err != nil {
				fmt.Fprintf(os.Stderr, "Error writing wildcard flag: %v\n", err)
				return fmt.Errorf("failed to write wildcard information: %w", err)
			}
		}

		if len(template.Spec.NetworkConfig.IngressRules) > 0 {
			if _, err := fmt.Fprintf(os.Stdout, "  Ingress Rules:\n"); err != nil {
				fmt.Fprintf(os.Stderr, "Error writing ingress rules header: %v\n", err)
				return fmt.Errorf("failed to write ingress rules header: %w", err)
			}
			w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
			for _, rule := range template.Spec.NetworkConfig.IngressRules {
				_, err := fmt.Fprintf(w, "    %s%s -> %s:%d\n",
					rule.Host,
					rule.Path,
					rule.ServiceName,
					rule.ServicePort)
				if err != nil {
					fmt.Fprintf(os.Stderr, "Error writing ingress rule: %v\n", err)
					return fmt.Errorf("failed to write ingress rule: %w", err)
				}
			}
			if err := w.Flush(); err != nil {
				fmt.Fprintf(os.Stderr, "Error flushing ingress rules output: %v\n", err)
				return fmt.Errorf("failed to flush ingress rules output: %w", err)
			}
		}
	}

	// Usage example
	if _, err := fmt.Fprintf(os.Stdout, "\nTo instantiate this template:\n"); err != nil {
		fmt.Fprintf(os.Stderr, "Error writing instantiation header: %v\n", err)
		return fmt.Errorf("failed to write instantiation instructions: %w", err)
	}
	cmd := fmt.Sprintf("mom-client template instantiate %s", template.Name)

	// Add required parameters
	hasRequired := false
	for _, param := range template.Spec.Parameters {
		if param.Required && param.DefaultValue == "" {
			if !hasRequired {
				if _, err := fmt.Fprintf(os.Stdout, "\nRequired parameters:\n"); err != nil {
					fmt.Fprintf(os.Stderr, "Error writing required parameters header: %v\n", err)
					return fmt.Errorf("failed to write required parameters header: %w", err)
				}
				hasRequired = true
			}
			cmd += fmt.Sprintf(" --param %s=<value>", param.Name)
			if _, err := fmt.Fprintf(os.Stdout, "  %s: %s\n", param.Name, param.Description); err != nil {
				fmt.Fprintf(os.Stderr, "Error writing parameter description: %v\n", err)
				return fmt.Errorf("failed to write parameter description: %w", err)
			}
		}
	}

	if _, err := fmt.Fprintf(os.Stdout, "\nCommand example:\n"); err != nil {
		fmt.Fprintf(os.Stderr, "Error writing command example header: %v\n", err)
		return fmt.Errorf("failed to write command example header: %w", err)
	}
	if _, err := fmt.Fprintf(os.Stdout, "  %s\n", cmd); err != nil {
		fmt.Fprintf(os.Stderr, "Error writing command example: %v\n", err)
		return fmt.Errorf("failed to write command example: %w", err)
	}

	return nil
}
