// This file contains functions for formatting and printing chat logs to the terminal.
// These functions operate exclusively on the in-memory protobuf data structures.
// They do NOT access the filesystem; all content (from content files, snippets, etc.)
// is expected to have been loaded into the 'Content' fields of the protobuf messages
// before these functions are called.

package main

import (
	"fmt"
	"path/filepath"
	"strings"

	"go.wit.com/lib/protobuf/chatpb"
)

const termWidth = 100 // The target width for the formatted output boxes.

// prettyFormatChat is the main entry point to print a detailed view of a Chat topic.
func prettyFormatChat(chat *chatpb.Chat) {
	fmt.Printf("\n========================================================\n")
	fmt.Printf("== Chat Topic: %s (UUID: %s)\n", chat.GetChatName(), chat.GetUuid())
	fmt.Printf("========================================================\n\n")

	for _, entry := range chat.GetEntries() {
		author := entry.GetFrom().String()
		var formattedTime string
		if ctime := entry.GetCtime(); ctime != nil {
			t := ctime.AsTime()
			formattedTime = t.Format("2006-01-02 15:04:05")
		} else {
			formattedTime = "No Timestamp"
		}

		// Use the in-memory Content field directly.
		content := entry.GetContent()

		if content != "" {
			printContent(author, formattedTime, content)
		}

		if table := entry.GetTable(); table != nil {
			printTable(table)
		}
		for _, toolCall := range entry.GetToolCalls() {
			printToolCallBox(toolCall)
		}
		if snippets := entry.GetSnippets(); snippets != nil {
			for _, snippet := range snippets {
				printCodeSnippet(snippet)
			}
		}
		fmt.Println()
	}
}

// printContent handles the wrapping for the main conversational text.
func printContent(author, timestamp, content string) {
	// Right-align USER messages, left-align REGEX messages.
	if author == "USER" {
		printRightAligned(author, timestamp, content)
	} else {
		printLeftAligned(author, timestamp, content)
	}
}

func printLeftAligned(author, timestamp, content string) {
	prefix := fmt.Sprintf("✦ %s (%s):", author, timestamp)
	fmt.Println(prefix)

	indent := "\t"
	contentWidth := termWidth - 8 // 8 spaces for a standard tab

	paragraphs := strings.Split(content, "\n")

	for _, paragraph := range paragraphs {
		words := strings.Fields(paragraph)
		if len(words) == 0 {
			fmt.Println() // Preserve paragraph breaks
			continue
		}

		currentLine := indent + words[0]
		for _, word := range words[1:] {
			if len(currentLine)+1+len(word) <= contentWidth {
				currentLine += " " + word
			} else {
				fmt.Println(currentLine)
				currentLine = indent + word
			}
		}
		fmt.Println(currentLine)
	}
}

func printRightAligned(author, timestamp, content string) {
	prefix := fmt.Sprintf("(%s) %s ✦", timestamp, author)

	// Print the prefix first, right-aligned.
	fmt.Printf("%*s\n", termWidth, prefix)

	// The available width for the text.
	contentWidth := termWidth - 8 // Leave a tab's worth of margin on the left

	paragraphs := strings.Split(content, "\n")

	for _, paragraph := range paragraphs {
		words := strings.Fields(paragraph)
		if len(words) == 0 {
			fmt.Println() // Preserve paragraph breaks
			continue
		}

		currentLine := words[0]
		for _, word := range words[1:] {
			if len(currentLine)+1+len(word) <= contentWidth {
				currentLine += " " + word
			} else {
				// Print the completed line, right-aligned.
				fmt.Printf("%*s\n", termWidth, currentLine)
				currentLine = word
			}
		}
		// Print the last remaining line of the paragraph, right-aligned.
		fmt.Printf("%*s\n", termWidth, currentLine)
	}
}

func printTable(table *chatpb.Table) {
	if table == nil || len(table.GetRows()) == 0 {
		return
	}
	fmt.Println("┌─[ Table Data ]──────────────────────────────────────────")
	for _, row := range table.GetRows() {
		fmt.Printf("│ %s\n", strings.Join(row.GetFields(), " │ "))
	}
	fmt.Printf("└─────────────────────────────────────────────────────────\n\n")
}

func printCodeSnippet(snippet *chatpb.CodeSnippet) {
	// Use the in-memory Content field directly.
	code := snippet.GetContent()
	language := filepath.Base(snippet.GetFilename()) // Still useful for display

	fmt.Println() // Add extra line feed for spacing

	// --- Top Border ---
	topBorder := fmt.Sprintf("┌─[ Code Snippet: %s ]", language)
	fmt.Printf("%s%s┐\n", topBorder, strings.Repeat("─", termWidth-len(topBorder)-1))

	// --- Content Lines ---
	for _, line := range strings.Split(strings.TrimSpace(code), "\n") {
		// Calculate padding: total width - borders/padding - text length
		padding := termWidth - 4 - len(line)
		if padding < 0 {
			padding = 0 // Should not happen with wrapping, but as a safeguard
		}
		fmt.Printf("│ %s%s │\n", line, strings.Repeat(" ", padding))
	}

	// --- Bottom Border ---
	fmt.Printf("└%s┘\n\n", strings.Repeat("─", termWidth-2))
}

func printToolCallBox(tc *chatpb.ToolCall) {
	boxWidth := termWidth - 2
	fmt.Printf(" ╭%s╮\n", strings.Repeat("─", boxWidth))
	header := fmt.Sprintf(" ✔  %s %s (%s)", tc.GetName(), tc.GetInput(), tc.GetDescription())
	printWrappedLine(header, boxWidth)
	printEmptyLine(boxWidth)
	if stdout := tc.GetOutputStdout(); stdout != "" {
		for _, line := range strings.Split(stdout, "\n") {
			printWrappedLine("    "+line, boxWidth)
		}
	}
	if stderr := tc.GetOutputStderr(); stderr != "" {
		for _, line := range strings.Split(stderr, "\n") {
			printWrappedLine("    "+line, boxWidth)
		}
	}
	printEmptyLine(boxWidth)
	fmt.Printf(" ╰%s╯\n", strings.Repeat("─", boxWidth))
}

func printWrappedLine(text string, width int) {
	if len(text) == 0 {
		printEmptyLine(width)
		return
	}
	for len(text) > width {
		fmt.Printf(" │ %-*s │\n", width, text[:width])
		text = text[width:]
	}
	fmt.Printf(" │ %-*s │\n", width, text)
}

func printEmptyLine(width int) {
	fmt.Printf(" │ %*s │\n", width, "")
}
