package gateway

import (
	"context"
	"testing"

	storagemodel "github.com/tech/sendico/gateway/chsettle/storage/model"
	paymenttypes "github.com/tech/sendico/pkg/payments/types"
	moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
	chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1"
)

func TestResolveSettlementScenario_AmountBuckets(t *testing.T) {
	tests := []struct {
		name   string
		amount string
		want   string
	}{
		{name: "bucket_000_fast_success", amount: "10.00", want: scenarioFastSuccess.Name},
		{name: "bucket_100_slow_success", amount: "11.00", want: scenarioSlowSuccess.Name},
		{name: "bucket_200_fail_immediate", amount: "12.00", want: scenarioFailImmediate.Name},
		{name: "bucket_300_fail_timeout", amount: "13.00", want: scenarioFailTimeout.Name},
		{name: "bucket_400_stuck_pending", amount: "14.00", want: scenarioStuckPending.Name},
		{name: "bucket_500_retry_then_success", amount: "15.00", want: scenarioRetryThenSuccess.Name},
		{name: "bucket_600_webhook_delayed_success", amount: "16.00", want: scenarioWebhookDelayedSuccess.Name},
		{name: "bucket_700_slow_then_fail", amount: "17.00", want: scenarioSlowThenFail.Name},
		{name: "bucket_800_partial_progress_stuck", amount: "18.00", want: scenarioPartialProgressStuck.Name},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			got := resolveSettlementScenario("idem-"+tc.name, &paymenttypes.Money{Amount: tc.amount, Currency: "USD"}, nil)
			if got.Name != tc.want {
				t.Fatalf("scenario mismatch: got=%q want=%q", got.Name, tc.want)
			}
		})
	}
}

func TestResolveSettlementScenario_ExplicitOverride(t *testing.T) {
	got := resolveSettlementScenario("idem-override", &paymenttypes.Money{Amount: "10.00", Currency: "USD"}, map[string]string{
		scenarioMetadataKey: "stuck",
	})
	if got.Name != scenarioStuckPending.Name {
		t.Fatalf("scenario mismatch: got=%q want=%q", got.Name, scenarioStuckPending.Name)
	}
}

func TestSubmitTransfer_UsesImmediateFailureScenario(t *testing.T) {
	svc, repo, _ := newTestService(t)

	resp, err := svc.SubmitTransfer(context.Background(), &chainv1.SubmitTransferRequest{
		IdempotencyKey: "idem-immediate-fail",
		IntentRef:      "intent-immediate-fail",
		OperationRef:   "op-immediate-fail",
		PaymentRef:     "payment-immediate-fail",
		Amount:         &moneyv1.Money{Amount: "9.99", Currency: "USD"},
		Metadata: map[string]string{
			scenarioMetadataAliasKey: "fail_immediate",
		},
	})
	if err != nil {
		t.Fatalf("submit transfer failed: %v", err)
	}
	if got, want := resp.GetTransfer().GetStatus(), chainv1.TransferStatus_TRANSFER_FAILED; got != want {
		t.Fatalf("transfer status mismatch: got=%v want=%v", got, want)
	}

	record := repo.payments.records["idem-immediate-fail"]
	if record == nil {
		t.Fatalf("expected payment record")
	}
	if got, want := record.Status, storagemodel.PaymentStatusFailed; got != want {
		t.Fatalf("record status mismatch: got=%s want=%s", got, want)
	}
	if got, want := record.Scenario, scenarioFailImmediate.Name; got != want {
		t.Fatalf("record scenario mismatch: got=%q want=%q", got, want)
	}
}

func TestApplyScenarioTransition_SetsFinalSuccess(t *testing.T) {
	svc, repo, _ := newTestService(t)
	_ = repo.payments.Upsert(context.Background(), &storagemodel.PaymentRecord{
		IdempotencyKey: "idem-transition-success",
		IntentRef:      "intent-transition-success",
		OperationRef:   "op-transition-success",
		PaymentRef:     "payment-transition-success",
		RequestedMoney: &paymenttypes.Money{Amount: "5.00", Currency: "USD"},
		Status:         storagemodel.PaymentStatusWaiting,
		Scenario:       scenarioSlowSuccess.Name,
	})

	svc.applyScenarioTransition("idem-transition-success", scenarioSlowSuccess)

	record := repo.payments.records["idem-transition-success"]
	if record == nil {
		t.Fatalf("expected payment record")
	}
	if got, want := record.Status, storagemodel.PaymentStatusSuccess; got != want {
		t.Fatalf("record status mismatch: got=%s want=%s", got, want)
	}
	if record.ExecutedMoney == nil {
		t.Fatalf("expected executed money")
	}
}
