package output

import (
	"encoding/json"
	"fmt"
	"log"
	"strings"

	"github.com/tidbcloud/aws-shared-provider/tools/cloud-instances/types"
	"gopkg.in/yaml.v3"
)

// Options defines output formatting options
type Options struct {
	Format  string // table, json, yaml, all
	Style   string // pretty, compact
	Details bool
}

// Formatter handles output formatting
type Formatter struct {
	opts Options
}

// NewFormatter creates a new output formatter
func NewFormatter(opts Options) *Formatter {
	return &Formatter{opts: opts}
}

// FormatOutput formats and prints instances according to options
func (f *Formatter) FormatOutput(instances []types.UnifiedInstance, provider string) error {
	switch f.opts.Format {
	case "all":
		fmt.Println("=== Table Format ===")
		f.outputTable(instances, provider)
		fmt.Println("\n=== JSON Format ===")
		if err := f.outputJSON(instances); err != nil {
			return err
		}
		fmt.Println("\n=== YAML Format ===")
		if err := f.outputYAML(instances); err != nil {
			return err
		}
	case "json":
		return f.outputJSON(instances)
	case "yaml":
		return f.outputYAML(instances)
	default:
		f.outputTable(instances, provider)
	}
	return nil
}

// outputJSON formats instances as JSON
func (f *Formatter) outputJSON(instances []types.UnifiedInstance) error {
	var data interface{}
	if f.opts.Details {
		data = instances
	} else {
		// Extract only instance types
		instanceTypes := make([]string, len(instances))
		for i, inst := range instances {
			instanceTypes[i] = inst.InstanceType
		}
		data = instanceTypes
	}

	var jsonData []byte
	var err error

	if f.opts.Style == "pretty" {
		jsonData, err = json.MarshalIndent(data, "", "  ")
	} else {
		jsonData, err = json.Marshal(data)
	}

	if err != nil {
		return err
	}
	fmt.Println(string(jsonData))
	return nil
}

// outputYAML formats instances as YAML
func (f *Formatter) outputYAML(instances []types.UnifiedInstance) error {
	var data interface{}
	if f.opts.Details {
		data = instances
	} else {
		// Extract only instance types
		instanceTypes := make([]string, len(instances))
		for i, inst := range instances {
			instanceTypes[i] = inst.InstanceType
		}
		data = instanceTypes
	}

	yamlData, err := yaml.Marshal(data)
	if err != nil {
		return err
	}
	fmt.Println(string(yamlData))
	return nil
}

// outputTable formats instances as a table
func (f *Formatter) outputTable(instances []types.UnifiedInstance, provider string) {
	if len(instances) == 0 {
		fmt.Println("No instances found matching the criteria.")
		return
	}

	// Print provider info
	fmt.Printf("Provider: %s\n", provider)
	fmt.Println(strings.Repeat("-", 140))

	// Header
	if f.opts.Details {
		fmt.Printf("%-20s %-20s %-8s %-12s %-10s %-10s %-20s %-15s %-20s\n",
			"Instance Type", "Instance Family", "vCPU", "Memory", "Price", "Currency", "Location", "Network", "Storage")
	} else {
		fmt.Printf("%-20s %-8s %-12s %-10s %-10s %-20s\n",
			"Instance Type", "vCPU", "Memory", "Price", "Currency", "Location")
	}
	fmt.Println(strings.Repeat("-", 140))

	// Rows
	for _, inst := range instances {
		if f.opts.Details {
			fmt.Printf("%-20s %-20s %-8s %-12s %-10.4f %-10s %-20s %-15s %-20s\n",
				inst.InstanceType,
				inst.InstanceFamily,
				inst.VCPU,
				inst.Memory,
				inst.Price,
				inst.Currency,
				inst.Location,
				inst.NetworkPerformance,
				inst.Storage)
		} else {
			fmt.Printf("%-20s %-8s %-12s %-10.4f %-10s %-20s\n",
				inst.InstanceType,
				inst.VCPU,
				inst.Memory,
				inst.Price,
				inst.Currency,
				inst.Location)
		}
	}
}

// PrintError prints an error message
func (f *Formatter) PrintError(msg string) {
	log.Printf("ERROR: %s", msg)
}

// PrintInfo prints an info message
func (f *Formatter) PrintInfo(msg string) {
	log.Printf("INFO: %s", msg)
}

// PrintWarning prints a warning message
func (f *Formatter) PrintWarning(msg string) {
	log.Printf("WARNING: %s", msg)
}

// ListProviders prints available providers
func (f *Formatter) ListProviders(providers []string) {
	fmt.Println("Available Providers:")
	for _, p := range providers {
		fmt.Printf("  - %s\n", p)
	}
}

// ListRegions prints available regions for a provider
func (f *Formatter) ListRegions(provider string, regions map[string]string) {
	fmt.Printf("Available Regions for %s:\n", provider)
	for id, name := range regions {
		fmt.Printf("  %-20s %s\n", id, name)
	}
}
