package automation

import (
	"context"
	"testing"
	"time"

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

func TestExecuteScheduledVersion_DelegatesToSharedExecutorAndReturnsStructuredResult(t *testing.T) {
	ctx := context.Background()
	version := &models.FlowVersion{Id: "301issue646unit"}
	inputs := map[string]interface{}{"k": "v"}
	user := newSystemAutomationUser()
	want := &models.FlowExecutionResult{
		ActionName: "Issue646UnitFlow",
		IsSuccess:  false,
		Errors: []models.FlowExecutionError{{
			StatusCode: "FLOW_ERROR",
			Message:    "shared path returned structured failure",
		}},
	}

	var gotVersion *models.FlowVersion
	var gotName string
	var gotInputs map[string]interface{}
	var gotUser *models.UserSession

	s := &SchedulerService{
		executeFlowVersionFn: func(callCtx context.Context, flowVersion *models.FlowVersion, flowAPIName string, callInputs map[string]interface{}, callUser *models.UserSession) (*models.FlowExecutionResult, error) {
			if callCtx != ctx {
				t.Fatalf("executeFlowVersionFn ctx mismatch")
			}
			gotVersion = flowVersion
			gotName = flowAPIName
			gotInputs = callInputs
			gotUser = callUser
			return want, nil
		},
	}

	got, err := s.executeScheduledVersion(ctx, version, "Issue646UnitFlow", inputs, user)
	if err != nil {
		t.Fatalf("executeScheduledVersion() error = %v", err)
	}
	if got != want {
		t.Fatalf("executeScheduledVersion() result = %#v, want exact shared-result pointer %#v", got, want)
	}
	if gotVersion != version {
		t.Fatalf("shared executor received version %p, want %p", gotVersion, version)
	}
	if gotName != "Issue646UnitFlow" {
		t.Fatalf("shared executor flowAPIName = %q, want %q", gotName, "Issue646UnitFlow")
	}
	if gotInputs["k"] != "v" {
		t.Fatalf("shared executor inputs = %#v, want original map", gotInputs)
	}
	if gotUser != user {
		t.Fatalf("shared executor user = %p, want %p", gotUser, user)
	}
}

func TestExecuteScheduledDefinition_OneInputUsesSystemContextAndSystemUser(t *testing.T) {
	baseCtx := context.Background()
	def := &models.FlowDefinition{
		Id:            "300issue646unit",
		DeveloperName: "Issue646ScheduledDefinition",
	}
	version := scheduledFlowVersion("Once", "2026-05-11", "09:00:30")
	version.Id = "301issue646unit"
	systemUser := newSystemAutomationUser()
	inputs := map[string]interface{}{
		"$Record": models.SObject{constants.FieldID: "x640000000000001"},
	}
	store := newScheduledRunReservationStoreStub()
	now := time.Date(2026, 5, 11, 9, 1, 29, 0, time.UTC)

	var loadCtx context.Context
	var loadUser *models.UserSession
	var execCtx context.Context
	var execUser *models.UserSession
	var execInputs map[string]interface{}

	s := &SchedulerService{
		nowFn: func() time.Time { return now },
		loadScheduledInputsFn: func(callCtx context.Context, flowVersion *models.FlowVersion, user *models.UserSession) ([]map[string]interface{}, error) {
			loadCtx = callCtx
			loadUser = user
			if flowVersion != version {
				t.Fatalf("loadScheduledInputsFn flowVersion = %p, want %p", flowVersion, version)
			}
			return []map[string]interface{}{inputs}, nil
		},
		executeFlowVersionFn: func(callCtx context.Context, flowVersion *models.FlowVersion, flowAPIName string, callInputs map[string]interface{}, user *models.UserSession) (*models.FlowExecutionResult, error) {
			execCtx = callCtx
			execUser = user
			execInputs = callInputs
			if flowVersion != version {
				t.Fatalf("executeFlowVersionFn flowVersion = %p, want %p", flowVersion, version)
			}
			if flowAPIName != def.DeveloperName {
				t.Fatalf("executeFlowVersionFn flowAPIName = %q, want %q", flowAPIName, def.DeveloperName)
			}
			return &models.FlowExecutionResult{ActionName: flowAPIName, IsSuccess: true}, nil
		},
		reservationStoreFn: func() scheduledRunReservationStore {
			return store
		},
	}

	s.executeScheduledDefinition(baseCtx, def, version, systemUser)

	if constants.GetSecurityContext(loadCtx) != constants.SystemContext {
		t.Fatalf("loadScheduledInputsFn security context = %v, want %v", constants.GetSecurityContext(loadCtx), constants.SystemContext)
	}
	if constants.GetSecurityContext(execCtx) != constants.SystemContext {
		t.Fatalf("executeFlowVersionFn security context = %v, want %v", constants.GetSecurityContext(execCtx), constants.SystemContext)
	}
	if loadUser == nil || loadUser.ID != constants.SystemUserID {
		t.Fatalf("loadScheduledInputsFn user = %#v, want system automation user", loadUser)
	}
	if execUser == nil || execUser.ID != constants.SystemUserID {
		t.Fatalf("executeFlowVersionFn user = %#v, want system automation user", execUser)
	}
	if execInputs[constants.FieldID] == "x640000000000001" {
		t.Fatalf("executeFlowVersionFn received flattened record instead of original inputs map: %#v", execInputs)
	}
	record, ok := execInputs["$Record"].(models.SObject)
	if !ok || record[constants.FieldID] != "x640000000000001" {
		t.Fatalf("executeFlowVersionFn inputs = %#v, want original $Record payload", execInputs)
	}
	if len(store.completeCalls) != 1 {
		t.Fatalf("reservation Complete call count = %d, want 1", len(store.completeCalls))
	}
}
