package devagents

import (
	"context"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"github.com/enmanuel/agents/internal/config"
	"github.com/enmanuel/agents/pkg/decision"
	"github.com/enmanuel/agents/tools"

	"log/slog"
)

// newMetricsTestAgent creates a minimal Agent for testing the !metrics command.
// Does NOT connect to Matrix or LLM.
func newMetricsTestAgent(logDir string) *Agent {
	cfg := &config.AgentConfig{
		Agent: config.AgentMeta{
			ID:   "test-bot",
			Name: "Test Bot",
		},
	}
	return &Agent{
		cfg:        cfg,
		logDir:     logDir,
		toolReg:    tools.NewRegistry(slog.Default()),
		logger:     slog.Default(),
		startTime:  time.Now(),
		commands:   make(map[string]CommandHandler),
		cmdAliases: make(map[string]string),
	}
}

func TestCmdMetrics_NoLogDir(t *testing.T) {
	a := newMetricsTestAgent("")
	result := a.cmdMetrics(context.Background(), decision.MessageContext{})
	if !strings.Contains(result, "no configurado") {
		t.Errorf("expected 'no configurado' message, got: %s", result)
	}
}

func TestCmdMetrics_NoLogsToday(t *testing.T) {
	dir := t.TempDir()
	// Create the agent subdirectory but with no log files
	agentDir := filepath.Join(dir, "test-bot")
	os.MkdirAll(agentDir, 0o755)

	a := newMetricsTestAgent(dir)
	result := a.cmdMetrics(context.Background(), decision.MessageContext{})
	if !strings.Contains(result, "No hay logs") {
		t.Errorf("expected 'No hay logs' message, got: %s", result)
	}
}

func TestCmdMetrics_AggregatesCorrectly(t *testing.T) {
	dir := t.TempDir()
	agentDir := filepath.Join(dir, "test-bot")
	os.MkdirAll(agentDir, 0o755)

	// Create a JSONL log file for today
	today := time.Now().UTC().Format("2006-01-02")
	logFile := filepath.Join(agentDir, today+".jsonl")

	lines := []string{
		`{"time":"2026-04-09T10:00:00Z","level":"DEBUG","msg":"handling event","agent_id":"test-bot","sender":"@user:example.com"}`,
		`{"time":"2026-04-09T10:00:01Z","level":"INFO","msg":"command_received","agent_id":"test-bot","command":"help"}`,
		`{"time":"2026-04-09T10:00:02Z","level":"DEBUG","msg":"handling event","agent_id":"test-bot","sender":"@user2:example.com"}`,
		`{"time":"2026-04-09T10:01:00Z","level":"DEBUG","msg":"LLM responded","agent_id":"test-bot","content_len":100,"duration_ms":500}`,
		`{"time":"2026-04-09T10:01:01Z","level":"DEBUG","msg":"LLM responded","agent_id":"test-bot","content_len":200,"duration_ms":300,"tokens_used":150}`,
		`{"time":"2026-04-09T10:02:00Z","level":"INFO","msg":"tool_exec_end","agent_id":"test-bot","tool":"current_time","duration_ms":5}`,
		`{"time":"2026-04-09T10:02:01Z","level":"WARN","msg":"tool_exec_error","agent_id":"test-bot","tool":"ssh_command","err":"timeout"}`,
		`{"time":"2026-04-09T10:03:00Z","level":"ERROR","msg":"something_failed","agent_id":"test-bot"}`,
	}

	content := strings.Join(lines, "\n") + "\n"
	if err := os.WriteFile(logFile, []byte(content), 0o644); err != nil {
		t.Fatalf("WriteFile: %v", err)
	}

	a := newMetricsTestAgent(dir)
	result := a.cmdMetrics(context.Background(), decision.MessageContext{})

	// Verify the output contains expected metrics
	checks := map[string]string{
		"messages":    "| Mensajes recibidos | 2 |",
		"commands":    "| Comandos ejecutados | 1 |",
		"llm_calls":  "| Llamadas LLM | 2 |",
		"llm_tokens":  "| Tokens LLM (total) | 150 |",
		"tool_calls":  "| Llamadas a tools | 2 |",
		"tool_errors": "| Errores de tools | 1 |",
		"errors":      "| Errores totales | 1 |",
		"entries":     "| Entradas de log | 8 |",
	}

	for name, expected := range checks {
		if !strings.Contains(result, expected) {
			t.Errorf("missing %s: expected %q in output:\n%s", name, expected, result)
		}
	}
}

func TestCmdMetrics_LLMLatencyAverage(t *testing.T) {
	dir := t.TempDir()
	agentDir := filepath.Join(dir, "test-bot")
	os.MkdirAll(agentDir, 0o755)

	today := time.Now().UTC().Format("2006-01-02")
	logFile := filepath.Join(agentDir, today+".jsonl")

	lines := []string{
		`{"time":"2026-04-09T10:01:00Z","level":"DEBUG","msg":"LLM responded","duration_ms":400}`,
		`{"time":"2026-04-09T10:01:01Z","level":"DEBUG","msg":"LLM responded","duration_ms":600}`,
	}

	content := strings.Join(lines, "\n") + "\n"
	os.WriteFile(logFile, []byte(content), 0o644)

	a := newMetricsTestAgent(dir)
	result := a.cmdMetrics(context.Background(), decision.MessageContext{})

	// Average of 400 and 600 = 500
	if !strings.Contains(result, "| Latencia LLM (media) | 500 ms |") {
		t.Errorf("expected average latency 500 ms in output:\n%s", result)
	}
}
