package persistence

import (
	"testing"

	"github.com/nexuscrm/shared/pkg/models"
)

// -----------------------------------------------------------------------
// marshalJSON / unmarshalJSON  (metadata_repository.go)
// -----------------------------------------------------------------------

func TestMarshalJSON(t *testing.T) {
	r := &MetadataRepository{db: nil}

	t.Run("nil value returns empty string", func(t *testing.T) {
		got, err := r.marshalJSON(nil)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if got != "" {
			t.Errorf("marshalJSON(nil) = %q, want empty string", got)
		}
	})

	t.Run("string slice", func(t *testing.T) {
		got, err := r.marshalJSON([]string{"a", "b", "c"})
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if got != `["a","b","c"]` {
			t.Errorf("marshalJSON() = %q, want [\"a\",\"b\",\"c\"]", got)
		}
	})

	t.Run("map", func(t *testing.T) {
		got, err := r.marshalJSON(map[string]string{"key": "val"})
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if got != `{"key":"val"}` {
			t.Errorf("marshalJSON() = %q, want {\"key\":\"val\"}", got)
		}
	})

	t.Run("bool value", func(t *testing.T) {
		got, err := r.marshalJSON(true)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if got != "true" {
			t.Errorf("marshalJSON(true) = %q, want true", got)
		}
	})

	t.Run("int value", func(t *testing.T) {
		got, err := r.marshalJSON(42)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if got != "42" {
			t.Errorf("marshalJSON(42) = %q, want 42", got)
		}
	})

	t.Run("empty slice", func(t *testing.T) {
		got, err := r.marshalJSON([]string{})
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if got != "[]" {
			t.Errorf("marshalJSON(empty) = %q, want []", got)
		}
	})
}

func TestUnmarshalJSON(t *testing.T) {
	r := &MetadataRepository{db: nil}

	t.Run("empty string is no-op", func(t *testing.T) {
		var result []string
		r.unmarshalJSON("", &result)
		if result != nil {
			t.Errorf("unmarshalJSON empty should not modify target, got %v", result)
		}
	})

	t.Run("valid JSON array", func(t *testing.T) {
		var result []string
		r.unmarshalJSON(`["a","b","c"]`, &result)
		if len(result) != 3 {
			t.Errorf("expected 3 elements, got %d", len(result))
		}
	})

	t.Run("valid JSON object", func(t *testing.T) {
		var result map[string]interface{}
		r.unmarshalJSON(`{"key":"val"}`, &result)
		if result["key"] != "val" {
			t.Errorf("expected key=val, got %v", result["key"])
		}
	})

	t.Run("invalid JSON does not panic", func(t *testing.T) {
		var result []string
		// This should log an error but not panic
		r.unmarshalJSON("not-json{}", &result)
		if result != nil {
			t.Errorf("invalid JSON should not modify target, got %v", result)
		}
	})

	t.Run("valid JSON with nested objects", func(t *testing.T) {
		var result map[string]interface{}
		r.unmarshalJSON(`{"nested":{"a":1}}`, &result)
		if result["nested"] == nil {
			t.Error("expected nested object")
		}
	})
}

// -----------------------------------------------------------------------
// applyFieldAliasing  (metadata_scan_schema.go) — deprecated no-op
// -----------------------------------------------------------------------

func TestApplyFieldAliasing_NoOp(t *testing.T) {
	r := &MetadataRepository{db: nil}

	field := &models.FieldMetadata{
		APIName: "TestField",
		Label:   "Test",
	}

	// Should not modify the field (it's a deprecated no-op)
	r.applyFieldAliasing(field, true)
	if field.APIName != "TestField" {
		t.Errorf("applyFieldAliasing should be a no-op, APIName changed to %q", field.APIName)
	}

	r.applyFieldAliasing(field, false)
	if field.APIName != "TestField" {
		t.Errorf("applyFieldAliasing should be a no-op, APIName changed to %q", field.APIName)
	}
}

// -----------------------------------------------------------------------
// NewRecordRepository, NewQueryRepository, etc — constructor tests
// -----------------------------------------------------------------------

func TestNewRecordRepository(t *testing.T) {
	r := NewRecordRepository(nil)
	if r == nil {
		t.Fatal("NewRecordRepository should not return nil")
	}
	if r.db != nil {
		t.Error("db should be nil when passed nil")
	}
}

func TestNewQueryRepository(t *testing.T) {
	r := NewQueryRepository(nil)
	if r == nil {
		t.Fatal("NewQueryRepository should not return nil")
	}
}

func TestNewSchemaRepository(t *testing.T) {
	r := NewSchemaRepository(nil, nil)
	if r == nil {
		t.Fatal("NewSchemaRepository should not return nil")
	}
}

func TestNewMetadataRepository(t *testing.T) {
	r := NewMetadataRepository(nil)
	if r == nil {
		t.Fatal("NewMetadataRepository should not return nil")
	}
}

func TestNewPermissionRepository(t *testing.T) {
	r := NewPermissionRepository(nil)
	if r == nil {
		t.Fatal("NewPermissionRepository should not return nil")
	}
}

func TestNewBulkRepository(t *testing.T) {
	r := NewBulkRepository(nil)
	if r == nil {
		t.Fatal("NewBulkRepository should not return nil")
	}
}

func TestNewUserRepository(t *testing.T) {
	r := NewUserRepository(nil)
	if r == nil {
		t.Fatal("NewUserRepository should not return nil")
	}
}

func TestSetSchemaProvider(t *testing.T) {
	r := NewRecordRepository(nil)
	r.SetSchemaProvider(nil)
	if r.schemaProvider != nil {
		t.Error("schemaProvider should be nil")
	}
}

func TestNewMRURepository(t *testing.T) {
	r := NewMRURepository(nil)
	if r == nil {
		t.Fatal("NewMRURepository should not return nil")
	}
}

func TestNewOAuthRepository(t *testing.T) {
	r := NewOAuthRepository(nil)
	if r == nil {
		t.Fatal("NewOAuthRepository should not return nil")
	}
}

func TestNewOutboxRepository(t *testing.T) {
	r := NewOutboxRepository(nil)
	if r == nil {
		t.Fatal("NewOutboxRepository should not return nil")
	}
}

func TestNewSessionRepository(t *testing.T) {
	r := NewSessionRepository(nil)
	if r == nil {
		t.Fatal("NewSessionRepository should not return nil")
	}
}

func TestNewSystemRepository(t *testing.T) {
	r := NewSystemRepository(nil)
	if r == nil {
		t.Fatal("NewSystemRepository should not return nil")
	}
}

func TestNewRollupRepository(t *testing.T) {
	r := NewRollupRepository(nil)
	if r == nil {
		t.Fatal("NewRollupRepository should not return nil")
	}
}
