package main

import (
	"encoding/json"
	"fmt"
	"os"
	"sync"
	"time"
)

// ChatLogger appends one JSON line per tool invocation to a file. Thread-safe.
// Format per line: {"ts":"...","tool":"...","input":{...},"ok":bool,"error":"...","result_summary":"..."}
type ChatLogger struct {
	path string
	mu   sync.Mutex
}

func newChatLogger(path string) *ChatLogger {
	return &ChatLogger{path: path}
}

type ChatLogEntry struct {
	TS            string          `json:"ts"`
	Tool          string          `json:"tool"`
	Input         json.RawMessage `json:"input"`
	OK            bool            `json:"ok"`
	Error         string          `json:"error,omitempty"`
	ResultSummary string          `json:"result_summary,omitempty"`
}

func (l *ChatLogger) Log(tool string, input json.RawMessage, res ToolResult) {
	if l == nil || l.path == "" {
		return
	}
	entry := ChatLogEntry{
		TS:    time.Now().UTC().Format(time.RFC3339Nano),
		Tool:  tool,
		Input: input,
		OK:    res.OK,
		Error: res.Error,
	}
	if res.OK && res.Result != nil {
		entry.ResultSummary = summarizeResult(res.Result)
	}
	line, err := json.Marshal(entry)
	if err != nil {
		return
	}
	l.mu.Lock()
	defer l.mu.Unlock()
	f, err := os.OpenFile(l.path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
	if err != nil {
		return
	}
	defer f.Close()
	f.Write(line)
	f.Write([]byte("\n"))
}

// summarizeResult produces a short description of a tool result for the log.
// Keeps the log line compact: full payloads can be reconstructed from operations.db.
func summarizeResult(v any) string {
	switch r := v.(type) {
	case *Column:
		return fmt.Sprintf("column %s name=%q", r.ID, r.Name)
	case *Card:
		return fmt.Sprintf("card %s title=%q col=%s", r.ID, r.Title, r.ColumnID)
	case []Card:
		return fmt.Sprintf("%d cards", len(r))
	case []HistoryEntry:
		return fmt.Sprintf("%d history entries", len(r))
	case map[string]any:
		// list_board shape
		cols, _ := r["columns"].([]Column)
		cards, _ := r["cards"].([]Card)
		return fmt.Sprintf("board: %d cols, %d cards", len(cols), len(cards))
	}
	b, err := json.Marshal(v)
	if err != nil || len(b) == 0 {
		return ""
	}
	if len(b) > 200 {
		return string(b[:200]) + "..."
	}
	return string(b)
}
