package gateway

import (
	"context"
	"testing"

	storagemodel "github.com/tech/sendico/gateway/tgsettle/storage/model"
	paymenttypes "github.com/tech/sendico/pkg/payments/types"
	moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
	connectorv1 "github.com/tech/sendico/pkg/proto/connector/v1"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

func TestSubmitOperation_UsesOperationRefAsOperationID(t *testing.T) {
	svc, _, _ := newTestService(t)
	svc.chatID = "1"

	req := &connectorv1.SubmitOperationRequest{
		Operation: &connectorv1.Operation{
			Type:           connectorv1.OperationType_TRANSFER,
			IdempotencyKey: "idem-settlement-1",
			OperationRef:   "payment-1:hop_2_settlement_fx_convert",
			IntentRef:      "intent-1",
			Money:          &moneyv1.Money{Amount: "1.00", Currency: "USDT"},
			From: &connectorv1.OperationParty{
				Ref: &connectorv1.OperationParty_Account{Account: &connectorv1.AccountRef{
					ConnectorId: tgsettleConnectorID,
					AccountId:   "wallet-src",
				}},
			},
			To: &connectorv1.OperationParty{
				Ref: &connectorv1.OperationParty_Account{Account: &connectorv1.AccountRef{
					ConnectorId: tgsettleConnectorID,
					AccountId:   "wallet-dst",
				}},
			},
			Params: structFromMap(map[string]interface{}{
				"payment_ref":      "payment-1",
				"organization_ref": "org-1",
			}),
		},
	}

	resp, err := svc.SubmitOperation(context.Background(), req)
	if err != nil {
		t.Fatalf("SubmitOperation returned error: %v", err)
	}
	if resp.GetReceipt() == nil {
		t.Fatal("expected receipt")
	}
	if got := resp.GetReceipt().GetError(); got != nil {
		t.Fatalf("expected no connector error, got: %v", got)
	}
	if got, want := resp.GetReceipt().GetOperationId(), "payment-1:hop_2_settlement_fx_convert"; got != want {
		t.Fatalf("operation_id mismatch: got=%q want=%q", got, want)
	}
	if got, want := resp.GetReceipt().GetProviderRef(), "idem-settlement-1"; got != want {
		t.Fatalf("provider_ref mismatch: got=%q want=%q", got, want)
	}
}

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

	record := &storagemodel.PaymentRecord{
		IdempotencyKey:  "idem-settlement-2",
		OperationRef:    "payment-2:hop_2_settlement_fx_convert",
		PaymentIntentID: "pi-2",
		PaymentRef:      "payment-2",
		RequestedMoney:  &paymenttypes.Money{Amount: "5.00", Currency: "USDT"},
		Status:          storagemodel.PaymentStatusSuccess,
	}
	if err := repo.payments.Upsert(context.Background(), record); err != nil {
		t.Fatalf("failed to seed payment record: %v", err)
	}

	resp, err := svc.GetOperation(context.Background(), &connectorv1.GetOperationRequest{
		OperationId: "payment-2:hop_2_settlement_fx_convert",
	})
	if err != nil {
		t.Fatalf("GetOperation returned error: %v", err)
	}
	if resp.GetOperation() == nil {
		t.Fatal("expected operation")
	}
	if got, want := resp.GetOperation().GetOperationId(), "payment-2:hop_2_settlement_fx_convert"; got != want {
		t.Fatalf("operation_id mismatch: got=%q want=%q", got, want)
	}
	if got, want := resp.GetOperation().GetProviderRef(), "idem-settlement-2"; got != want {
		t.Fatalf("provider_ref mismatch: got=%q want=%q", got, want)
	}
}

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

	record := &storagemodel.PaymentRecord{
		IdempotencyKey:  "idem-settlement-3",
		OperationRef:    "payment-3:hop_2_settlement_fx_convert",
		PaymentIntentID: "pi-3",
		PaymentRef:      "payment-3",
		RequestedMoney:  &paymenttypes.Money{Amount: "5.00", Currency: "USDT"},
		Status:          storagemodel.PaymentStatusSuccess,
	}
	if err := repo.payments.Upsert(context.Background(), record); err != nil {
		t.Fatalf("failed to seed payment record: %v", err)
	}

	_, err := svc.GetOperation(context.Background(), &connectorv1.GetOperationRequest{
		OperationId: "idem-settlement-3",
	})
	if err == nil {
		t.Fatal("expected not found error")
	}
	if status.Code(err) != codes.NotFound {
		t.Fatalf("unexpected error code: got=%s want=%s", status.Code(err), codes.NotFound)
	}
}
