package dialectsfcrm

import (
	"encoding/json"
	"strings"
	"testing"

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

func TestReportWireAdapterProjectsDescribeResponseEnvelope(t *testing.T) {
	adapter := NewReportWireAdapter()

	result := adapter.ProjectReportDescribeResponse(&models.ReportDefinition{
		ID:           "00Oxx0000000001AAA",
		Name:         "Pipeline",
		SourceObject: "Opportunity",
		SourceRef:    "OpportunityList",
		DisplayMode:  "TABULAR",
		Filters: []models.ReportFilter{
			{Column: "StageName", Operator: "equals", Value: "Prospecting"},
		},
		DateFilter: &models.ReportDateFilter{
			Column:        "CloseDate",
			DurationValue: "CUSTOM",
			StartDate:     "2026-01-01",
			EndDate:       "2026-01-31",
		},
	}, nil)

	body, err := json.Marshal(result)
	if err != nil {
		t.Fatalf("marshal describe response: %v", err)
	}
	jsonBody := string(body)
	for _, want := range []string{
		`"reportMetadata":{`,
		`"id":"00Oxx0000000001AAA"`,
		`"reportFilters":[{"column":"StageName","operator":"equals","value":"Prospecting"}]`,
		`"reportType":{"label":"Opportunity","type":"OpportunityList"}`,
		`"sourceObject":"Opportunity"`,
		`"standardDateFilter":{"column":"CloseDate","durationValue":"CUSTOM","startDate":"2026-01-01","endDate":"2026-01-31"}`,
	} {
		if !strings.Contains(jsonBody, want) {
			t.Fatalf("describe JSON = %s, missing %s", jsonBody, want)
		}
	}
}

func TestReportWireAdapterDerivesReportTypeFromSourceObjectForLegacyDisplayModeRows(t *testing.T) {
	adapter := NewReportWireAdapter()

	result := adapter.ProjectReportDescribeResponse(&models.ReportDefinition{
		ID:           "00Oxx0000000002AAA",
		Name:         "Legacy Pipeline",
		SourceObject: "Opportunity",
		DisplayMode:  "TABULAR",
	}, nil)

	body, err := json.Marshal(result)
	if err != nil {
		t.Fatalf("marshal describe response: %v", err)
	}
	jsonBody := string(body)
	if !strings.Contains(jsonBody, `"reportType":{"label":"Opportunity","type":"OpportunityList"}`) {
		t.Fatalf("describe JSON = %s, want reportType derived from SourceObject", jsonBody)
	}
}

func TestReportWireAdapterProjectsLegacyTokenShapedStoredSourceObject(t *testing.T) {
	dialect := NewReportDefinitionDialect()
	def, err := dialect.ParseStoredDefinition(contract.Record{
		"Id":           "00Oxx0000000005AAA",
		"Name":         "Legacy Pipeline",
		"SourceObject": "OpportunityReport",
		"ReportType":   "Tabular",
	})
	if err != nil {
		t.Fatalf("ParseStoredDefinition: %v", err)
	}

	result := NewReportWireAdapter().ProjectReportDescribeResponse(def, nil)
	body, err := json.Marshal(result)
	if err != nil {
		t.Fatalf("marshal describe response: %v", err)
	}
	jsonBody := string(body)
	for _, want := range []string{
		`"sourceObject":"Opportunity"`,
		`"reportType":{"label":"Opportunity","type":"OpportunityReport"}`,
	} {
		if !strings.Contains(jsonBody, want) {
			t.Fatalf("describe JSON = %s, missing %s", jsonBody, want)
		}
	}
	if strings.Contains(jsonBody, "OpportunityReportList") {
		t.Fatalf("describe JSON = %s, must not project token-shaped SourceObject as OpportunityReportList", jsonBody)
	}
}

func TestReportWireAdapterDerivesReportTypeWhenSourceRefMatchesSourceObject(t *testing.T) {
	adapter := NewReportWireAdapter()

	result := adapter.ProjectReportDescribeResponse(&models.ReportDefinition{
		ID:           "00Oxx0000000003AAA",
		Name:         "Neutral Pipeline",
		SourceObject: "Opportunity",
		SourceRef:    "Opportunity",
	}, nil)

	body, err := json.Marshal(result)
	if err != nil {
		t.Fatalf("marshal describe response: %v", err)
	}
	jsonBody := string(body)
	if !strings.Contains(jsonBody, `"reportType":{"label":"Opportunity","type":"OpportunityList"}`) {
		t.Fatalf("describe JSON = %s, want single-object neutral SourceRef projected as OpportunityList", jsonBody)
	}
}

func TestReportWireAdapterProjectsDisplayModeAsSalesforceReportFormat(t *testing.T) {
	adapter := NewReportWireAdapter()
	def := &models.ReportDefinition{
		ID:           "00Oxx0000000004AAA",
		Name:         "Lowercase Summary",
		SourceObject: "Opportunity",
		SourceRef:    "Opportunity",
		DisplayMode:  "summary",
	}

	metadata := adapter.ProjectReportMetadata(def, nil)
	metadataBody, err := json.Marshal(metadata)
	if err != nil {
		t.Fatalf("marshal metadata: %v", err)
	}
	if !strings.Contains(string(metadataBody), `"reportFormat":"SUMMARY"`) {
		t.Fatalf("metadata JSON = %s, want uppercase reportFormat", metadataBody)
	}

	describe := adapter.ProjectReportDescribeResponse(def, nil)
	describeBody, err := json.Marshal(describe)
	if err != nil {
		t.Fatalf("marshal describe response: %v", err)
	}
	if !strings.Contains(string(describeBody), `"reportFormat":"SUMMARY"`) {
		t.Fatalf("describe JSON = %s, want uppercase reportFormat", describeBody)
	}
}

func TestReportWireAdapterInferredColumnsSkipNeutralCarrierFields(t *testing.T) {
	adapter := NewReportWireAdapter()

	result := adapter.ProjectReportResult(&models.ReportResult{
		ReportMetadata: models.ReportDefinition{
			Name:         "Neutral Carrier Probe",
			SourceObject: "Account",
			DisplayMode:  "TABULAR",
		},
		Rows: []models.SObject{{
			models.ObjectTypeMetadataKey: "Account",
			"attributes":                 map[string]interface{}{"type": "Account"},
			"_metadata":                  map[string]interface{}{"internal": true},
			"Name":                       "Visible Account",
		}},
	}, nil)

	body, err := json.Marshal(result)
	if err != nil {
		t.Fatalf("marshal report result: %v", err)
	}
	jsonBody := string(body)
	for _, want := range []string{`"detailColumns":["Name"]`, `"label":"Visible Account"`, `"value":"Visible Account"`} {
		if !strings.Contains(jsonBody, want) {
			t.Fatalf("report JSON = %s, missing %s", jsonBody, want)
		}
	}
	for _, forbidden := range []string{models.ObjectTypeMetadataKey, "attributes", "_metadata", "internal"} {
		if strings.Contains(jsonBody, forbidden) {
			t.Fatalf("report JSON leaked %q from neutral row: %s", forbidden, jsonBody)
		}
	}
}

func TestReportWireAdapterProjectsDoubleFieldsAsDoubleDataType(t *testing.T) {
	adapter := NewReportWireAdapter()

	result := adapter.ProjectReportResult(&models.ReportResult{
		ReportMetadata: models.ReportDefinition{
			Name:         "Pipeline",
			SourceObject: "Opportunity",
			DisplayMode:  "TABULAR",
			Columns:      []string{"Amount"},
		},
		Rows: []models.SObject{{
			"Amount": float64(42.5),
		}},
	}, &models.ObjectMetadata{
		FieldsMap: map[string]*models.FieldMetadata{
			"Amount": {
				APIName: "Amount",
				Label:   "Amount",
				Type:    constants.FieldTypeDouble,
			},
		},
	})

	body, err := json.Marshal(result)
	if err != nil {
		t.Fatalf("marshal report result: %v", err)
	}
	jsonBody := string(body)
	if !strings.Contains(jsonBody, `"Amount":{"dataType":"double","label":"Amount"}`) {
		t.Fatalf("report JSON = %s, want Amount dataType double", jsonBody)
	}
	if strings.Contains(jsonBody, `"Amount":{"dataType":"int","label":"Amount"}`) {
		t.Fatalf("report JSON = %s, must not label double field as int", jsonBody)
	}
}

func TestReportWireAdapterProjectsSummaryEnvelope(t *testing.T) {
	adapter := NewReportWireAdapter()

	result := adapter.ProjectReportResult(&models.ReportResult{
		ReportMetadata: models.ReportDefinition{
			Name:         "Work By Status",
			SourceObject: "Issue",
			DisplayMode:  "SUMMARY",
			Grouping:     []string{"Status"},
			Aggregates:   []models.ReportAggregate{{Field: "Points", Type: "SUM"}},
		},
		Rows: []models.SObject{{
			"name": "Open",
			"val":  float64(3),
		}},
		TotalCount: 1,
	}, nil)

	body, err := json.Marshal(result)
	if err != nil {
		t.Fatalf("marshal report result: %v", err)
	}
	jsonBody := string(body)
	for _, want := range []string{
		`"reportFormat":"SUMMARY"`,
		`"groupingsDown":{"groupings":[{"key":"0","label":"Open","value":"Open"}]}`,
		`"0!T":{"aggregates":[{"label":"3","value":3}],"rows":[]}`,
	} {
		if !strings.Contains(jsonBody, want) {
			t.Fatalf("report JSON = %s, missing %s", jsonBody, want)
		}
	}
}
