package cmd

import (
	"encoding/json"
	"fmt"
	"os"
	"strings"
	"text/tabwriter"

	"github.com/spf13/cobra"
	"github.com/tidbcloud/investibook/cli/internal/api"
)

var debugContextJSON bool

var debugCmd = &cobra.Command{
	Use:   "debug",
	Short: "Debug workspace internals",
}

var debugContextCmd = &cobra.Command{
	Use:   "context [workspace-id]",
	Short: "Show workspace context usage breakdown",
	Args:  cobra.MaximumNArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		client, cfg := mustClient()
		wsID := ""
		if len(args) > 0 {
			wsID = args[0]
		} else {
			wsID = mustWorkspace(cfg)
		}
		report, err := client.GetContextDebug(wsID)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: %v\n", err)
			os.Exit(1)
		}
		if debugContextJSON {
			data, err := json.MarshalIndent(report, "", "  ")
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error: %v\n", err)
				os.Exit(1)
			}
			fmt.Println(string(data))
			return
		}
		printContextDebugReport(report)
	},
}

func init() {
	debugContextCmd.Flags().BoolVar(&debugContextJSON, "json", false, "print raw JSON")
	debugCmd.AddCommand(debugContextCmd)
	rootCmd.AddCommand(debugCmd)
}

func printContextDebugReport(report *api.ContextDebugReport) {
	used := report.ActualContext.ContextUsed
	size := report.ActualContext.ContextSize
	percent := "n/a"
	if report.ActualContext.Percent != nil {
		percent = fmt.Sprintf("%.2f%%", *report.ActualContext.Percent)
	}
	fmt.Printf("Workspace: %s\n", report.WorkspaceID)
	fmt.Printf("Actual context: %s / %s tokens (%s)\n", formatInt(used), formatInt(size), percent)
	if report.ActualContext.SessionID != "" {
		fmt.Printf("Session: %s at %s\n", report.ActualContext.SessionID, report.ActualContext.CreatedAt)
	}
	fmt.Printf("Estimator: %s\n\n", report.EstimateModel.TokenEstimator)

	w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
	fmt.Fprintln(w, "SOURCE\tSCOPE\tITEMS\tEST TOKENS\tSCALED TOKENS\tUSED %\tWINDOW %\tBYTES")
	for _, row := range report.Categories {
		fmt.Fprintf(
			w,
			"%s\t%s\t%d\t%s\t%s\t%s\t%s\t%s\n",
			row.Label,
			row.Scope,
			row.ItemCount,
			formatInt(row.EstimatedTokens),
			formatOptionalInt(row.ScaledContextTokens),
			formatOptionalPercent(row.PercentOfUsedContext),
			formatOptionalPercent(row.PercentOfContextWindow),
			formatInt(row.Bytes),
		)
	}
	w.Flush()

	if len(report.Notes) > 0 {
		fmt.Println()
		fmt.Println("Notes:")
		for _, note := range report.Notes {
			fmt.Printf("- %s\n", note)
		}
	}
}

func formatOptionalInt(v *int) string {
	if v == nil {
		return "-"
	}
	return formatInt(*v)
}

func formatOptionalPercent(v *float64) string {
	if v == nil {
		return "-"
	}
	return fmt.Sprintf("%.2f%%", *v)
}

func formatInt(v int) string {
	s := fmt.Sprintf("%d", v)
	n := len(s)
	if n <= 3 {
		return s
	}
	var b strings.Builder
	first := n % 3
	if first == 0 {
		first = 3
	}
	b.WriteString(s[:first])
	for i := first; i < n; i += 3 {
		b.WriteString(",")
		b.WriteString(s[i : i+3])
	}
	return b.String()
}
