package cmd

import (
	"fmt"
	"io"
	"sort"
	"strings"
	"text/tabwriter"
)

func writeDiagnoseBundleTableOutput(stdout io.Writer, bundle DiagnoseBundle) error {
	scope := bundle.Scope

	if _, err := fmt.Fprintf(stdout, "diagnose.v2 bundle for %q\n", firstNonEmpty(scope.Seed, "-")); err != nil {
		return err
	}
	if _, err := fmt.Fprintf(
		stdout,
		"searched cluster=%s namespace=%s\n",
		firstNonEmpty(strings.TrimSpace(scope.ClusterID), "-"),
		firstNonEmpty(strings.TrimSpace(scope.Namespace), "-"),
	); err != nil {
		return err
	}
	if _, err := fmt.Fprintf(stdout, "Profile timezone: %s\n", firstNonEmpty(strings.TrimSpace(scope.Timezone), "-")); err != nil {
		return err
	}
	if _, err := fmt.Fprintf(
		stdout,
		"Query window local: %s -> %s\n",
		firstNonEmpty(strings.TrimSpace(scope.StartLocal), strings.TrimSpace(scope.StartUTC), "-"),
		firstNonEmpty(strings.TrimSpace(scope.EndLocal), strings.TrimSpace(scope.EndUTC), "-"),
	); err != nil {
		return err
	}
	if _, err := fmt.Fprintf(
		stdout,
		"Query window UTC:   %s -> %s\n",
		firstNonEmpty(strings.TrimSpace(scope.StartUTC), "-"),
		firstNonEmpty(strings.TrimSpace(scope.EndUTC), "-"),
	); err != nil {
		return err
	}
	if _, err := fmt.Fprintf(stdout, "seed matches=%d related logs=%d\n", len(bundle.SeedMatches), len(bundle.RelatedLogs)); err != nil {
		return err
	}
	if _, err := fmt.Fprintf(stdout, "warnings=%d types=%s\n", len(bundle.Warnings), diagnoseWarningTypesSummary(bundle.Warnings)); err != nil {
		return err
	}
	if _, err := fmt.Fprintf(stdout, "groups=%d\n", len(bundle.Groups)); err != nil {
		return err
	}

	if len(bundle.Groups) > 0 {
		writer := tabwriter.NewWriter(stdout, 0, 0, 2, ' ', 0)
		for _, group := range bundle.Groups {
			if _, err := fmt.Fprintf(
				writer,
				"%s\tkeyspace=%s\tcluster=%s\tcomponents=%s\tseed=%d\trelated=%d\tevents=%d\tfirst=%s\tlast=%s\n",
				firstNonEmpty(strings.TrimSpace(group.Kind), "-"),
				firstNonEmpty(strings.TrimSpace(group.Keyspace), "-"),
				firstNonEmpty(strings.TrimSpace(group.ClusterID), "-"),
				diagnoseBundleGroupComponentsSummary(group.Components),
				len(group.SeedMatchIDs),
				len(group.RelatedLogIDs),
				len(group.EventIDs),
				firstNonEmpty(strings.TrimSpace(group.FirstSeenUTC), "-"),
				firstNonEmpty(strings.TrimSpace(group.LastSeenUTC), "-"),
			); err != nil {
				return err
			}
		}
		if err := writer.Flush(); err != nil {
			return err
		}
	}

	_, err := fmt.Fprintln(stdout, "rerun with -o json to inspect the full diagnose.v2 evidence bundle")
	return err
}

func diagnoseWarningTypesSummary(warnings []DiagnoseWarning) string {
	if len(warnings) == 0 {
		return "-"
	}

	codes := make(map[string]struct{}, len(warnings))
	for _, warning := range warnings {
		if code := strings.TrimSpace(warning.Code); code != "" {
			codes[code] = struct{}{}
		}
	}
	if len(codes) == 0 {
		return "-"
	}

	values := make([]string, 0, len(codes))
	for code := range codes {
		values = append(values, code)
	}
	sort.Strings(values)
	return strings.Join(values, ",")
}

func diagnoseBundleGroupComponentsSummary(components []string) string {
	if len(components) == 0 {
		return "-"
	}

	unique := make(map[string]struct{}, len(components))
	for _, component := range components {
		if value := strings.TrimSpace(component); value != "" {
			unique[value] = struct{}{}
		}
	}
	if len(unique) == 0 {
		return "-"
	}

	values := make([]string, 0, len(unique))
	for value := range unique {
		values = append(values, value)
	}
	sort.Strings(values)
	return strings.Join(values, "/")
}
