package events_test

import (
	"encoding/json"
	"testing"
	"time"

	"bit.admedia.com/scm/ad/adpilot-indexing-code-parser.com/internal/contracts/events"
)

func TestFileChangedEventJSONRoundTrip(t *testing.T) {
	original := events.NewFileChangedEvent(
		"evt_1",
		"company/payment-service",
		"snap_1",
		"a3f9c12b",
		"src/payments/processor.go",
		"go",
		events.FileKindCode,
		events.ChangeTypeModified,
	)

	data, err := json.Marshal(original)
	if err != nil {
		t.Fatalf("marshal: %v", err)
	}

	var decoded events.FileChangedEvent
	if err := json.Unmarshal(data, &decoded); err != nil {
		t.Fatalf("unmarshal: %v", err)
	}

	if decoded.EventID != original.EventID {
		t.Errorf("event_id: got %q, want %q", decoded.EventID, original.EventID)
	}
	if decoded.EventVersion != "v1" {
		t.Errorf("event_version: got %q, want v1", decoded.EventVersion)
	}
	if decoded.RepoID != original.RepoID {
		t.Errorf("repo_id: got %q, want %q", decoded.RepoID, original.RepoID)
	}
	if decoded.FilePath != original.FilePath {
		t.Errorf("file_path: got %q, want %q", decoded.FilePath, original.FilePath)
	}
	if decoded.FileKind != events.FileKindCode {
		t.Errorf("file_kind: got %q, want code", decoded.FileKind)
	}
	if decoded.ChangeType != events.ChangeTypeModified {
		t.Errorf("change_type: got %q, want modified", decoded.ChangeType)
	}
}

func TestCommitsChangedEventJSONRoundTrip(t *testing.T) {
	original := events.NewCommitsChangedEvent(
		"evt_cc_1",
		"company/payment-service",
		"snap_1",
		"a3f9c12b",
	)
	original.ParentSHA = "b2e8a01a"
	original.ChangedFiles = []string{"src/main.go", "src/util.go"}

	data, err := json.Marshal(original)
	if err != nil {
		t.Fatalf("marshal: %v", err)
	}

	var decoded events.CommitsChangedEvent
	if err := json.Unmarshal(data, &decoded); err != nil {
		t.Fatalf("unmarshal: %v", err)
	}

	if decoded.ParentSHA != "b2e8a01a" {
		t.Errorf("parent_sha: got %q, want b2e8a01a", decoded.ParentSHA)
	}
	if len(decoded.ChangedFiles) != 2 {
		t.Fatalf("changed_files: got %d, want 2", len(decoded.ChangedFiles))
	}
}

func TestChunksReadyEventJSONRoundTrip(t *testing.T) {
	original := events.NewChunksReadyEvent(
		"evt_cr_1",
		"company/payment-service",
		"snap_1",
		"a3f9c12b",
		"src/payments/processor.go",
		"go",
		[]events.CodeChunk{
			{
				ChunkID:    "chunk_1",
				SymbolName: "ProcessPayment",
				SymbolType: events.SymbolTypeFunction,
				StartLine:  10,
				EndLine:    42,
			},
		},
	)

	data, err := json.Marshal(original)
	if err != nil {
		t.Fatalf("marshal: %v", err)
	}

	var decoded events.ChunksReadyEvent
	if err := json.Unmarshal(data, &decoded); err != nil {
		t.Fatalf("unmarshal: %v", err)
	}

	if len(decoded.Chunks) != 1 {
		t.Fatalf("chunks: got %d, want 1", len(decoded.Chunks))
	}
	if decoded.Chunks[0].SymbolType != events.SymbolTypeFunction {
		t.Errorf("symbol_type: got %q, want function", decoded.Chunks[0].SymbolType)
	}
}

func TestFileChangedEventUnmarshalFromRepoSyncPayload(t *testing.T) {
	createdAt := time.Date(2026, 5, 22, 11, 30, 0, 0, time.UTC)
	payload := []byte(`{
		"event_id": "evt_snap_01_ready_file_a1b2c3d4",
		"event_version": "v1",
		"created_at": "2026-05-22T11:30:00Z",
		"repo_id": "ad/adpilot-indexing-repo-sync.com",
		"snapshot_id": "snap_01HZX",
		"commit_sha": "a3f9c12b",
		"file_path": "internal/service/sync.go",
		"language": "go",
		"file_kind": "code",
		"change_type": "modified"
	}`)

	var decoded events.FileChangedEvent
	if err := json.Unmarshal(payload, &decoded); err != nil {
		t.Fatalf("unmarshal repo-sync payload: %v", err)
	}

	if decoded.EventID != "evt_snap_01_ready_file_a1b2c3d4" {
		t.Errorf("event_id: got %q", decoded.EventID)
	}
	if decoded.RepoID != "ad/adpilot-indexing-repo-sync.com" {
		t.Errorf("repo_id: got %q", decoded.RepoID)
	}
	if decoded.FileKind != events.FileKindCode {
		t.Errorf("file_kind: got %q", decoded.FileKind)
	}
	if !decoded.CreatedAt.Equal(createdAt) {
		t.Errorf("created_at: got %v, want %v", decoded.CreatedAt, createdAt)
	}
}

func TestFileKindIsValid(t *testing.T) {
	if !events.FileKindCode.IsValid() {
		t.Fatal("expected code to be valid")
	}
	if events.FileKind("invalid").IsValid() {
		t.Fatal("expected invalid file kind to be rejected")
	}
}

func TestChangeTypeIsValid(t *testing.T) {
	if !events.ChangeTypeAdded.IsValid() {
		t.Fatal("expected added to be valid")
	}
	if events.ChangeType("copied").IsValid() {
		t.Fatal("expected invalid change type to be rejected")
	}
}
