package monetix

import (
	"bytes"
	"context"
	"encoding/json"
	"io"
	"net/http"
	"strings"
	"testing"

	"go.uber.org/zap"
)

type roundTripperFunc func(*http.Request) (*http.Response, error)

func (f roundTripperFunc) RoundTrip(r *http.Request) (*http.Response, error) {
	return f(r)
}

func TestSendCardPayout_SignsPayload(t *testing.T) {
	secret := "secret"
	var captured CardPayoutRequest

	httpClient := &http.Client{
		Transport: roundTripperFunc(func(r *http.Request) (*http.Response, error) {
			if r.URL.Path != "/v2/payment/card/payout" {
				t.Fatalf("expected payout path, got %q", r.URL.Path)
			}
			body, _ := io.ReadAll(r.Body)
			if err := json.Unmarshal(body, &captured); err != nil {
				t.Fatalf("failed to decode request: %v", err)
			}
			resp := APIResponse{}
			resp.Operation.RequestID = "req-1"
			payload, _ := json.Marshal(resp)
			return &http.Response{
				StatusCode: http.StatusOK,
				Body:       io.NopCloser(bytes.NewReader(payload)),
				Header:     http.Header{"Content-Type": []string{"application/json"}},
			}, nil
		}),
	}

	cfg := Config{
		BaseURL:   "https://monetix.test",
		SecretKey: secret,
	}
	client := NewClient(cfg, httpClient, zap.NewNop())

	req := CardPayoutRequest{
		General: General{ProjectID: 1, PaymentID: "payout-1"},
		Customer: Customer{
			ID:        "cust-1",
			FirstName: "Jane",
			LastName:  "Doe",
			IP:        "203.0.113.10",
		},
		Payment: Payment{Amount: 1000, Currency: "RUB"},
		Card:    Card{PAN: "4111111111111111", Year: 2030, Month: 12, CardHolder: "JANE DOE"},
	}

	result, err := client.CreateCardPayout(context.Background(), req)
	if err != nil {
		t.Fatalf("expected no error, got %v", err)
	}
	if !result.Accepted {
		t.Fatalf("expected accepted response")
	}
	if captured.General.Signature == "" {
		t.Fatalf("expected signature in request")
	}

	signed := captured
	signed.General.Signature = ""
	expectedSig, err := SignPayload(signed, secret)
	if err != nil {
		t.Fatalf("failed to compute signature: %v", err)
	}
	if captured.General.Signature != expectedSig {
		t.Fatalf("expected signature %q, got %q", expectedSig, captured.General.Signature)
	}
}

func TestSendCardPayout_HTTPError(t *testing.T) {
	httpClient := &http.Client{
		Transport: roundTripperFunc(func(r *http.Request) (*http.Response, error) {
			body := `{"code":"E100","message":"denied"}`
			return &http.Response{
				StatusCode: http.StatusBadRequest,
				Body:       io.NopCloser(strings.NewReader(body)),
				Header:     http.Header{"Content-Type": []string{"application/json"}},
			}, nil
		}),
	}

	cfg := Config{
		BaseURL:   "https://monetix.test",
		SecretKey: "secret",
	}
	client := NewClient(cfg, httpClient, zap.NewNop())

	req := CardPayoutRequest{
		General: General{ProjectID: 1, PaymentID: "payout-1"},
		Customer: Customer{
			ID:        "cust-1",
			FirstName: "Jane",
			LastName:  "Doe",
			IP:        "203.0.113.10",
		},
		Payment: Payment{Amount: 1000, Currency: "RUB"},
		Card:    Card{PAN: "4111111111111111", Year: 2030, Month: 12, CardHolder: "JANE DOE"},
	}

	result, err := client.CreateCardPayout(context.Background(), req)
	if err != nil {
		t.Fatalf("expected no error, got %v", err)
	}
	if result.Accepted {
		t.Fatalf("expected rejected response")
	}
	if result.ErrorCode != "E100" {
		t.Fatalf("expected error code E100, got %q", result.ErrorCode)
	}
	if result.ErrorMessage != "denied" {
		t.Fatalf("expected error message denied, got %q", result.ErrorMessage)
	}
}
