package storage

import (
	"database/sql"
	"testing"
	"time"

	"git.toki-labs.com/toki/gito/services/core/internal/events"
)

type mockScanner struct {
	scanFunc func(dest ...any) error
}

func (m *mockScanner) Scan(dest ...any) error {
	return m.scanFunc(dest...)
}

func TestScanOperationEventAllowsNullOperationID(t *testing.T) {
	now := time.Now().UTC()

	// mockScanner that returns NULL for operation_id
	mock := &mockScanner{
		scanFunc: func(dest ...any) error {
			if len(dest) != 7 {
				t.Fatalf("expected 7 dest arguments, got %d", len(dest))
			}

			// 1. opID (sql.NullString) -> NULL
			if opID, ok := dest[0].(*sql.NullString); ok {
				*opID = sql.NullString{String: "", Valid: false}
			} else {
				t.Fatalf("dest[0] is not *sql.NullString")
			}

			// 2. Event.ID (string)
			if id, ok := dest[1].(*string); ok {
				*id = "evt_123"
			} else {
				t.Fatalf("dest[1] is not *string")
			}

			// 3. Event.Type (string)
			if et, ok := dest[2].(*string); ok {
				*et = events.BranchUpdated
			} else {
				t.Fatalf("dest[2] is not *string")
			}

			// 4. Event.Subject (string)
			if sub, ok := dest[3].(*string); ok {
				*sub = "repo:myrepo"
			} else {
				t.Fatalf("dest[3] is not *string")
			}

			// 5. Event.Payload ([]byte)
			if pay, ok := dest[4].(*[]byte); ok {
				*pay = []byte(`{"branch":"main"}`)
			} else {
				t.Fatalf("dest[4] is not *[]byte")
			}

			// 6. Event.CreatedAt (time.Time)
			if cat, ok := dest[5].(*time.Time); ok {
				*cat = now
			} else {
				t.Fatalf("dest[5] is not *time.Time")
			}

			// 7. publishedAt (sql.NullTime) -> NULL (not published yet)
			if pat, ok := dest[6].(*sql.NullTime); ok {
				*pat = sql.NullTime{Valid: false}
			} else {
				t.Fatalf("dest[6] is not *sql.NullTime")
			}

			return nil
		},
	}

	ev, err := scanOperationEvent(mock)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	if ev.OperationID != "" {
		t.Errorf("expected empty OperationID, got %q", ev.OperationID)
	}
	if ev.Event.ID != "evt_123" {
		t.Errorf("expected Event.ID 'evt_123', got %q", ev.Event.ID)
	}
	if ev.Event.Type != events.BranchUpdated {
		t.Errorf("expected Event.Type 'branch.updated', got %q", ev.Event.Type)
	}
	if ev.Event.Subject != "repo:myrepo" {
		t.Errorf("expected Event.Subject 'repo:myrepo', got %q", ev.Event.Subject)
	}
	if string(ev.Event.Payload) != `{"branch":"main"}` {
		t.Errorf("expected Event.Payload, got %q", string(ev.Event.Payload))
	}
	if !ev.Event.CreatedAt.Equal(now) {
		t.Errorf("expected Event.CreatedAt %v, got %v", now, ev.Event.CreatedAt)
	}
	if ev.PublishedAt != nil {
		t.Errorf("expected nil PublishedAt, got %v", ev.PublishedAt)
	}
}
