package datahub

import (
	"context"
	"errors"
	"testing"

	dhclient "github.com/txn2/mcp-datahub/pkg/client"
	"github.com/txn2/mcp-datahub/pkg/types"

	"github.com/txn2/mcp-data-platform/pkg/semantic"
)

const (
	dhAdapterTestMaxHops       = 3
	dhAdapterTestInheritLen    = 3
	dhAdapterTestColumnsLen    = 3
	dhAdapterTestTimestampMs   = 1700000000000
	dhAdapterTestPropsIntVal   = 123
	dhAdapterTestLineageDepth  = 3
	dhAdapterTestUnexpectedErr = "unexpected error: %v"
	dhAdapterTestPlatformTrino = "trino"
	dhAdapterTestTableUsers    = "users"
	dhAdapterTestCatalogRdbms  = "rdbms"
	dhAdapterTestSchemaPublic  = "public"
	dhAdapterTestPlatformPG    = "postgres"
	dhAdapterTestExpectedErr   = "expected error"
)

// mockDataHubClient implements the Client interface for testing.
type mockDataHubClient struct {
	searchAcrossEntitiesFunc func(ctx context.Context, query string, opts ...dhclient.SearchOption) (*types.SearchResult, error)
	semanticSearchFunc       func(ctx context.Context, query string, opts ...dhclient.SearchOption) (*types.SearchResult, error)
	getEntityFunc            func(ctx context.Context, urn string) (*types.Entity, error)
	getSchemaFunc            func(ctx context.Context, urn string) (*types.SchemaMetadata, error)
	getSchemasFunc           func(ctx context.Context, urns []string) (map[string]*types.SchemaMetadata, error)
	getLineageFunc           func(ctx context.Context, urn string, opts ...dhclient.LineageOption) (*types.LineageResult, error)
	getColumnLineageFunc     func(ctx context.Context, urn string) (*types.ColumnLineage, error)
	getGlossaryTermFunc      func(ctx context.Context, urn string) (*types.GlossaryTerm, error)
	getQueriesFunc           func(ctx context.Context, urn string) (*types.QueryList, error)
	pingFunc                 func(ctx context.Context) error
	closeFunc                func() error
}

func (m *mockDataHubClient) SearchAcrossEntities(ctx context.Context, query string, opts ...dhclient.SearchOption) (*types.SearchResult, error) {
	if m.searchAcrossEntitiesFunc != nil {
		return m.searchAcrossEntitiesFunc(ctx, query, opts...)
	}
	return &types.SearchResult{}, nil
}

func (m *mockDataHubClient) SemanticSearch(ctx context.Context, query string, opts ...dhclient.SearchOption) (*types.SearchResult, error) {
	if m.semanticSearchFunc != nil {
		return m.semanticSearchFunc(ctx, query, opts...)
	}
	return &types.SearchResult{}, nil
}

func (m *mockDataHubClient) GetEntity(ctx context.Context, urn string) (*types.Entity, error) {
	if m.getEntityFunc != nil {
		return m.getEntityFunc(ctx, urn)
	}
	return &types.Entity{}, nil
}

func (m *mockDataHubClient) GetSchema(ctx context.Context, urn string) (*types.SchemaMetadata, error) {
	if m.getSchemaFunc != nil {
		return m.getSchemaFunc(ctx, urn)
	}
	return &types.SchemaMetadata{}, nil
}

func (m *mockDataHubClient) GetSchemas(ctx context.Context, urns []string) (map[string]*types.SchemaMetadata, error) {
	if m.getSchemasFunc != nil {
		return m.getSchemasFunc(ctx, urns)
	}
	return make(map[string]*types.SchemaMetadata), nil
}

func (m *mockDataHubClient) GetLineage(ctx context.Context, urn string, opts ...dhclient.LineageOption) (*types.LineageResult, error) {
	if m.getLineageFunc != nil {
		return m.getLineageFunc(ctx, urn, opts...)
	}
	return &types.LineageResult{}, nil
}

func (m *mockDataHubClient) GetColumnLineage(ctx context.Context, urn string) (*types.ColumnLineage, error) {
	if m.getColumnLineageFunc != nil {
		return m.getColumnLineageFunc(ctx, urn)
	}
	return &types.ColumnLineage{DatasetURN: urn}, nil
}

func (m *mockDataHubClient) GetGlossaryTerm(ctx context.Context, urn string) (*types.GlossaryTerm, error) {
	if m.getGlossaryTermFunc != nil {
		return m.getGlossaryTermFunc(ctx, urn)
	}
	return &types.GlossaryTerm{}, nil
}

func (m *mockDataHubClient) GetQueries(ctx context.Context, urn string) (*types.QueryList, error) {
	if m.getQueriesFunc != nil {
		return m.getQueriesFunc(ctx, urn)
	}
	return &types.QueryList{}, nil
}

func (m *mockDataHubClient) Ping(ctx context.Context) error {
	if m.pingFunc != nil {
		return m.pingFunc(ctx)
	}
	return nil
}

func (m *mockDataHubClient) Close() error {
	if m.closeFunc != nil {
		return m.closeFunc()
	}
	return nil
}

func TestNewWithClient_NilClient(t *testing.T) {
	_, err := NewWithClient(Config{}, nil)
	if err == nil {
		t.Error("expected error for nil client")
	}
}

func TestNewWithClient_ValidClient(t *testing.T) {
	mock := &mockDataHubClient{}
	adapter, err := NewWithClient(Config{}, mock)
	if err != nil {
		t.Fatalf(dhAdapterTestUnexpectedErr, err)
	}
	if adapter.Name() != "datahub" {
		t.Errorf("expected name 'datahub', got %q", adapter.Name())
	}
	if adapter.cfg.Platform != dhAdapterTestPlatformTrino {
		t.Errorf("expected default platform 'trino', got %q", adapter.cfg.Platform)
	}
}

func TestNewWithClient_Debug(t *testing.T) {
	mock := &mockDataHubClient{}

	adapter, err := NewWithClient(Config{Debug: true}, mock)
	if err != nil {
		t.Fatalf(dhAdapterTestUnexpectedErr, err)
	}
	if !adapter.cfg.Debug {
		t.Error("expected Debug to be true")
	}

	adapter2, err := NewWithClient(Config{}, mock)
	if err != nil {
		t.Fatalf(dhAdapterTestUnexpectedErr, err)
	}
	if adapter2.cfg.Debug {
		t.Error("expected Debug to default to false")
	}
}

func TestNewWithClient_LineageConfig(t *testing.T) {
	mock := &mockDataHubClient{}
	lineageCfg := LineageConfig{
		Enabled:             true,
		MaxHops:             dhAdapterTestMaxHops,
		Inherit:             []string{"glossary_terms", "descriptions", "tags"},
		ConflictResolution:  "nearest",
		PreferColumnLineage: true,
	}
	adapter, err := NewWithClient(Config{URL: "http://datahub.example.com", Lineage: lineageCfg}, mock)
	if err != nil {
		t.Fatalf(dhAdapterTestUnexpectedErr, err)
	}

	gotCfg := adapter.LineageConfig()
	if !gotCfg.Enabled {
		t.Error("LineageConfig().Enabled = false, want true")
	}
	if gotCfg.MaxHops != dhAdapterTestMaxHops {
		t.Errorf("LineageConfig().MaxHops = %d, want %d", gotCfg.MaxHops, dhAdapterTestMaxHops)
	}
	if len(gotCfg.Inherit) != dhAdapterTestInheritLen {
		t.Errorf("LineageConfig().Inherit len = %d, want %d", len(gotCfg.Inherit), dhAdapterTestInheritLen)
	}
	if gotCfg.ConflictResolution != "nearest" {
		t.Errorf("LineageConfig().ConflictResolution = %q, want %q", gotCfg.ConflictResolution, "nearest")
	}
	if !gotCfg.PreferColumnLineage {
		t.Error("LineageConfig().PreferColumnLineage = false, want true")
	}
}

func TestAdapterName(t *testing.T) {
	mock := &mockDataHubClient{}
	adapter, _ := NewWithClient(Config{}, mock)
	if adapter.Name() != "datahub" {
		t.Errorf("expected 'datahub', got %q", adapter.Name())
	}
}

func TestGetTableContext(t *testing.T) {
	ctx := context.Background()

	mock := &mockDataHubClient{
		getEntityFunc: func(_ context.Context, _ string) (*types.Entity, error) {
			return &types.Entity{
				URN:          "urn:li:dataset:(urn:li:dataPlatform:trino,schema.table,PROD)",
				Description:  "Test table",
				LastModified: dhAdapterTestTimestampMs,
				Owners: []types.Owner{
					{URN: "urn:li:corpuser:owner1", Name: "Owner One", Email: "owner1@example.com", Type: types.OwnershipTypeTechnicalOwner},
				},
				Tags: []types.Tag{
					{Name: "important"},
				},
				GlossaryTerms: []types.GlossaryTerm{
					{URN: "urn:li:glossaryTerm:revenue", Name: "Revenue"},
				},
				Domain: &types.Domain{
					URN:  "urn:li:domain:finance",
					Name: "Finance",
				},
				Deprecation: &types.Deprecation{
					Deprecated: true,
					Note:       "Use new_table instead",
				},
				Properties: map[string]any{
					"owner_team": "analytics",
				},
			}, nil
		},
	}
	adapter, _ := NewWithClient(Config{Platform: dhAdapterTestPlatformTrino}, mock)

	result, err := adapter.GetTableContext(ctx, semantic.TableIdentifier{Schema: "schema", Table: "table"})
	if err != nil {
		t.Fatalf(dhAdapterTestUnexpectedErr, err)
	}

	if result.Description != "Test table" {
		t.Errorf("expected description 'Test table', got %q", result.Description)
	}
	if len(result.Owners) != 1 {
		t.Errorf("expected 1 owner, got %d", len(result.Owners))
	}
	if len(result.Tags) != 1 {
		t.Errorf("expected 1 tag, got %d", len(result.Tags))
	}
	if result.Domain == nil || result.Domain.Name != "Finance" {
		t.Error("expected domain Finance")
	}
	if result.Deprecation == nil || !result.Deprecation.Deprecated {
		t.Error("expected deprecation to be set")
	}
}

func TestGetColumnContext(t *testing.T) {
	ctx := context.Background()

	mock := &mockDataHubClient{
		getSchemaFunc: func(_ context.Context, _ string) (*types.SchemaMetadata, error) {
			return &types.SchemaMetadata{
				Fields: []types.SchemaField{
					{
						FieldPath:   "user_id",
						Description: "User identifier",
						Tags:        []types.Tag{{Name: "pii"}},
					},
					{
						FieldPath:   "email",
						Description: "User email",
						Tags:        []types.Tag{{Name: "sensitive"}},
						GlossaryTerms: []types.GlossaryTerm{
							{URN: "urn:li:glossaryTerm:email", Name: "Email Address"},
						},
					},
				},
			}, nil
		},
	}
	adapter, _ := NewWithClient(Config{Platform: dhAdapterTestPlatformTrino}, mock)

	t.Run("found column", func(t *testing.T) {
		result, err := adapter.GetColumnContext(ctx, semantic.ColumnIdentifier{
			TableIdentifier: semantic.TableIdentifier{Schema: "schema", Table: "table"},
			Column:          "email",
		})
		if err != nil {
			t.Fatalf(dhAdapterTestUnexpectedErr, err)
		}
		if result.Name != "email" {
			t.Errorf("expected name 'email', got %q", result.Name)
		}
		if !result.IsSensitive {
			t.Error("expected IsSensitive to be true")
		}
		if len(result.GlossaryTerms) != 1 {
			t.Errorf("expected 1 glossary term, got %d", len(result.GlossaryTerms))
		}
	})

	t.Run("column not found", func(t *testing.T) {
		_, err := adapter.GetColumnContext(ctx, semantic.ColumnIdentifier{
			TableIdentifier: semantic.TableIdentifier{Schema: "schema", Table: "table"},
			Column:          "nonexistent",
		})
		if err == nil {
			t.Error("expected error for missing column")
		}
	})
}

func TestGetColumnsContext(t *testing.T) {
	ctx := context.Background()

	mock := &mockDataHubClient{
		getSchemaFunc: func(_ context.Context, _ string) (*types.SchemaMetadata, error) {
			return &types.SchemaMetadata{
				Fields: []types.SchemaField{
					{FieldPath: "id", Description: "ID"},
					{FieldPath: "name", Description: "Name"},
					{FieldPath: "nested.field", Description: "Nested field"},
				},
			}, nil
		},
	}
	adapter, _ := NewWithClient(Config{Platform: dhAdapterTestPlatformTrino}, mock)

	result, err := adapter.GetColumnsContext(ctx, semantic.TableIdentifier{Schema: "schema", Table: "table"})
	if err != nil {
		t.Fatalf(dhAdapterTestUnexpectedErr, err)
	}

	if len(result) != dhAdapterTestColumnsLen {
		t.Errorf("expected %d columns, got %d", dhAdapterTestColumnsLen, len(result))
	}
	// Nested field should be extracted as just "field"
	if _, ok := result["field"]; !ok {
		t.Error("expected 'field' key for nested.field")
	}
}

func TestGetLineage(t *testing.T) {
	ctx := context.Background()

	mock := &mockDataHubClient{
		getLineageFunc: func(_ context.Context, _ string, _ ...dhclient.LineageOption) (*types.LineageResult, error) {
			return &types.LineageResult{
				Nodes: []types.LineageNode{
					{URN: "urn:li:dataset:1", Name: "source_table", Type: "DATASET", Platform: dhAdapterTestPlatformTrino, Level: 1},
					{URN: "urn:li:dataset:2", Name: "target_table", Type: "DATASET", Platform: dhAdapterTestPlatformTrino, Level: 0},
				},
				Edges: []types.LineageEdge{
					{Source: "urn:li:dataset:1", Target: "urn:li:dataset:2"},
				},
			}, nil
		},
	}
	adapter, _ := NewWithClient(Config{Platform: dhAdapterTestPlatformTrino}, mock)

	t.Run("upstream lineage", func(t *testing.T) {
		result, err := adapter.GetLineage(ctx, semantic.TableIdentifier{Schema: "schema", Table: "table"}, semantic.LineageUpstream, dhAdapterTestLineageDepth)
		if err != nil {
			t.Fatalf(dhAdapterTestUnexpectedErr, err)
		}
		if result.Direction != semantic.LineageUpstream {
			t.Errorf("expected upstream direction")
		}
		if len(result.Entities) != 2 {
			t.Errorf("expected 2 entities, got %d", len(result.Entities))
		}
	})

	t.Run("downstream lineage", func(t *testing.T) {
		result, err := adapter.GetLineage(ctx, semantic.TableIdentifier{Schema: "schema", Table: "table"}, semantic.LineageDownstream, dhAdapterTestLineageDepth)
		if err != nil {
			t.Fatalf(dhAdapterTestUnexpectedErr, err)
		}
		if result.Direction != semantic.LineageDownstream {
			t.Errorf("expected downstream direction")
		}
	})
}

func TestGetGlossaryTerm(t *testing.T) {
	ctx := context.Background()

	mock := &mockDataHubClient{
		getGlossaryTermFunc: func(_ context.Context, urn string) (*types.GlossaryTerm, error) {
			return &types.GlossaryTerm{
				URN:         urn,
				Name:        "Revenue",
				Description: "Total revenue from sales",
			}, nil
		},
	}
	adapter, _ := NewWithClient(Config{}, mock)

	result, err := adapter.GetGlossaryTerm(ctx, "urn:li:glossaryTerm:revenue")
	if err != nil {
		t.Fatalf(dhAdapterTestUnexpectedErr, err)
	}

	if result.Name != "Revenue" {
		t.Errorf("expected name 'Revenue', got %q", result.Name)
	}
	if result.Description != "Total revenue from sales" {
		t.Errorf("expected description, got %q", result.Description)
	}
}

func TestSearchTables(t *testing.T) {
	ctx := context.Background()

	mock := &mockDataHubClient{
		searchAcrossEntitiesFunc: func(_ context.Context, _ string, _ ...dhclient.SearchOption) (*types.SearchResult, error) {
			return &types.SearchResult{
				Entities: []types.SearchEntity{
					{
						URN:         "urn:li:dataset:1",
						Name:        dhAdapterTestTableUsers,
						Platform:    dhAdapterTestPlatformTrino,
						Description: "User table",
						Tags:        []types.Tag{{Name: "important"}},
						Domain:      &types.Domain{Name: "Core"},
						MatchedFields: []types.MatchedField{
							{Name: "name"},
						},
					},
				},
			}, nil
		},
	}
	adapter, _ := NewWithClient(Config{}, mock)

	results, err := adapter.SearchTables(ctx, semantic.SearchFilter{
		Query:  dhAdapterTestTableUsers,
		Limit:  10,
		Offset: 0,
	})
	if err != nil {
		t.Fatalf(dhAdapterTestUnexpectedErr, err)
	}

	if len(results) != 1 {
		t.Errorf("expected 1 result, got %d", len(results))
	}
	if results[0].Name != dhAdapterTestTableUsers {
		t.Errorf("expected name 'users', got %q", results[0].Name)
	}
	if results[0].Domain != "Core" {
		t.Errorf("expected domain 'Core', got %q", results[0].Domain)
	}
	if results[0].MatchedField != "name" {
		t.Errorf("expected matched field 'name', got %q", results[0].MatchedField)
	}
}

func TestResolveURN(t *testing.T) {
	mock := &mockDataHubClient{}
	adapter, _ := NewWithClient(Config{}, mock)
	ctx := context.Background()

	tests := []struct {
		name        string
		urn         string
		wantCatalog string
		wantSchema  string
		wantTable   string
		wantErr     bool
	}{
		{
			name:        "valid URN with 3 parts",
			urn:         "urn:li:dataset:(urn:li:dataPlatform:trino,catalog.schema.table,PROD)",
			wantCatalog: "catalog",
			wantSchema:  "schema",
			wantTable:   "table",
			wantErr:     false,
		},
		{
			name:       "valid URN with 2 parts",
			urn:        "urn:li:dataset:(urn:li:dataPlatform:trino,schema.table,PROD)",
			wantSchema: "schema",
			wantTable:  "table",
			wantErr:    false,
		},
		{
			name:    "invalid URN prefix",
			urn:     "urn:wrong:dataset:(urn:li:dataPlatform:trino,table,PROD)",
			wantErr: true,
		},
		{
			name:    "invalid URN format",
			urn:     "urn:li:dataset:invalid",
			wantErr: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result, err := adapter.ResolveURN(ctx, tt.urn)
			if tt.wantErr {
				if err == nil {
					t.Error(dhAdapterTestExpectedErr)
				}
				return
			}
			if err != nil {
				t.Fatalf(dhAdapterTestUnexpectedErr, err)
			}
			assertResolvedURN(t, result, tt.wantCatalog, tt.wantSchema, tt.wantTable)
		})
	}
}

func assertResolvedURN(t *testing.T, result *semantic.TableIdentifier, wantCatalog, wantSchema, wantTable string) {
	t.Helper()
	if result.Catalog != wantCatalog {
		t.Errorf("expected catalog %q, got %q", wantCatalog, result.Catalog)
	}
	if result.Schema != wantSchema {
		t.Errorf("expected schema %q, got %q", wantSchema, result.Schema)
	}
	if result.Table != wantTable {
		t.Errorf("expected table %q, got %q", wantTable, result.Table)
	}
}

func TestBuildURN(t *testing.T) {
	mock := &mockDataHubClient{}
	adapter, _ := NewWithClient(Config{Platform: dhAdapterTestPlatformTrino}, mock)
	ctx := context.Background()

	urn, err := adapter.BuildURN(ctx, semantic.TableIdentifier{Catalog: "hive", Schema: "analytics", Table: dhAdapterTestTableUsers})
	if err != nil {
		t.Fatalf(dhAdapterTestUnexpectedErr, err)
	}

	expected := "urn:li:dataset:(urn:li:dataPlatform:trino,hive.analytics.users,PROD)"
	if urn != expected {
		t.Errorf("expected %q, got %q", expected, urn)
	}
}

func TestBuildDatasetURNWithCatalogMapping(t *testing.T) {
	mock := &mockDataHubClient{}

	tests := []struct {
		name           string
		platform       string
		catalogMapping map[string]string
		table          semantic.TableIdentifier
		expectedURN    string
	}{
		{
			name:           "no mapping configured - uses original catalog",
			platform:       dhAdapterTestPlatformTrino,
			catalogMapping: nil,
			table:          semantic.TableIdentifier{Catalog: dhAdapterTestCatalogRdbms, Schema: dhAdapterTestSchemaPublic, Table: dhAdapterTestTableUsers},
			expectedURN:    "urn:li:dataset:(urn:li:dataPlatform:trino,rdbms.public.users,PROD)",
		},
		{
			name:           "catalog mapping applied",
			platform:       dhAdapterTestPlatformPG,
			catalogMapping: map[string]string{dhAdapterTestCatalogRdbms: "warehouse"},
			table:          semantic.TableIdentifier{Catalog: dhAdapterTestCatalogRdbms, Schema: dhAdapterTestSchemaPublic, Table: dhAdapterTestTableUsers},
			expectedURN:    "urn:li:dataset:(urn:li:dataPlatform:postgres,warehouse.public.users,PROD)",
		},
		{
			name:           "catalog not in mapping - uses original",
			platform:       dhAdapterTestPlatformPG,
			catalogMapping: map[string]string{"iceberg": "datalake"},
			table:          semantic.TableIdentifier{Catalog: dhAdapterTestCatalogRdbms, Schema: dhAdapterTestSchemaPublic, Table: dhAdapterTestTableUsers},
			expectedURN:    "urn:li:dataset:(urn:li:dataPlatform:postgres,rdbms.public.users,PROD)",
		},
		{
			name:           "empty catalog - schema.table only",
			platform:       dhAdapterTestPlatformPG,
			catalogMapping: map[string]string{dhAdapterTestCatalogRdbms: "warehouse"},
			table:          semantic.TableIdentifier{Schema: dhAdapterTestSchemaPublic, Table: dhAdapterTestTableUsers},
			expectedURN:    "urn:li:dataset:(urn:li:dataPlatform:postgres,public.users,PROD)",
		},
		{
			name:           "table only - no catalog or schema",
			platform:       dhAdapterTestPlatformPG,
			catalogMapping: nil,
			table:          semantic.TableIdentifier{Table: dhAdapterTestTableUsers},
			expectedURN:    "urn:li:dataset:(urn:li:dataPlatform:postgres,users,PROD)",
		},
		{
			name:           "multiple catalog mappings",
			platform:       dhAdapterTestPlatformPG,
			catalogMapping: map[string]string{dhAdapterTestCatalogRdbms: "warehouse", "iceberg": "datalake"},
			table:          semantic.TableIdentifier{Catalog: "iceberg", Schema: "analytics", Table: "events"},
			expectedURN:    "urn:li:dataset:(urn:li:dataPlatform:postgres,datalake.analytics.events,PROD)",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			adapter, err := NewWithClient(Config{
				Platform:       tt.platform,
				CatalogMapping: tt.catalogMapping,
			}, mock)
			if err != nil {
				t.Fatalf("unexpected error creating adapter: %v", err)
			}

			urn := adapter.buildDatasetURN(tt.table)
			if urn != tt.expectedURN {
				t.Errorf("expected URN %q, got %q", tt.expectedURN, urn)
			}
		})
	}
}

func TestAdapterClose(t *testing.T) {
	closed := false
	mock := &mockDataHubClient{
		closeFunc: func() error {
			closed = true
			return nil
		},
	}
	adapter, _ := NewWithClient(Config{}, mock)

	err := adapter.Close()
	if err != nil {
		t.Errorf(dhAdapterTestUnexpectedErr, err)
	}
	if !closed {
		t.Error("expected client to be closed")
	}
}

func TestConvertOwners(t *testing.T) {
	owners := []types.Owner{
		{URN: "urn:1", Name: "Owner1", Email: "o1@test.com", Type: types.OwnershipTypeTechnicalOwner},
		{URN: "urn:2", Name: "Owner2", Email: "o2@test.com", Type: types.OwnershipTypeBusinessOwner},
	}
	result := convertOwners(owners)
	if len(result) != 2 {
		t.Errorf("expected 2 owners, got %d", len(result))
	}
}

func TestConvertTags(t *testing.T) {
	tags := []types.Tag{{Name: "tag1"}, {Name: "tag2"}}
	result := convertTags(tags)
	if len(result) != 2 || result[0] != "tag1" {
		t.Error("tags not converted correctly")
	}
}

func TestConvertDomainAndDeprecation(t *testing.T) {
	if convertDomain(nil) != nil {
		t.Error("expected nil for nil domain")
	}
	if convertDeprecation(nil) != nil {
		t.Error("expected nil for nil deprecation")
	}

	dep := &types.Deprecation{Deprecated: true, Note: "test", DecommissionTime: dhAdapterTestTimestampMs}
	result := convertDeprecation(dep)
	if result.DecommDate == nil {
		t.Error("expected decommission date to be set")
	}
}

func TestConvertProperties(t *testing.T) {
	if convertProperties(nil) != nil {
		t.Error("expected nil for nil properties")
	}

	props := map[string]any{"key1": "value1", "key2": dhAdapterTestPropsIntVal, "key3": "value3"}
	result := convertProperties(props)
	if len(result) != 2 {
		t.Errorf("expected 2 properties, got %d", len(result))
	}
}

func TestConvertTimestamp(t *testing.T) {
	if convertTimestamp(0) != nil {
		t.Error("expected nil for zero timestamp")
	}
	if convertTimestamp(dhAdapterTestTimestampMs) == nil {
		t.Error("expected non-nil timestamp")
	}
}

func TestExtractFieldName(t *testing.T) {
	tests := []struct {
		input    string
		expected string
	}{
		{"simple", "simple"},
		{"nested.field", "field"},
		{"deeply.nested.field", "field"},
		{"", ""},
	}
	for _, tt := range tests {
		result := extractFieldName(tt.input)
		if result != tt.expected {
			t.Errorf("extractFieldName(%q) = %q, want %q", tt.input, result, tt.expected)
		}
	}
}

func TestOwnerTypeToSemantic(t *testing.T) {
	if ownerTypeToSemantic(types.OwnershipTypeTechnicalOwner) != semantic.OwnerTypeUser {
		t.Error("unexpected owner type conversion")
	}
	if ownerTypeToSemantic(types.OwnershipTypeBusinessOwner) != semantic.OwnerTypeUser {
		t.Error("unexpected owner type conversion")
	}
	if ownerTypeToSemantic(types.OwnershipType("unknown")) != semantic.OwnerTypeUser {
		t.Error("unexpected owner type conversion for unknown type")
	}
}

func TestGetTableContextError(t *testing.T) {
	ctx := context.Background()
	mock := &mockDataHubClient{
		getEntityFunc: func(_ context.Context, _ string) (*types.Entity, error) {
			return nil, errors.New("entity not found")
		},
	}
	adapter, _ := NewWithClient(Config{}, mock)

	_, err := adapter.GetTableContext(ctx, semantic.TableIdentifier{Schema: "schema", Table: "table"})
	if err == nil {
		t.Error(dhAdapterTestExpectedErr)
	}
}

func TestGetColumnContextError(t *testing.T) {
	ctx := context.Background()
	mock := &mockDataHubClient{
		getSchemaFunc: func(_ context.Context, _ string) (*types.SchemaMetadata, error) {
			return nil, errors.New("schema not found")
		},
	}
	adapter, _ := NewWithClient(Config{}, mock)

	_, err := adapter.GetColumnContext(ctx, semantic.ColumnIdentifier{
		TableIdentifier: semantic.TableIdentifier{Schema: "schema", Table: "table"},
		Column:          "col",
	})
	if err == nil {
		t.Error(dhAdapterTestExpectedErr)
	}
}

func TestGetColumnsContextError(t *testing.T) {
	ctx := context.Background()
	mock := &mockDataHubClient{
		getSchemaFunc: func(_ context.Context, _ string) (*types.SchemaMetadata, error) {
			return nil, errors.New("schema not found")
		},
	}
	adapter, _ := NewWithClient(Config{}, mock)

	_, err := adapter.GetColumnsContext(ctx, semantic.TableIdentifier{Schema: "schema", Table: "table"})
	if err == nil {
		t.Error(dhAdapterTestExpectedErr)
	}
}

func TestGetLineageError(t *testing.T) {
	ctx := context.Background()
	mock := &mockDataHubClient{
		getLineageFunc: func(_ context.Context, _ string, _ ...dhclient.LineageOption) (*types.LineageResult, error) {
			return nil, errors.New("lineage not found")
		},
	}
	adapter, _ := NewWithClient(Config{}, mock)

	_, err := adapter.GetLineage(ctx, semantic.TableIdentifier{Schema: "schema", Table: "table"}, semantic.LineageUpstream, dhAdapterTestLineageDepth)
	if err == nil {
		t.Error(dhAdapterTestExpectedErr)
	}
}

func TestGetGlossaryTermNotFound(t *testing.T) {
	ctx := context.Background()
	mock := &mockDataHubClient{
		getGlossaryTermFunc: func(_ context.Context, _ string) (*types.GlossaryTerm, error) {
			return nil, nil //nolint:nilnil // test mock: simulates not-found case
		},
	}
	adapter, _ := NewWithClient(Config{}, mock)

	_, err := adapter.GetGlossaryTerm(ctx, "urn:li:glossaryTerm:notfound")
	if err == nil {
		t.Error("expected error for nil glossary term")
	}
}

func TestGetGlossaryTermError(t *testing.T) {
	ctx := context.Background()
	mock := &mockDataHubClient{
		getGlossaryTermFunc: func(_ context.Context, _ string) (*types.GlossaryTerm, error) {
			return nil, errors.New("term not found")
		},
	}
	adapter, _ := NewWithClient(Config{}, mock)

	_, err := adapter.GetGlossaryTerm(ctx, "urn:li:glossaryTerm:notfound")
	if err == nil {
		t.Error(dhAdapterTestExpectedErr)
	}
}

func TestSearchTablesError(t *testing.T) {
	ctx := context.Background()
	mock := &mockDataHubClient{
		searchAcrossEntitiesFunc: func(_ context.Context, _ string, _ ...dhclient.SearchOption) (*types.SearchResult, error) {
			return nil, errors.New("search failed")
		},
	}
	adapter, _ := NewWithClient(Config{}, mock)

	_, err := adapter.SearchTables(ctx, semantic.SearchFilter{Query: "test"})
	if err == nil {
		t.Error(dhAdapterTestExpectedErr)
	}
}

func TestSearchTablesWithFilters(t *testing.T) {
	ctx := context.Background()
	mock := &mockDataHubClient{
		searchAcrossEntitiesFunc: func(_ context.Context, _ string, _ ...dhclient.SearchOption) (*types.SearchResult, error) {
			return &types.SearchResult{
				Entities: []types.SearchEntity{
					{URN: "urn:1", Name: "table1"},
				},
			}, nil
		},
	}
	adapter, _ := NewWithClient(Config{}, mock)

	// Test with domain and tag filters
	results, err := adapter.SearchTables(ctx, semantic.SearchFilter{
		Query:  "test",
		Domain: "finance",
		Tags:   []string{"pii", "sensitive"},
		Limit:  50,
		Offset: 10,
	})
	if err != nil {
		t.Fatalf(dhAdapterTestUnexpectedErr, err)
	}
	if len(results) != 1 {
		t.Errorf("expected 1 result, got %d", len(results))
	}
}

func TestSearchTablesAdvancedFilters(t *testing.T) {
	ctx := context.Background()

	t.Run("passes field filters to SearchAcrossEntities", func(t *testing.T) {
		var capturedQuery string
		mock := &mockDataHubClient{
			searchAcrossEntitiesFunc: func(_ context.Context, query string, _ ...dhclient.SearchOption) (*types.SearchResult, error) {
				capturedQuery = query
				return &types.SearchResult{
					Entities: []types.SearchEntity{
						{URN: "urn:1", Name: "orders"},
					},
				}, nil
			},
		}
		adapter, _ := NewWithClient(Config{}, mock)

		results, err := adapter.SearchTables(ctx, semantic.SearchFilter{
			Query: "*",
			Filters: []semantic.FieldFilter{
				{Field: "fieldPaths", Values: []string{"email"}, Condition: "CONTAIN"},
				{Field: "platform", Values: []string{"urn:li:dataPlatform:trino"}},
			},
			Limit: 10,
		})
		if err != nil {
			t.Fatalf(dhAdapterTestUnexpectedErr, err)
		}
		if capturedQuery != "*" {
			t.Errorf("expected query '*', got %q", capturedQuery)
		}
		if len(results) != 1 {
			t.Errorf("expected 1 result, got %d", len(results))
		}
	})

	t.Run("uses SemanticSearch for semantic mode", func(t *testing.T) {
		semanticCalled := false
		mock := &mockDataHubClient{
			semanticSearchFunc: func(_ context.Context, _ string, _ ...dhclient.SearchOption) (*types.SearchResult, error) {
				semanticCalled = true
				return &types.SearchResult{}, nil
			},
			searchAcrossEntitiesFunc: func(_ context.Context, _ string, _ ...dhclient.SearchOption) (*types.SearchResult, error) {
				t.Error("SearchAcrossEntities should not be called in semantic mode")
				return &types.SearchResult{}, nil
			},
		}
		adapter, _ := NewWithClient(Config{}, mock)

		_, err := adapter.SearchTables(ctx, semantic.SearchFilter{
			Query: "revenue metrics",
			Mode:  "semantic",
		})
		if err != nil {
			t.Fatalf(dhAdapterTestUnexpectedErr, err)
		}
		if !semanticCalled {
			t.Error("expected SemanticSearch to be called")
		}
	})

	t.Run("semantic mode is case-insensitive", func(t *testing.T) {
		semanticCalled := false
		mock := &mockDataHubClient{
			semanticSearchFunc: func(_ context.Context, _ string, _ ...dhclient.SearchOption) (*types.SearchResult, error) {
				semanticCalled = true
				return &types.SearchResult{}, nil
			},
		}
		adapter, _ := NewWithClient(Config{}, mock)

		_, err := adapter.SearchTables(ctx, semantic.SearchFilter{
			Query: "test",
			Mode:  "Semantic",
		})
		if err != nil {
			t.Fatalf(dhAdapterTestUnexpectedErr, err)
		}
		if !semanticCalled {
			t.Error("expected SemanticSearch to be called for capitalized Mode")
		}
	})

	t.Run("semantic mode with filters", func(t *testing.T) {
		semanticCalled := false
		mock := &mockDataHubClient{
			semanticSearchFunc: func(_ context.Context, _ string, _ ...dhclient.SearchOption) (*types.SearchResult, error) {
				semanticCalled = true
				return &types.SearchResult{
					Entities: []types.SearchEntity{{URN: "urn:1", Name: "revenue"}},
				}, nil
			},
		}
		adapter, _ := NewWithClient(Config{}, mock)

		results, err := adapter.SearchTables(ctx, semantic.SearchFilter{
			Query: "revenue",
			Mode:  "semantic",
			Filters: []semantic.FieldFilter{
				{Field: "fieldPaths", Values: []string{"amount"}, Condition: "CONTAIN"},
			},
		})
		if err != nil {
			t.Fatalf(dhAdapterTestUnexpectedErr, err)
		}
		if !semanticCalled {
			t.Error("expected SemanticSearch to be called")
		}
		if len(results) != 1 {
			t.Errorf("expected 1 result, got %d", len(results))
		}
	})

	t.Run("entity types override default DATASET", func(t *testing.T) {
		mock := &mockDataHubClient{
			searchAcrossEntitiesFunc: func(_ context.Context, _ string, _ ...dhclient.SearchOption) (*types.SearchResult, error) {
				return &types.SearchResult{}, nil
			},
		}
		adapter, _ := NewWithClient(Config{}, mock)

		_, err := adapter.SearchTables(ctx, semantic.SearchFilter{
			Query:       "test",
			EntityTypes: []string{"DATASET", "DASHBOARD"},
		})
		if err != nil {
			t.Fatalf(dhAdapterTestUnexpectedErr, err)
		}
	})
}

func TestBuildDHFilters(t *testing.T) {
	t.Run("empty filter produces no output", func(t *testing.T) {
		filters := buildDHFilters(semantic.SearchFilter{Query: "test"})
		if len(filters) != 0 {
			t.Errorf("expected 0 filters, got %d", len(filters))
		}
	})

	t.Run("legacy fields mapped correctly", func(t *testing.T) {
		filters := buildDHFilters(semantic.SearchFilter{
			Platform: "urn:li:dataPlatform:trino",
			Tags:     []string{"urn:li:tag:pii"},
			Domain:   "urn:li:domain:finance",
			Owner:    "urn:li:corpuser:alice",
		})
		if len(filters) != 4 {
			t.Fatalf("expected 4 filters, got %d", len(filters))
		}
		if filters[0].Field != "platform" {
			t.Errorf("expected platform filter, got %q", filters[0].Field)
		}
		if filters[1].Field != "tags" {
			t.Errorf("expected tags filter, got %q", filters[1].Field)
		}
		if filters[2].Field != "domains" {
			t.Errorf("expected domains filter, got %q", filters[2].Field)
		}
		if filters[3].Field != "owners" {
			t.Errorf("expected owners filter, got %q", filters[3].Field)
		}
	})

	t.Run("explicit filters with condition and negation", func(t *testing.T) {
		filters := buildDHFilters(semantic.SearchFilter{
			Filters: []semantic.FieldFilter{
				{Field: "fieldPaths", Values: []string{"email"}, Condition: "CONTAIN"},
				{Field: "tags", Values: []string{"urn:li:tag:deprecated"}, Negated: true},
			},
		})
		if len(filters) != 2 {
			t.Fatalf("expected 2 filters, got %d", len(filters))
		}
		if filters[0].Condition != "CONTAIN" {
			t.Errorf("expected CONTAIN condition, got %q", filters[0].Condition)
		}
		if !filters[1].Negated {
			t.Error("expected second filter to be negated")
		}
	})

	t.Run("legacy and explicit filters combined", func(t *testing.T) {
		filters := buildDHFilters(semantic.SearchFilter{
			Platform: "urn:li:dataPlatform:trino",
			Filters: []semantic.FieldFilter{
				{Field: "fieldPaths", Values: []string{"customer_id"}},
			},
		})
		if len(filters) != 2 {
			t.Fatalf("expected 2 filters, got %d", len(filters))
		}
	})
}

func TestAdapterCloseError(t *testing.T) {
	mock := &mockDataHubClient{
		closeFunc: func() error {
			return errors.New("close failed")
		},
	}
	adapter, _ := NewWithClient(Config{}, mock)

	err := adapter.Close()
	if err == nil {
		t.Error(dhAdapterTestExpectedErr)
	}
}

func TestResolveURNEdgeCases(t *testing.T) {
	mock := &mockDataHubClient{}
	adapter, _ := NewWithClient(Config{}, mock)
	ctx := context.Background()

	t.Run("single part table name is invalid", func(t *testing.T) {
		_, err := adapter.ResolveURN(ctx, "urn:li:dataset:(urn:li:dataPlatform:trino,table,PROD)")
		if err == nil {
			t.Error("expected error for single part table name")
		}
	})

	t.Run("empty path in URN", func(t *testing.T) {
		_, err := adapter.ResolveURN(ctx, "urn:li:dataset:(urn:li:dataPlatform:trino,,PROD)")
		if err == nil {
			t.Error("expected error for empty path")
		}
	})
}

func TestFieldToColumnContextEdgeCases(t *testing.T) {
	ctx := context.Background()

	mock := &mockDataHubClient{
		getSchemaFunc: func(_ context.Context, _ string) (*types.SchemaMetadata, error) {
			return &types.SchemaMetadata{
				Fields: []types.SchemaField{
					{
						FieldPath:   "pii_field",
						Description: "Sensitive data",
						Tags:        []types.Tag{{Name: "pii"}},
						NativeType:  "VARCHAR",
					},
				},
			}, nil
		},
	}
	adapter, _ := NewWithClient(Config{Platform: dhAdapterTestPlatformTrino}, mock)

	result, err := adapter.GetColumnContext(ctx, semantic.ColumnIdentifier{
		TableIdentifier: semantic.TableIdentifier{Schema: "schema", Table: "table"},
		Column:          "pii_field",
	})
	if err != nil {
		t.Fatalf(dhAdapterTestUnexpectedErr, err)
	}

	if !result.IsPII {
		t.Error("expected IsPII to be true for pii tag")
	}
}

func TestGetCuratedQueryCount(t *testing.T) {
	ctx := context.Background()

	t.Run("returns count from client", func(t *testing.T) {
		mock := &mockDataHubClient{
			getQueriesFunc: func(_ context.Context, _ string) (*types.QueryList, error) {
				return &types.QueryList{
					Total:   3,
					Queries: []types.Query{{URN: "q1"}, {URN: "q2"}, {URN: "q3"}},
				}, nil
			},
		}
		adapter, _ := NewWithClient(Config{}, mock)

		count, err := adapter.GetCuratedQueryCount(ctx, "urn:li:dataset:1")
		if err != nil {
			t.Fatalf(dhAdapterTestUnexpectedErr, err)
		}
		if count != 3 {
			t.Errorf("expected count 3, got %d", count)
		}
	})

	t.Run("returns zero for empty queries", func(t *testing.T) {
		mock := &mockDataHubClient{
			getQueriesFunc: func(_ context.Context, _ string) (*types.QueryList, error) {
				return &types.QueryList{Total: 0}, nil
			},
		}
		adapter, _ := NewWithClient(Config{}, mock)

		count, err := adapter.GetCuratedQueryCount(ctx, "urn:li:dataset:1")
		if err != nil {
			t.Fatalf(dhAdapterTestUnexpectedErr, err)
		}
		if count != 0 {
			t.Errorf("expected count 0, got %d", count)
		}
	})

	t.Run("returns error on client failure", func(t *testing.T) {
		mock := &mockDataHubClient{
			getQueriesFunc: func(_ context.Context, _ string) (*types.QueryList, error) {
				return nil, errors.New("client error")
			},
		}
		adapter, _ := NewWithClient(Config{}, mock)

		_, err := adapter.GetCuratedQueryCount(ctx, "urn:li:dataset:1")
		if err == nil {
			t.Error(dhAdapterTestExpectedErr)
		}
	})
}

func TestConvertStructuredProperties(t *testing.T) {
	t.Run("nil input", func(t *testing.T) {
		result := convertStructuredProperties(nil)
		if result != nil {
			t.Errorf("expected nil, got %v", result)
		}
	})

	t.Run("empty input", func(t *testing.T) {
		result := convertStructuredProperties([]types.StructuredPropertyValue{})
		if result != nil {
			t.Errorf("expected nil, got %v", result)
		}
	})

	t.Run("with definition", func(t *testing.T) {
		input := []types.StructuredPropertyValue{
			{
				PropertyURN: "urn:li:structuredProperty:io.acryl.privacy.retentionTime",
				Definition: &types.StructuredPropertyDefinition{
					QualifiedName: "io.acryl.privacy.retentionTime",
					DisplayName:   "Retention Time",
					ValueType:     "NUMBER",
				},
				Values: []any{float64(90)},
			},
		}
		result := convertStructuredProperties(input)
		if len(result) != 1 {
			t.Fatalf("expected 1 property, got %d", len(result))
		}
		if result[0].QualifiedName != "io.acryl.privacy.retentionTime" {
			t.Errorf("QualifiedName = %q, want %q", result[0].QualifiedName, "io.acryl.privacy.retentionTime")
		}
		if result[0].DisplayName != "Retention Time" {
			t.Errorf("DisplayName = %q, want %q", result[0].DisplayName, "Retention Time")
		}
		if len(result[0].Values) != 1 {
			t.Errorf("Values len = %d, want 1", len(result[0].Values))
		}
	})

	t.Run("without definition", func(t *testing.T) {
		input := []types.StructuredPropertyValue{
			{
				PropertyURN: "urn:li:structuredProperty:foo",
				Values:      []any{"bar"},
			},
		}
		result := convertStructuredProperties(input)
		if len(result) != 1 {
			t.Fatalf("expected 1 property, got %d", len(result))
		}
		if result[0].QualifiedName != "" {
			t.Errorf("expected empty QualifiedName, got %q", result[0].QualifiedName)
		}
	})
}

func TestConvertIncidents(t *testing.T) {
	t.Run("nil input", func(t *testing.T) {
		count, incidents := convertIncidents(nil)
		if count != 0 || incidents != nil {
			t.Errorf("expected 0/nil, got %d/%v", count, incidents)
		}
	})

	t.Run("zero total", func(t *testing.T) {
		count, incidents := convertIncidents(&types.IncidentResult{Total: 0})
		if count != 0 || incidents != nil {
			t.Errorf("expected 0/nil, got %d/%v", count, incidents)
		}
	})

	t.Run("with incidents", func(t *testing.T) {
		input := &types.IncidentResult{
			Total: 2,
			Incidents: []types.Incident{
				{
					URN:         "urn:li:incident:abc",
					Type:        "OPERATIONAL",
					Title:       "Pipeline down",
					Description: "ETL failed",
					State:       "ACTIVE",
					Created:     dhAdapterTestTimestampMs,
				},
				{
					URN:   "urn:li:incident:def",
					Type:  "CUSTOM",
					Title: "Schema drift",
					State: "ACTIVE",
				},
			},
		}
		count, incidents := convertIncidents(input)
		if count != 2 {
			t.Errorf("count = %d, want 2", count)
		}
		if len(incidents) != 2 {
			t.Fatalf("incidents len = %d, want 2", len(incidents))
		}
		if incidents[0].URN != "urn:li:incident:abc" {
			t.Errorf("incident[0].URN = %q", incidents[0].URN)
		}
		if incidents[0].Title != "Pipeline down" {
			t.Errorf("incident[0].Title = %q", incidents[0].Title)
		}
		if incidents[0].Created != dhAdapterTestTimestampMs {
			t.Errorf("incident[0].Created = %d, want %d", incidents[0].Created, dhAdapterTestTimestampMs)
		}
		if incidents[1].Type != "CUSTOM" {
			t.Errorf("incident[1].Type = %q", incidents[1].Type)
		}
	})
}

func TestConvertDataContract(t *testing.T) {
	t.Run("nil input", func(t *testing.T) {
		result := convertDataContract(nil)
		if result != nil {
			t.Errorf("expected nil, got %v", result)
		}
	})

	t.Run("passing contract", func(t *testing.T) {
		input := &types.DataContract{
			Status: "PASSING",
			AssertionResults: []types.AssertionResult{
				{AssertionURN: "urn:li:assertion:freshness-1", Type: "FRESHNESS"},
				{AssertionURN: "urn:li:assertion:schema-1", Type: "SCHEMA"},
			},
		}
		result := convertDataContract(input)
		if result == nil {
			t.Fatal("expected non-nil result")
		}
		if result.Status != "PASSING" {
			t.Errorf("Status = %q, want PASSING", result.Status)
		}
		if len(result.AssertionResults) != 2 {
			t.Fatalf("AssertionResults len = %d, want 2", len(result.AssertionResults))
		}
		if result.AssertionResults[0].Type != "FRESHNESS" {
			t.Errorf("AssertionResults[0].Type = %q", result.AssertionResults[0].Type)
		}
	})

	t.Run("no assertions", func(t *testing.T) {
		input := &types.DataContract{Status: "FAILING"}
		result := convertDataContract(input)
		if result == nil {
			t.Fatal("expected non-nil result")
		}
		if result.Status != "FAILING" {
			t.Errorf("Status = %q, want FAILING", result.Status)
		}
		if len(result.AssertionResults) != 0 {
			t.Errorf("expected empty assertions, got %d", len(result.AssertionResults))
		}
	})
}

func TestGetTableContext_WithV14Fields(t *testing.T) {
	ctx := context.Background()
	mock := &mockDataHubClient{
		getEntityFunc: func(_ context.Context, _ string) (*types.Entity, error) {
			return &types.Entity{
				URN:         "urn:li:dataset:test",
				Description: "test table",
				StructuredProperties: []types.StructuredPropertyValue{
					{
						PropertyURN: "urn:li:structuredProperty:retention",
						Definition: &types.StructuredPropertyDefinition{
							QualifiedName: "retention",
							DisplayName:   "Retention Days",
						},
						Values: []any{float64(90)},
					},
				},
				ActiveIncidents: &types.IncidentResult{
					Total: 1,
					Incidents: []types.Incident{
						{URN: "urn:li:incident:1", Type: "OPERATIONAL", Title: "Down", State: "ACTIVE"},
					},
				},
				DataContract: &types.DataContract{
					Status: "PASSING",
					AssertionResults: []types.AssertionResult{
						{AssertionURN: "urn:li:assertion:freshness-1", Type: "FRESHNESS"},
					},
				},
			}, nil
		},
	}

	adapter, _ := NewWithClient(Config{}, mock)
	tc, err := adapter.GetTableContext(ctx, semantic.TableIdentifier{Schema: "public", Table: "users"})
	if err != nil {
		t.Fatalf(dhAdapterTestUnexpectedErr, err)
	}

	// Structured properties
	if len(tc.StructuredProperties) != 1 {
		t.Fatalf("StructuredProperties len = %d, want 1", len(tc.StructuredProperties))
	}
	if tc.StructuredProperties[0].QualifiedName != "retention" {
		t.Errorf("StructuredProperties[0].QualifiedName = %q", tc.StructuredProperties[0].QualifiedName)
	}

	// Incidents
	if tc.ActiveIncidents != 1 {
		t.Errorf("ActiveIncidents = %d, want 1", tc.ActiveIncidents)
	}
	if len(tc.Incidents) != 1 {
		t.Fatalf("Incidents len = %d, want 1", len(tc.Incidents))
	}
	if tc.Incidents[0].Title != "Down" {
		t.Errorf("Incidents[0].Title = %q", tc.Incidents[0].Title)
	}

	// Data contract
	if tc.DataContract == nil {
		t.Fatal("DataContract is nil")
	}
	if tc.DataContract.Status != "PASSING" {
		t.Errorf("DataContract.Status = %q", tc.DataContract.Status)
	}
}

func TestGetTableContext_V13Compat(t *testing.T) {
	ctx := context.Background()
	mock := &mockDataHubClient{
		getEntityFunc: func(_ context.Context, _ string) (*types.Entity, error) {
			return &types.Entity{
				URN:         "urn:li:dataset:test",
				Description: "legacy table",
				// No v1.4 fields — simulates DataHub 1.3.x
			}, nil
		},
	}

	adapter, _ := NewWithClient(Config{}, mock)
	tc, err := adapter.GetTableContext(ctx, semantic.TableIdentifier{Schema: "public", Table: "users"})
	if err != nil {
		t.Fatalf(dhAdapterTestUnexpectedErr, err)
	}

	if len(tc.StructuredProperties) != 0 {
		t.Errorf("expected no structured properties, got %d", len(tc.StructuredProperties))
	}
	if tc.ActiveIncidents != 0 {
		t.Errorf("expected 0 active incidents, got %d", tc.ActiveIncidents)
	}
	if tc.DataContract != nil {
		t.Errorf("expected nil data contract, got %v", tc.DataContract)
	}
}

// Verify Adapter implements interfaces.
var (
	_ semantic.Provider    = (*Adapter)(nil)
	_ semantic.URNResolver = (*Adapter)(nil)
)
