package rest

import (
	"testing"

	"github.com/gin-gonic/gin"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/models"
	"github.com/stretchr/testify/assert"
)

// ---------------------------------------------------------------------------
// defToSFMetadata — ReportDefinition to Salesforce wire format
// ---------------------------------------------------------------------------

func TestDefToSFMetadata_Basic(t *testing.T) {
	def := &models.ReportDefinition{
		ID:           "rpt-001",
		Name:         "Sales Report",
		ReportFormat: "TABULAR",
		ReportType:   "AccountReport",
		SourceObject: "Account",
	}

	result := defToSFMetadata(def)

	assert.Equal(t, "rpt-001", result["id"])
	assert.Equal(t, "Sales Report", result["name"])
	assert.Equal(t, "TABULAR", result["reportFormat"])
	assert.Equal(t, "Account", result["sourceObject"])

	reportType, ok := result["reportType"].(gin.H)
	assert.True(t, ok)
	assert.Equal(t, "AccountReport", reportType["type"])
	assert.Equal(t, "Account", reportType["label"])
}

func TestDefToSFMetadata_WithColumns(t *testing.T) {
	def := &models.ReportDefinition{
		ID:           "rpt-002",
		Name:         "Col Report",
		ReportFormat: "TABULAR",
		ReportType:   "AccountReport",
		Columns:      []string{"Name", "Phone", "Email"},
	}

	result := defToSFMetadata(def)

	cols, ok := result["detailColumns"]
	assert.True(t, ok)
	assert.Equal(t, []string{"Name", "Phone", "Email"}, cols)
}

func TestDefToSFMetadata_WithFilters(t *testing.T) {
	def := &models.ReportDefinition{
		ID:           "rpt-003",
		Name:         "Filtered Report",
		ReportFormat: "TABULAR",
		ReportType:   "AccountReport",
		Filters: []models.ReportFilter{
			{Column: "Status", Operator: "equals", Value: "Active"},
		},
	}

	result := defToSFMetadata(def)

	_, hasFilters := result["reportFilters"]
	assert.True(t, hasFilters)
}

func TestDefToSFMetadata_WithGrouping(t *testing.T) {
	def := &models.ReportDefinition{
		ID:           "rpt-004",
		Name:         "Grouped Report",
		ReportFormat: "SUMMARY",
		ReportType:   "AccountReport",
		Grouping:     []string{"Industry", "Type"},
	}

	result := defToSFMetadata(def)

	groups, ok := result["groupingsDown"]
	assert.True(t, ok)
	groupSlice := groups.([]gin.H)
	assert.Len(t, groupSlice, 2)
	assert.Equal(t, "Industry", groupSlice[0]["name"])
	assert.Equal(t, "Asc", groupSlice[0]["sortOrder"])
}

func TestDefToSFMetadata_NoSourceObject(t *testing.T) {
	def := &models.ReportDefinition{
		ID:           "rpt-005",
		Name:         "Minimal",
		ReportFormat: "TABULAR",
		ReportType:   "Custom",
	}

	result := defToSFMetadata(def)

	_, hasSource := result["sourceObject"]
	assert.False(t, hasSource, "Empty source object should not be included")
}

// ---------------------------------------------------------------------------
// toReportResponse — SObject to wire format
// ---------------------------------------------------------------------------

func TestToReportResponse_Full(t *testing.T) {
	record := models.SObject{
		"Id":            "rpt-001",
		"Name":          "Pipeline Report",
		"DeveloperName": "Pipeline_Report",
		"FolderId":      "folder-001",
		"Description":   "Shows pipeline data",
		"ReportType":    "OpportunityReport",
		"SourceObject":  "Opportunity",
	}

	resp := toReportResponse(record)

	assert.Equal(t, "rpt-001", resp.ID)
	assert.Equal(t, "Pipeline Report", resp.Name)
	assert.Equal(t, "Pipeline_Report", resp.DeveloperName)
	assert.Equal(t, "folder-001", resp.FolderID)
	assert.Equal(t, "Shows pipeline data", resp.Description)
	assert.Equal(t, "OpportunityReport", resp.ReportType)
	assert.Equal(t, "Opportunity", resp.SourceObject)
}

func TestToReportResponse_Empty(t *testing.T) {
	resp := toReportResponse(models.SObject{})
	assert.Equal(t, "", resp.ID)
	assert.Equal(t, "", resp.Name)
}

// ---------------------------------------------------------------------------
// toDashboardResponse — SObject to wire format
// ---------------------------------------------------------------------------

func TestToDashboardResponse_Full(t *testing.T) {
	record := models.SObject{
		"Id":            "dash-001",
		"Name":          "Sales Dashboard",
		"DeveloperName": "Sales_Dashboard",
		"FolderId":      "folder-002",
		"Description":   "Overview of sales",
		"LayoutType":    "FixedLayout",
	}

	resp := toDashboardResponse(record)

	assert.Equal(t, "dash-001", resp.ID)
	assert.Equal(t, "Sales Dashboard", resp.Name)
	assert.Equal(t, "Sales_Dashboard", resp.DeveloperName)
	assert.Equal(t, "folder-002", resp.FolderID)
	assert.Equal(t, "Overview of sales", resp.Description)
	assert.Equal(t, "FixedLayout", resp.LayoutType)
}

func TestToDashboardResponse_Empty(t *testing.T) {
	resp := toDashboardResponse(models.SObject{})
	assert.Equal(t, "", resp.ID)
	assert.Equal(t, "", resp.Name)
}

// ---------------------------------------------------------------------------
// extractReportType — helper
// ---------------------------------------------------------------------------

func TestExtractReportType_StringValue(t *testing.T) {
	rt := extractReportType("AccountReport")
	assert.Equal(t, "AccountReport", rt)
}

func TestExtractReportType_MapValue(t *testing.T) {
	rt := extractReportType(map[string]interface{}{"type": "OpportunityReport"})
	assert.Equal(t, "OpportunityReport", rt)
}

func TestExtractReportType_MapWithoutType(t *testing.T) {
	rt := extractReportType(map[string]interface{}{"label": "some label"})
	assert.Equal(t, "", rt)
}

func TestExtractReportType_NilValue(t *testing.T) {
	rt := extractReportType(nil)
	assert.Equal(t, "", rt)
}

func TestExtractReportType_IntValue(t *testing.T) {
	rt := extractReportType(42)
	assert.Equal(t, "", rt)
}

// ---------------------------------------------------------------------------
// toSalesforceReportResult — internal → Salesforce wire format
// ---------------------------------------------------------------------------

func TestToSalesforceReportResult_Tabular(t *testing.T) {
	result := &models.ReportResult{
		ReportMetadata: models.ReportDefinition{
			ID:           "rpt-1",
			Name:         "Opp Report",
			SourceObject: "Opportunity",
			ReportType:   "tabular",
			ReportFormat: "Tabular",
			Columns:      []string{"Name", "Amount"},
		},
		Rows: []models.SObject{
			{"Name": "Deal 1", "Amount": "50000"},
			{"Name": "Deal 2", "Amount": "75000"},
		},
	}

	sf := toSalesforceReportResult(result, nil)

	meta, ok := sf["reportMetadata"].(gin.H)
	assert.True(t, ok)
	assert.Equal(t, "TABULAR", meta["reportFormat"])
	assert.Equal(t, []string{"Name", "Amount"}, meta["detailColumns"])

	aggKeys, ok := meta["aggregates"].([]string)
	assert.True(t, ok)
	assert.Contains(t, aggKeys, "RowCount")

	extMeta, ok := meta["reportExtendedMetadata"].(gin.H)
	assert.True(t, ok)
	dci, ok := extMeta["detailColumnInfo"].(gin.H)
	assert.True(t, ok)
	assert.Contains(t, dci, "Name")
	assert.Contains(t, dci, "Amount")
	gci, ok := extMeta["groupingColumnInfo"].(gin.H)
	assert.True(t, ok)
	assert.Empty(t, gci)

	factMap, ok := sf["factMap"].(gin.H)
	assert.True(t, ok)
	tt, ok := factMap["T!T"].(gin.H)
	assert.True(t, ok)
	rows, ok := tt["rows"].([]gin.H)
	assert.True(t, ok)
	assert.Len(t, rows, 2)

	cells := rows[0]["dataCells"].([]gin.H)
	assert.Len(t, cells, 2)
	assert.Equal(t, "Deal 1", cells[0]["label"])
	assert.Equal(t, "50000", cells[1]["label"])

	aggs := tt["aggregates"].([]gin.H)
	assert.Len(t, aggs, 1)
	assert.Equal(t, 2, aggs[0]["value"])

	assert.Equal(t, true, sf["hasDetailRows"])

	gd, ok := sf["groupingsDown"].(gin.H)
	assert.True(t, ok)
	groupings := gd["groupings"].([]gin.H)
	assert.Empty(t, groupings)
}

func TestToSalesforceReportResult_Summary(t *testing.T) {
	result := &models.ReportResult{
		ReportMetadata: models.ReportDefinition{
			ID:           "rpt-2",
			Name:         "Pipeline Summary",
			SourceObject: "Opportunity",
			ReportType:   "tabular",
			ReportFormat: "Summary",
			Grouping:     []string{"StageName"},
			Aggregates:   []models.ReportAggregate{{Field: "Amount", Type: "SUM"}},
		},
		Rows: []models.SObject{
			{"name": "Closed Won", "val": 100000.0},
			{"name": "Prospecting", "val": 25000.0},
		},
	}

	sf := toSalesforceReportResult(result, nil)

	meta := sf["reportMetadata"].(gin.H)
	assert.Equal(t, "SUMMARY", meta["reportFormat"])

	factMap := sf["factMap"].(gin.H)
	assert.Contains(t, factMap, "0!T")
	assert.Contains(t, factMap, "1!T")
	assert.Contains(t, factMap, "T!T")

	group0 := factMap["0!T"].(gin.H)
	aggs0 := group0["aggregates"].([]gin.H)
	assert.Equal(t, 100000.0, aggs0[0]["value"])

	group1 := factMap["1!T"].(gin.H)
	aggs1 := group1["aggregates"].([]gin.H)
	assert.Equal(t, 25000.0, aggs1[0]["value"])

	gd := sf["groupingsDown"].(gin.H)
	groupings := gd["groupings"].([]gin.H)
	assert.Len(t, groupings, 2)
	assert.Equal(t, "Closed Won", groupings[0]["label"])
	assert.Equal(t, "0", groupings[0]["key"])

	assert.Equal(t, false, sf["hasDetailRows"])
}

func TestToSalesforceReportResult_EmptyRows(t *testing.T) {
	result := &models.ReportResult{
		ReportMetadata: models.ReportDefinition{
			ID:           "rpt-3",
			Name:         "Empty Report",
			SourceObject: "Contact",
			ReportType:   "tabular",
			ReportFormat: "TABULAR",
			Columns:      []string{"Name"},
		},
		Rows: []models.SObject{},
	}

	sf := toSalesforceReportResult(result, nil)

	factMap := sf["factMap"].(gin.H)
	tt := factMap["T!T"].(gin.H)
	rows := tt["rows"].([]gin.H)
	assert.Empty(t, rows)
	assert.Equal(t, false, sf["hasDetailRows"])
}

// Wave-3 wire-format check: CRT degradation warnings must surface under
// reportExtendedMetadata.warnings when present, and must be omitted when
// the warnings slice is empty. See design §4.11.
func TestToSalesforceReportResult_CRTWarningsSurfaced(t *testing.T) {
	t.Run("populated warnings land on reportExtendedMetadata", func(t *testing.T) {
		result := &models.ReportResult{
			ReportMetadata: models.ReportDefinition{
				ID:           "rpt-warn",
				Name:         "Degraded CRT",
				SourceObject: "CustomEntityCustomEntity$A__c$B__c",
				ReportType:   "tabular",
				ReportFormat: "TABULAR",
				Columns:      []string{"Name"},
			},
			Rows: []models.SObject{{"Name": "a"}},
			Warnings: []models.CRTWarning{
				{Code: "crt_nested_unsupported", Message: "nested rendered as A__c"},
				{Code: "crt_column_unresolved", Message: "Foo dropped"},
			},
		}
		sf := toSalesforceReportResult(result, nil)
		meta := sf["reportMetadata"].(gin.H)
		ext := meta["reportExtendedMetadata"].(gin.H)
		warns, ok := ext["warnings"].([]models.CRTWarning)
		if assert.True(t, ok, "warnings should be present as []CRTWarning") {
			assert.Len(t, warns, 2)
			assert.Equal(t, models.CRTWarningCode("crt_nested_unsupported"), warns[0].Code)
			assert.Equal(t, models.CRTWarningCode("crt_column_unresolved"), warns[1].Code)
		}
	})

	t.Run("empty warnings slice omits the field", func(t *testing.T) {
		result := &models.ReportResult{
			ReportMetadata: models.ReportDefinition{
				ID:           "rpt-clean",
				Name:         "Clean",
				SourceObject: "Opportunity",
				ReportType:   "tabular",
				ReportFormat: "TABULAR",
				Columns:      []string{"Name"},
			},
			Rows:     []models.SObject{{"Name": "a"}},
			Warnings: nil,
		}
		sf := toSalesforceReportResult(result, nil)
		meta := sf["reportMetadata"].(gin.H)
		ext := meta["reportExtendedMetadata"].(gin.H)
		_, present := ext["warnings"]
		assert.False(t, present, "warnings key must be absent when slice is empty")
	})
}

func TestToSalesforceReportResult_NoColumnsInferredFromRows(t *testing.T) {
	result := &models.ReportResult{
		ReportMetadata: models.ReportDefinition{
			ID:           "rpt-4",
			Name:         "No Columns",
			SourceObject: "Account",
			ReportType:   "tabular",
			ReportFormat: "TABULAR",
		},
		Rows: []models.SObject{
			{"Id": "001", "Name": "Acme"},
		},
	}

	sf := toSalesforceReportResult(result, nil)

	meta := sf["reportMetadata"].(gin.H)
	cols := meta["detailColumns"].([]string)
	assert.Contains(t, cols, "Id")
	assert.Contains(t, cols, "Name")
}

func TestToSalesforceReportResult_ColumnAliasResolution(t *testing.T) {
	result := &models.ReportResult{
		ReportMetadata: models.ReportDefinition{
			ID:           "rpt-5",
			Name:         "Alias Test",
			SourceObject: "Opportunity",
			ReportType:   "tabular",
			ReportFormat: "TABULAR",
			Columns:      []string{"OPPORTUNITY_NAME", "Amount", "CREATED_DATE"},
		},
		Rows: []models.SObject{
			{"Name": "Deal 1", "Amount": "50000", "CreatedDate": "2025-01-15"},
		},
	}

	sf := toSalesforceReportResult(result, nil)

	factMap := sf["factMap"].(gin.H)
	tt := factMap["T!T"].(gin.H)
	rows := tt["rows"].([]gin.H)
	cells := rows[0]["dataCells"].([]gin.H)

	assert.Equal(t, "Deal 1", cells[0]["label"])
	assert.Equal(t, "50000", cells[1]["label"])
	assert.Equal(t, "2025-01-15", cells[2]["label"])
}

func TestToSalesforceReportResult_ContractOrderJoinAliases(t *testing.T) {
	result := &models.ReportResult{
		ReportMetadata: models.ReportDefinition{
			ID:           "rpt-6",
			Name:         "Contracts & Orders",
			SourceObject: "ContractOrder",
			ReportType:   "ContractOrderList",
			ReportFormat: "SUMMARY",
			Columns: []string{
				"RECORDTYPE",
				"ACCOUNT_OWNER",
				"ORDER_STATUS",
				"Order.Product_Family__c",
				"Order.TCV_Amount__c",
				"Order.ACV_Amount__c",
				"Order.Net_Fees__c",
			},
			Grouping:   []string{"ACCOUNT_NAME", "ORDER_EFFECTIVE_DATE"},
			Aggregates: []models.ReportAggregate{{Field: "Order.TCV_Amount__c", Type: "SUM"}},
		},
		Rows: []models.SObject{
			{
				"AccountId_Name":         "Acme Corp",
				"OrderEffectiveDate":     "2026-04-01",
				"RecordTypeId_Name":      "TiDB Cloud Services Agreement Online",
				"AccountId_OwnerId_Name": "Alice Admin",
				"OrderStatus":            "Activated",
				"Product_Family__c":      "Database",
				"TCV_Amount__c":          1000.0,
				"ACV_Amount__c":          400.0,
				"Net_Fees__c":            125.0,
			},
			{
				"AccountId_Name":         "Acme Corp",
				"OrderEffectiveDate":     "2026-04-15",
				"RecordTypeId_Name":      "Expansion",
				"AccountId_OwnerId_Name": "Alice Admin",
				"OrderStatus":            "Pending",
				"Product_Family__c":      "AI",
				"TCV_Amount__c":          500.0,
				"ACV_Amount__c":          250.0,
				"Net_Fees__c":            75.0,
			},
			{
				"AccountId_Name":         "Globex Inc",
				"OrderEffectiveDate":     "2026-05-01",
				"RecordTypeId_Name":      "New",
				"AccountId_OwnerId_Name": "Bob Builder",
				"OrderStatus":            "Activated",
				"Product_Family__c":      "Observability",
				"TCV_Amount__c":          800.0,
				"ACV_Amount__c":          350.0,
				"Net_Fees__c":            90.0,
			},
		},
	}

	sf := toSalesforceReportResult(result, nil)

	meta := sf["reportMetadata"].(gin.H)
	assert.Equal(t, []string{
		"RECORDTYPE",
		"ACCOUNT_OWNER",
		"ORDER_STATUS",
		"Order.Product_Family__c",
		"Order.TCV_Amount__c",
		"Order.ACV_Amount__c",
		"Order.Net_Fees__c",
	}, meta["detailColumns"])
	extMeta := meta["reportExtendedMetadata"].(gin.H)
	groupingInfo := extMeta["groupingColumnInfo"].(gin.H)
	assert.Equal(t, "Account Name", groupingInfo["ACCOUNT_NAME"].(gin.H)["label"])
	assert.Equal(t, "Order Effective Date", groupingInfo["ORDER_EFFECTIVE_DATE"].(gin.H)["label"])

	gd := sf["groupingsDown"].(gin.H)
	groupings := gd["groupings"].([]gin.H)
	assert.Len(t, groupings, 2)
	assert.Equal(t, "Acme Corp (2)", groupings[0]["label"])
	assert.Equal(t, "Globex Inc (1)", groupings[1]["label"])

	acmeChildren := groupings[0]["groupings"].([]gin.H)
	assert.Len(t, acmeChildren, 2)
	assert.Equal(t, "0_0", acmeChildren[0]["key"])
	assert.Equal(t, "2026-04-01 (1)", acmeChildren[0]["label"])
	assert.Equal(t, "0_1", acmeChildren[1]["key"])
	assert.Equal(t, "2026-04-15 (1)", acmeChildren[1]["label"])

	factMap := sf["factMap"].(gin.H)
	grandTotal := factMap["T!T"].(gin.H)
	grandAggs := grandTotal["aggregates"].([]gin.H)
	assert.Equal(t, 3, grandAggs[0]["value"])
	assert.Equal(t, 2300.0, grandAggs[1]["value"])

	accountSubtotal := factMap["0!T"].(gin.H)
	accountSubtotalRows := accountSubtotal["rows"].([]gin.H)
	assert.Empty(t, accountSubtotalRows)
	accountAggs := accountSubtotal["aggregates"].([]gin.H)
	assert.Equal(t, 2, accountAggs[0]["value"])
	assert.Equal(t, 1500.0, accountAggs[1]["value"])

	firstLeaf := factMap["0_0!T"].(gin.H)
	rows := firstLeaf["rows"].([]gin.H)
	cells := rows[0]["dataCells"].([]gin.H)
	assert.Equal(t, "TiDB Cloud Services Agreement Online", cells[0]["label"])
	assert.Equal(t, "Alice Admin", cells[1]["label"])
	assert.Equal(t, "Activated", cells[2]["label"])
	assert.Equal(t, "Database", cells[3]["label"])
	assert.Equal(t, 1000.0, cells[4]["value"])
	assert.Equal(t, 400.0, cells[5]["value"])
	assert.Equal(t, 125.0, cells[6]["value"])

	secondLeafAggs := factMap["0_1!T"].(gin.H)["aggregates"].([]gin.H)
	assert.Equal(t, 1, secondLeafAggs[0]["value"])
	assert.Equal(t, 500.0, secondLeafAggs[1]["value"])

	globexLeaf := factMap["1_0!T"].(gin.H)
	globexRows := globexLeaf["rows"].([]gin.H)
	globexCells := globexRows[0]["dataCells"].([]gin.H)
	assert.Equal(t, "New", globexCells[0]["label"])
	assert.Equal(t, "Bob Builder", globexCells[1]["label"])
}

func TestBuildExtendedMetadata_GroupingColumnInfoUsesFriendlyLabels(t *testing.T) {
	ext := buildExtendedMetadata(
		[]string{"Name"},
		[]string{"Region__c", "ForecastQuarter__c"},
		[]models.ReportAggregate{{Field: "Amount", Type: "SUM"}},
		nil,
	)

	groupingInfo := ext["groupingColumnInfo"].(gin.H)
	assert.Equal(t, "Region", groupingInfo["Region__c"].(gin.H)["label"])
	assert.Equal(t, "Forecast Quarter", groupingInfo["ForecastQuarter__c"].(gin.H)["label"])
}

// ---------------------------------------------------------------------------
// helper function tests
// ---------------------------------------------------------------------------

func TestSfAggregateKey(t *testing.T) {
	assert.Equal(t, "RowCount", sfAggregateKey(models.ReportAggregate{Field: "", Type: "RowCount"}))
	assert.Equal(t, "s!Amount", sfAggregateKey(models.ReportAggregate{Field: "Amount", Type: "SUM"}))
	assert.Equal(t, "a!Amount", sfAggregateKey(models.ReportAggregate{Field: "Amount", Type: "AVG"}))
	assert.Equal(t, "mx!Amount", sfAggregateKey(models.ReportAggregate{Field: "Amount", Type: "MAX"}))
	assert.Equal(t, "mn!Amount", sfAggregateKey(models.ReportAggregate{Field: "Amount", Type: "MIN"}))
}

func TestBuildAggregateKeys_AlwaysIncludesRowCount(t *testing.T) {
	keys := buildAggregateKeys(nil)
	assert.Equal(t, []string{"RowCount"}, keys)

	keys = buildAggregateKeys([]models.ReportAggregate{{Field: "Amount", Type: "SUM"}})
	assert.Equal(t, []string{"RowCount", "s!Amount"}, keys)

	keys = buildAggregateKeys([]models.ReportAggregate{{Field: "", Type: "RowCount"}})
	assert.Equal(t, []string{"RowCount"}, keys)
}

func TestResolveColumnValue(t *testing.T) {
	row := models.SObject{"Name": "Test", "Amount": "100", "CreatedDate": "2025-01-01"}

	assert.Equal(t, "Test", resolveColumnValue(row, "Name", nil))
	assert.Equal(t, "Test", resolveColumnValue(row, "OPPORTUNITY_NAME", nil))
	assert.Equal(t, "2025-01-01", resolveColumnValue(row, "CREATED_DATE", nil))
	assert.Equal(t, "Test", resolveColumnValue(row, "name", nil))
	assert.Nil(t, resolveColumnValue(row, "NonExistent", nil))
}

func TestFormatNumber(t *testing.T) {
	assert.Equal(t, "100", formatNumber(100.0))
	assert.Equal(t, "100", formatNumber(100))
	assert.Equal(t, "99.99", formatNumber(99.99))
}

func TestLooksLikeAggregatedRows(t *testing.T) {
	assert.True(t, looksLikeAggregatedRows([]models.SObject{{"name": "A", "val": 1}}))
	assert.False(t, looksLikeAggregatedRows([]models.SObject{{"Name": "A", "Amount": 1}}))
	assert.False(t, looksLikeAggregatedRows(nil))
}

// ---------------------------------------------------------------------------
// Metadata-driven formatting tests
// ---------------------------------------------------------------------------

func testSchema() *models.ObjectMetadata {
	relName := "Account"
	return &models.ObjectMetadata{
		APIName: "Opportunity",
		FieldsMap: map[string]*models.FieldMetadata{
			"CloseDate":            {APIName: "CloseDate", Label: "Close Date", Type: constants.FieldTypeDatetime},
			"Amount":               {APIName: "Amount", Label: "Amount", Type: constants.FieldTypeCurrency},
			"Probability":          {APIName: "Probability", Label: "Probability (%)", Type: constants.FieldTypePercent},
			"StageName":            {APIName: "StageName", Label: "Stage", Type: constants.FieldTypePicklist},
			"Name":                 {APIName: "Name", Label: "Opportunity Name", Type: constants.FieldTypeString},
			"AccountId":            {APIName: "AccountId", Label: "Account ID", Type: constants.FieldTypeReference, ReferenceTo: []string{"Account"}, RelationshipName: &relName},
			"IsActive":             {APIName: "IsActive", Label: "Active", Type: constants.FieldTypeBoolean},
			"OwnerId":              {APIName: "OwnerId", Label: "Owner ID", Type: constants.FieldTypeReference},
			"LeadSource":           {APIName: "LeadSource", Label: "Lead Source", Type: constants.FieldTypePicklist},
			"ForecastCategoryName": {APIName: "ForecastCategoryName", Label: "Forecast Category", Type: constants.FieldTypeString},
			"CampaignId":           {APIName: "CampaignId", Label: "Campaign Source", Type: constants.FieldTypeReference, ReferenceTo: []string{"Campaign"}},
			"RecordTypeId":         {APIName: "RecordTypeId", Label: "Record Type ID", Type: constants.FieldTypeReference, ReferenceTo: []string{"RecordType"}},
		},
	}
}

func TestBuildExtendedMetadata_UsesFieldLabels(t *testing.T) {
	schema := testSchema()
	ext := buildExtendedMetadata(
		[]string{"CLOSE_DATE", "STAGE_NAME"},
		[]string{},
		[]models.ReportAggregate{},
		schema,
	)

	dci := ext["detailColumnInfo"].(gin.H)
	closeDateInfo := dci["CLOSE_DATE"].(gin.H)
	assert.Equal(t, "Close Date", closeDateInfo["label"])
	assert.Equal(t, "date", closeDateInfo["dataType"])

	stageInfo := dci["STAGE_NAME"].(gin.H)
	assert.Equal(t, "Stage", stageInfo["label"])
	assert.Equal(t, "string", stageInfo["dataType"])
}

func TestBuildExtendedMetadata_FallbackForUnknownColumns(t *testing.T) {
	schema := testSchema()
	ext := buildExtendedMetadata(
		[]string{"Opportunity.Product_Family__c"},
		[]string{},
		[]models.ReportAggregate{},
		schema,
	)

	dci := ext["detailColumnInfo"].(gin.H)
	info := dci["Opportunity.Product_Family__c"].(gin.H)
	assert.Equal(t, "Product Family", info["label"])
	assert.Equal(t, "string", info["dataType"])
}

func TestBuildExtendedMetadata_CorrectDataTypes(t *testing.T) {
	schema := testSchema()
	ext := buildExtendedMetadata(
		[]string{"CLOSE_DATE", "AMOUNT", "PROBABILITY", "IsActive", "AccountId"},
		[]string{},
		[]models.ReportAggregate{},
		schema,
	)

	dci := ext["detailColumnInfo"].(gin.H)
	assert.Equal(t, "date", dci["CLOSE_DATE"].(gin.H)["dataType"])
	assert.Equal(t, "currency", dci["AMOUNT"].(gin.H)["dataType"])
	assert.Equal(t, "percent", dci["PROBABILITY"].(gin.H)["dataType"])
	assert.Equal(t, "boolean", dci["IsActive"].(gin.H)["dataType"])
	assert.Equal(t, "string", dci["AccountId"].(gin.H)["dataType"]) // reference → string
}

func TestResolveColumnAlias_MetadataDriven(t *testing.T) {
	schema := testSchema()

	// Reference field → {FK}_Name
	assert.Equal(t, "AccountId_Name", resolveColumnAlias("ACCOUNT_NAME", schema))

	// Non-reference field → API name directly
	assert.Equal(t, "CloseDate", resolveColumnAlias("CLOSE_DATE", schema))
	assert.Equal(t, "StageName", resolveColumnAlias("STAGE_NAME", schema))
	assert.Equal(t, "Name", resolveColumnAlias("OPPORTUNITY_NAME", schema))

	// Owner is a reference field
	assert.Equal(t, "OwnerId_Name", resolveColumnAlias("OWNER", schema))

	// Unknown column → empty
	assert.Equal(t, "", resolveColumnAlias("NONEXISTENT", schema))
}

func TestResolveColumnAlias_CrossObject(t *testing.T) {
	schema := testSchema()

	// FULL_NAME → OwnerId_Name (owner display name, not record Name)
	assert.Equal(t, "OwnerId_Name", resolveColumnAlias("FULL_NAME", schema))

	// ACCOUNT_OWNER → AccountId_OwnerId_Name (nested FK)
	assert.Equal(t, "AccountId_OwnerId_Name", resolveColumnAlias("ACCOUNT_OWNER", schema))

	// CAMPAIGN_SOURCE → CampaignId_Name (via cross-object override)
	assert.Equal(t, "CampaignId_Name", resolveColumnAlias("CAMPAIGN_SOURCE", schema))

	// CAMPAIGN_SOURCE with nil schema still resolves (unconditional override)
	assert.Equal(t, "CampaignId_Name", resolveColumnAlias("CAMPAIGN_SOURCE", nil))

	// RECORD_TYPE and RECORDTYPE both resolve
	assert.Equal(t, "RecordTypeId_Name", resolveColumnAlias("RECORD_TYPE", schema))
	assert.Equal(t, "RecordTypeId_Name", resolveColumnAlias("RECORDTYPE", schema))
}

func TestResolveFieldLabel_CrossObject(t *testing.T) {
	schema := testSchema()

	// FULL_NAME → "Opportunity Owner" (not "Opportunity Name")
	assert.Equal(t, "Opportunity Owner", resolveFieldLabel("FULL_NAME", schema))

	// ACCOUNT_OWNER → "Account Owner"
	assert.Equal(t, "Account Owner", resolveFieldLabel("ACCOUNT_OWNER", schema))

	// CAMPAIGN_SOURCE → "Campaign Source"
	assert.Equal(t, "Campaign Source", resolveFieldLabel("CAMPAIGN_SOURCE", schema))

	// ACCOUNT_NAME → "Account Name" (not "Account ID")
	assert.Equal(t, "Account Name", resolveFieldLabel("ACCOUNT_NAME", schema))

	// OPP_ACCT_NAME → "Account Name" (not "Account ID")
	assert.Equal(t, "Account Name", resolveFieldLabel("OPP_ACCT_NAME", schema))

	// LEAD_OWNER → "Lead Owner" (not "Owner ID")
	assert.Equal(t, "Lead Owner", resolveFieldLabel("LEAD_OWNER", schema))
}

func TestResolveFieldLabel_MetadataDriven(t *testing.T) {
	schema := testSchema()

	assert.Equal(t, "Close Date", resolveFieldLabel("CLOSE_DATE", schema))
	assert.Equal(t, "Amount", resolveFieldLabel("AMOUNT", schema))
	assert.Equal(t, "Opportunity Name", resolveFieldLabel("OPPORTUNITY_NAME", schema))
	assert.Equal(t, "Lead Source", resolveFieldLabel("LEAD_SOURCE", schema))
	assert.Equal(t, "Forecast Category", resolveFieldLabel("FORECAST_CATEGORY", schema))

	// Fallback for unresolved columns
	assert.Equal(t, "Product Family", resolveFieldLabel("Opportunity.Product_Family__c", schema))
}

func TestResolveFieldDataType_MetadataDriven(t *testing.T) {
	schema := testSchema()

	assert.Equal(t, "date", resolveFieldDataType("CLOSE_DATE", schema))
	assert.Equal(t, "currency", resolveFieldDataType("AMOUNT", schema))
	assert.Equal(t, "percent", resolveFieldDataType("PROBABILITY", schema))
	assert.Equal(t, "boolean", resolveFieldDataType("IsActive", schema))
	assert.Equal(t, "string", resolveFieldDataType("STAGE_NAME", schema))

	// Nil schema → "string" default
	assert.Equal(t, "string", resolveFieldDataType("CLOSE_DATE", nil))
}

func TestResolveColumnValue_WithMetadata(t *testing.T) {
	schema := testSchema()
	row := models.SObject{
		"AccountId_Name": "Acme Corp",
		"Name":           "Deal 1",
		"CloseDate":      "2025-06-30",
		"OwnerId_Name":   "Alice Admin",
	}

	// Reference field resolves via metadata to _Name key
	assert.Equal(t, "Acme Corp", resolveColumnValue(row, "ACCOUNT_NAME", schema))
	assert.Equal(t, "Alice Admin", resolveColumnValue(row, "OWNER", schema))

	// Direct fields resolve to API name
	assert.Equal(t, "Deal 1", resolveColumnValue(row, "OPPORTUNITY_NAME", schema))
	assert.Equal(t, "2025-06-30", resolveColumnValue(row, "CLOSE_DATE", schema))
}

func TestResolveColumnValue_CrossObject(t *testing.T) {
	schema := testSchema()
	row := models.SObject{
		"Name":                    "Big Deal Q4",
		"OwnerId_Name":           "Alice Admin",
		"AccountId_OwnerId_Name": "Bob Manager",
		"CampaignId_Name":        "Spring Campaign",
		"RecordTypeId_Name":      "Enterprise",
	}

	// FULL_NAME → owner display name, not record name
	assert.Equal(t, "Alice Admin", resolveColumnValue(row, "FULL_NAME", schema))

	// ACCOUNT_OWNER → nested FK display name
	assert.Equal(t, "Bob Manager", resolveColumnValue(row, "ACCOUNT_OWNER", schema))

	// CAMPAIGN_SOURCE → campaign display name
	assert.Equal(t, "Spring Campaign", resolveColumnValue(row, "CAMPAIGN_SOURCE", schema))

	// CAMPAIGN_SOURCE with nil schema → still resolves via override
	assert.Equal(t, "Spring Campaign", resolveColumnValue(row, "CAMPAIGN_SOURCE", nil))

	// RECORD_TYPE → record type display name
	assert.Equal(t, "Enterprise", resolveColumnValue(row, "RECORD_TYPE", schema))
}
