package feed

import (
	"encoding/json"
	"os"
	"path/filepath"
	"testing"
	"time"

	"github.com/steveyegge/gastown/internal/events"
)

func TestCurator_FiltersByVisibility(t *testing.T) {
	// Create temp directory
	tmpDir, err := os.MkdirTemp("", "feed-test-*")
	if err != nil {
		t.Fatalf("creating temp dir: %v", err)
	}
	defer os.RemoveAll(tmpDir)

	// Create events file with test events
	eventsPath := filepath.Join(tmpDir, events.EventsFile)
	feedPath := filepath.Join(tmpDir, FeedFile)

	// Write a feed-visible event
	feedEvent := events.Event{
		Timestamp:  time.Now().UTC().Format(time.RFC3339),
		Source:     "gt",
		Type:       events.TypeSling,
		Actor:      "mayor",
		Payload:    map[string]interface{}{"bead": "gt-123", "target": "gastown/slit"},
		Visibility: events.VisibilityFeed,
	}
	feedData, _ := json.Marshal(feedEvent)

	// Write an audit-only event (should be filtered out)
	auditEvent := events.Event{
		Timestamp:  time.Now().UTC().Format(time.RFC3339),
		Source:     "gt",
		Type:       "internal_check",
		Actor:      "daemon",
		Visibility: events.VisibilityAudit,
	}
	auditData, _ := json.Marshal(auditEvent)

	// Create events file
	if err := os.WriteFile(eventsPath, []byte{}, 0644); err != nil {
		t.Fatalf("creating events file: %v", err)
	}

	// Start curator
	curator := NewCurator(tmpDir)
	if err := curator.Start(); err != nil {
		t.Fatalf("starting curator: %v", err)
	}
	defer curator.Stop()

	// Give curator time to start
	time.Sleep(50 * time.Millisecond)

	// Append events
	f, err := os.OpenFile(eventsPath, os.O_APPEND|os.O_WRONLY, 0644)
	if err != nil {
		t.Fatalf("opening events file: %v", err)
	}
	f.Write(append(feedData, '\n'))
	f.Write(append(auditData, '\n'))
	f.Close()

	// Wait for processing
	time.Sleep(300 * time.Millisecond)

	// Check feed file
	feedContent, err := os.ReadFile(feedPath)
	if err != nil {
		t.Fatalf("reading feed file: %v", err)
	}

	// Should contain feed event but not audit event
	if len(feedContent) == 0 {
		t.Error("feed file is empty, expected at least one event")
	}

	var writtenEvent FeedEvent
	if err := json.Unmarshal(feedContent[:len(feedContent)-1], &writtenEvent); err != nil {
		t.Fatalf("parsing feed event: %v", err)
	}

	if writtenEvent.Type != events.TypeSling {
		t.Errorf("expected type %s, got %s", events.TypeSling, writtenEvent.Type)
	}
	if writtenEvent.Actor != "mayor" {
		t.Errorf("expected actor 'mayor', got %s", writtenEvent.Actor)
	}
}

func TestCurator_DedupesDoneEvents(t *testing.T) {
	tmpDir, err := os.MkdirTemp("", "feed-test-*")
	if err != nil {
		t.Fatalf("creating temp dir: %v", err)
	}
	defer os.RemoveAll(tmpDir)

	eventsPath := filepath.Join(tmpDir, events.EventsFile)
	feedPath := filepath.Join(tmpDir, FeedFile)

	// Create events file
	if err := os.WriteFile(eventsPath, []byte{}, 0644); err != nil {
		t.Fatalf("creating events file: %v", err)
	}

	// Start curator
	curator := NewCurator(tmpDir)
	if err := curator.Start(); err != nil {
		t.Fatalf("starting curator: %v", err)
	}
	defer curator.Stop()

	time.Sleep(50 * time.Millisecond)

	// Write 3 identical done events from same actor
	f, _ := os.OpenFile(eventsPath, os.O_APPEND|os.O_WRONLY, 0644)
	for i := 0; i < 3; i++ {
		doneEvent := events.Event{
			Timestamp:  time.Now().UTC().Format(time.RFC3339),
			Source:     "gt",
			Type:       events.TypeDone,
			Actor:      "gastown/slit",
			Payload:    map[string]interface{}{"bead": "slit-12345"},
			Visibility: events.VisibilityFeed,
		}
		data, _ := json.Marshal(doneEvent)
		f.Write(append(data, '\n'))
	}
	f.Close()

	// Wait for processing
	time.Sleep(300 * time.Millisecond)

	// Count feed events
	feedContent, _ := os.ReadFile(feedPath)
	lines := 0
	for _, b := range feedContent {
		if b == '\n' {
			lines++
		}
	}

	// Should only have 1 event due to deduplication
	if lines != 1 {
		t.Errorf("expected 1 feed event after deduplication, got %d", lines)
	}
}

func TestCurator_GeneratesSummary(t *testing.T) {
	tmpDir, _ := os.MkdirTemp("", "feed-test-*")
	defer os.RemoveAll(tmpDir)

	curator := NewCurator(tmpDir)

	tests := []struct {
		event    *events.Event
		expected string
	}{
		{
			event: &events.Event{
				Type:    events.TypeSling,
				Actor:   "mayor",
				Payload: map[string]interface{}{"bead": "gt-123", "target": "gastown/slit"},
			},
			expected: "mayor assigned gt-123 to gastown/slit",
		},
		{
			event: &events.Event{
				Type:    events.TypeDone,
				Actor:   "gastown/slit",
				Payload: map[string]interface{}{"bead": "slit-12345"},
			},
			expected: "gastown/slit completed work on slit-12345",
		},
		{
			event: &events.Event{
				Type:  events.TypeHandoff,
				Actor: "gastown/witness",
			},
			expected: "gastown/witness handed off to fresh session",
		},
	}

	for _, tc := range tests {
		summary := curator.generateSummary(tc.event)
		if summary != tc.expected {
			t.Errorf("generateSummary(%s): expected %q, got %q", tc.event.Type, tc.expected, summary)
		}
	}
}
