// SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
// SPDX-License-Identifier: Apache-2.0

package app

import (
	"encoding/json"
	"fmt"
	"log/slog"
	"os"
	"text/tabwriter"
	"time"

	"github.com/spf13/cobra"

	"github.com/stacklok/toolhive/pkg/core"
	"github.com/stacklok/toolhive/pkg/workloads"
)

var statusCmd = &cobra.Command{
	Use:               "status [workload-name]",
	Args:              cobra.ExactArgs(1),
	Short:             "Show detailed status of an MCP server",
	Long:              `Display detailed status information for a specific MCP server managed by ToolHive.`,
	ValidArgsFunction: completeMCPServerNames,
	RunE:              statusCmdFunc,
}

var statusFormat string

func init() {
	statusCmd.Flags().StringVar(&statusFormat, "format", FormatText, "Output format (json or text)")
}

func statusCmdFunc(cmd *cobra.Command, args []string) error {
	ctx := cmd.Context()

	workloadName := args[0]

	// Instantiate the status manager.
	manager, err := workloads.NewManager(ctx)
	if err != nil {
		return fmt.Errorf("failed to create status manager: %v", err)
	}

	workload, err := manager.GetWorkload(ctx, workloadName)
	if err != nil {
		return fmt.Errorf("failed to get workload status: %v", err)
	}

	// Output based on format
	switch statusFormat {
	case FormatJSON:
		return printStatusJSONOutput(workload)
	default:
		printStatusTextOutput(workload)
		return nil
	}
}

func printStatusJSONOutput(workload core.Workload) error {
	uptime := ""
	if !workload.StartedAt.IsZero() {
		uptime = formatUptime(time.Since(workload.StartedAt))
	}

	output := struct {
		Name      string `json:"name"`
		Status    string `json:"status"`
		Health    string `json:"health,omitempty"`
		Package   string `json:"package"`
		URL       string `json:"url"`
		Port      int    `json:"port"`
		Transport string `json:"transport"`
		ProxyMode string `json:"proxy_mode,omitempty"`
		Group     string `json:"group,omitempty"`
		Uptime    string `json:"uptime,omitempty"`
	}{
		Name:      workload.Name,
		Status:    string(workload.Status),
		Health:    workload.StatusContext,
		Package:   workload.Package,
		URL:       workload.URL,
		Port:      workload.Port,
		Transport: string(workload.TransportType),
		ProxyMode: workload.ProxyMode,
		Group:     workload.Group,
		Uptime:    uptime,
	}

	jsonData, err := json.MarshalIndent(output, "", "  ")
	if err != nil {
		return fmt.Errorf("failed to marshal JSON: %v", err)
	}

	fmt.Println(string(jsonData))
	return nil
}

func printStatusTextOutput(workload core.Workload) {
	w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
	status := workloadStatusIndicator(workload.Status)

	// Print workload information in key-value format
	_, _ = fmt.Fprintf(w, "Name:\t%s\n", workload.Name)
	_, _ = fmt.Fprintf(w, "Status:\t%s\n", status)
	if workload.StatusContext != "" {
		_, _ = fmt.Fprintf(w, "Health:\t%s\n", workload.StatusContext)
	}
	_, _ = fmt.Fprintf(w, "Package:\t%s\n", workload.Package)
	_, _ = fmt.Fprintf(w, "URL:\t%s\n", workload.URL)
	_, _ = fmt.Fprintf(w, "Port:\t%d\n", workload.Port)
	_, _ = fmt.Fprintf(w, "Transport:\t%s\n", workload.TransportType)
	if workload.ProxyMode != "" {
		_, _ = fmt.Fprintf(w, "Proxy Mode:\t%s\n", workload.ProxyMode)
	}
	if workload.Group != "" {
		_, _ = fmt.Fprintf(w, "Group:\t%s\n", workload.Group)
	}
	_, _ = fmt.Fprintf(w, "Created:\t%s\n", workload.CreatedAt.Format("2006-01-02 15:04:05"))
	if workload.Remote {
		_, _ = fmt.Fprintf(w, "Remote:\t%v\n", workload.Remote)
	}
	if !workload.StartedAt.IsZero() {
		_, _ = fmt.Fprintf(w, "Uptime:\t%s\n", formatUptime(time.Since(workload.StartedAt)))
	}

	// Flush the tabwriter
	if err := w.Flush(); err != nil {
		slog.Error(fmt.Sprintf("Failed to flush tabwriter: %v", err))
	}
}

func formatUptime(d time.Duration) string {
	days := int(d.Hours()) / 24
	hours := int(d.Hours()) % 24
	minutes := int(d.Minutes()) % 60

	if days > 0 {
		return fmt.Sprintf("%dd %dh %dm", days, hours, minutes)
	}
	if hours > 0 {
		return fmt.Sprintf("%dh %dm", hours, minutes)
	}
	return fmt.Sprintf("%dm", minutes)
}
