//go:build integration

package controlplane

import (
	"context"
	"testing"

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

func TestOpportunityGroupedCountAndSumQueryReturnsBothAggregates(t *testing.T) {
	ctx := context.Background()
	conn, sm := setupCRMRuntimeForOpportunityLineItemRollup(t, ctx)
	defer conn.Close()

	admin := systemAdminSession()
	accountID := createAccountForOrderActivation(t, ctx, sm, admin)
	pricebookID := createPricebookForOpportunityRollup(t, ctx, sm, admin)
	productID := createProductForOpportunityRollup(t, ctx, sm, admin)
	pricebookEntryID := createPricebookEntryForOpportunityRollup(t, ctx, sm, admin, pricebookID, productID, 25)
	createOpportunityForAggregateQuery(t, ctx, sm, admin, accountID, pricebookEntryID, "Pipeline A", "Prospecting", 50)
	createOpportunityForAggregateQuery(t, ctx, sm, admin, accountID, pricebookEntryID, "Pipeline B", "Prospecting", 75.5)
	createOpportunityForAggregateQuery(t, ctx, sm, admin, accountID, pricebookEntryID, "Pipeline C", "Qualification", 10)

	result, err := sm.QuerySvc().QueryWithSpec(ctx, queryspec.QuerySpec{
		ObjectAPIName: "Opportunity",
		SelectFields: []string{
			"StageName",
			"COUNT(Id) c",
			"SUM(Amount) s",
		},
		GroupBy: "StageName",
	}, admin)
	if err != nil {
		t.Fatalf("query grouped Opportunity aggregates: %v", err)
	}
	if !result.IsAggregate {
		t.Fatal("IsAggregate = false, want grouped AggregateResult rows")
	}

	prospecting := findAggregateRowByStage(t, result.Records, "Prospecting")
	if got := numericAggregateValue(t, prospecting["c"]); got != 2 {
		t.Fatalf("Prospecting c = %v, want 2", got)
	}
	if got := numericAggregateValue(t, prospecting["s"]); got != 125.5 {
		t.Fatalf("Prospecting s = %v, want 125.5", got)
	}
}

func createOpportunityForAggregateQuery(t *testing.T, ctx context.Context, sm ServiceGraph, user *models.UserSession, accountID, pricebookEntryID, name, stage string, amount float64) string {
	t.Helper()
	opportunity, err := sm.Persistence().Insert(ctx, "Opportunity", models.SObject{
		"Name":      name,
		"AccountId": accountID,
		"StageName": stage,
		"CloseDate": "2026-07-01",
	}, user)
	if err != nil {
		t.Fatalf("create opportunity %s: %v", name, err)
	}
	id, _ := opportunity["Id"].(string)
	if id == "" {
		t.Fatalf("create opportunity %s returned empty Id", name)
	}
	insertOpportunityLineItemForRollup(t, ctx, sm, user, id, pricebookEntryID, 1, amount)
	return id
}

func findAggregateRowByStage(t *testing.T, rows []models.SObject, stage string) models.SObject {
	t.Helper()
	for _, row := range rows {
		if row["StageName"] == stage {
			return row
		}
	}
	t.Fatalf("records = %#v, want row for StageName %q", rows, stage)
	return nil
}

func numericAggregateValue(t *testing.T, raw any) float64 {
	t.Helper()
	got, err := numericField(raw)
	if err != nil {
		t.Fatalf("parse aggregate value %v (%T): %v", raw, raw, err)
	}
	return got
}
