package analytics

import (
	"context"
	"testing"

	"github.com/nexuscrm/metadata"
	"github.com/nexuscrm/permissions"
	"github.com/nexuscrm/kernel/pkg/ports"
	domainrls "github.com/nexuscrm/kernel/pkg/rls"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/models"
	"github.com/nexuscrm/shared/pkg/queryspec"
)

func TestQueryAppliesAggregateFetchLimitFromContext(t *testing.T) {
	schema := &models.ObjectMetadata{
		APIName:      "Account",
		SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: "Industry", Type: constants.FieldTypeString},
		},
	}
	repo := &aggregateFetchLimitRepository{}
	metadataSvc := metadata.NewMetadataService(&searchMetadataRepository{schema: schema}, nil, nil)
	permissionSvc := permissions.NewPermissionService(&searchPermissionRepository{
		fieldReads: map[string]bool{
			"account.id":       true,
			"account.industry": true,
		},
	}, metadataSvc, nil)
	qs := NewQueryService(repo, metadataSvc, permissionSvc, nil)

	_, err := qs.Query(
		WithAggregateFetchLimit(context.Background(), 1000),
		queryspec.QuerySpec{
			ObjectAPIName: "Account",
			SelectFields:  []string{"COUNT(Id)"},
			GroupBy:       "Industry",
			Limit:         200,
		},
		&models.UserSession{ID: "005-reader", ProfileID: "00e-standard"},
	)
	if err != nil {
		t.Fatalf("Query error = %v", err)
	}
	if repo.got.Limit != 1000 {
		t.Fatalf("analytics limit = %d, want aggregate fetch limit 1000", repo.got.Limit)
	}
}

func TestQueryWithSpec_PropagatesSkipTotalSizeToRepository(t *testing.T) {
	schema := &models.ObjectMetadata{
		APIName:      "Account",
		SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
		},
	}
	repo := &skipTotalSizeRepository{}
	metadataSvc := metadata.NewMetadataService(&searchMetadataRepository{schema: schema}, nil, nil)
	permissionSvc := permissions.NewPermissionService(&searchPermissionRepository{
		fieldReads: map[string]bool{
			"account.id":   true,
			"account.name": true,
		},
	}, metadataSvc, nil)
	qs := NewQueryService(repo, metadataSvc, permissionSvc, nil)

	_, err := qs.QueryWithSpec(context.Background(), queryspec.QuerySpec{
		ObjectAPIName: "Account",
		SelectFields:  []string{"Name"},
		Limit:         50,
		SkipTotalSize: true,
	}, &models.UserSession{ID: "005-reader", ProfileID: "00e-standard"})
	if err != nil {
		t.Fatalf("QueryWithSpec error = %v", err)
	}
	if !repo.findCalled {
		t.Fatal("repo.Find was not called")
	}
	if !repo.skipTotalSize {
		t.Fatal("repo.Find did not receive SkipTotalSize=true")
	}
}

type aggregateFetchLimitRepository struct {
	ports.QueryRepository

	got models.AnalyticsQuery
}

func (r *aggregateFetchLimitRepository) RunAnalytics(ctx context.Context, tableSchema *models.ObjectMetadata, q models.AnalyticsQuery, rlsResult *domainrls.Result) (interface{}, error) {
	r.got = q
	return []models.SObject{{"name": "Technology", "val": 1}}, nil
}

type skipTotalSizeRepository struct {
	ports.QueryRepository

	findCalled    bool
	skipTotalSize bool
}

func (r *skipTotalSizeRepository) Find(ctx context.Context, schema *models.ObjectMetadata, req models.QueryRequest, rlsResult *domainrls.Result, visibleFields []string) (*models.QueryResult, error) {
	r.findCalled = true
	r.skipTotalSize = req.SkipTotalSize
	return &models.QueryResult{
		TotalSize: 1,
		Done:      true,
		Records:   []models.SObject{{constants.FieldID: "001-test", constants.FieldName: "Acme"}},
	}, nil
}
