package e2e

import (
	"bytes"
	"encoding/json"
	"net/http"
	"os"
	"strings"
	"testing"
	"time"
)

func TestAPISmokeE2E(t *testing.T) {
	baseURL := strings.TrimRight(os.Getenv("BANKING_E2E_BASE_URL"), "/")
	if baseURL == "" {
		t.Skip("set BANKING_E2E_BASE_URL to run live API e2e smoke tests")
	}

	client := &http.Client{Timeout: 10 * time.Second}
	getOK(t, client, baseURL+"/healthz")
	getOK(t, client, baseURL+"/readyz")

	email := "e2e-" + time.Now().UTC().Format("20060102150405") + "@example.com"
	payload := map[string]string{
		"email":     email,
		"password":  "very-secure-passphrase",
		"full_name": "E2E Smoke",
	}
	body, _ := json.Marshal(payload)
	resp, err := client.Post(baseURL+"/v1/auth/register", "application/json", bytes.NewReader(body))
	if err != nil {
		t.Fatalf("register request: %v", err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusCreated {
		t.Fatalf("register status = %d, want %d", resp.StatusCode, http.StatusCreated)
	}

	seededEmail := strings.TrimSpace(os.Getenv("BANKING_E2E_CUSTOMER_EMAIL"))
	seededPassword := strings.TrimSpace(os.Getenv("BANKING_E2E_CUSTOMER_PASSWORD"))
	if seededEmail != "" && seededPassword != "" {
		token := login(t, client, baseURL, seededEmail, seededPassword)
		getAuthorizedOK(t, client, baseURL+"/v1/accounts", token)
	}
}

func getOK(t *testing.T, client *http.Client, url string) {
	t.Helper()
	resp, err := client.Get(url)
	if err != nil {
		t.Fatalf("GET %s: %v", url, err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		t.Fatalf("GET %s status = %d, want %d", url, resp.StatusCode, http.StatusOK)
	}
}

func login(t *testing.T, client *http.Client, baseURL, email, password string) string {
	t.Helper()
	payload := map[string]string{"email": email, "password": password}
	body, _ := json.Marshal(payload)
	resp, err := client.Post(baseURL+"/v1/auth/login", "application/json", bytes.NewReader(body))
	if err != nil {
		t.Fatalf("login request: %v", err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		t.Fatalf("login status = %d, want %d", resp.StatusCode, http.StatusOK)
	}
	var response struct {
		AccessToken string `json:"access_token"`
		Token       string `json:"token"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
		t.Fatalf("decode login response: %v", err)
	}
	if response.AccessToken != "" {
		return response.AccessToken
	}
	if response.Token != "" {
		return response.Token
	}
	t.Fatal("login response did not include access token")
	return ""
}

func getAuthorizedOK(t *testing.T, client *http.Client, url, token string) {
	t.Helper()
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		t.Fatalf("build GET %s: %v", url, err)
	}
	req.Header.Set("Authorization", "Bearer "+token)
	resp, err := client.Do(req)
	if err != nil {
		t.Fatalf("GET %s: %v", url, err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		t.Fatalf("GET %s status = %d, want %d", url, resp.StatusCode, http.StatusOK)
	}
}
