package integration_test

import (
	"context"
	"encoding/json"
	"net/http"
	"testing"
	"time"

	"galaxy/integration/testenv"
)

// TestMailFlow_LoginCodeAndAdminListing triggers a login code email
// (which uses backend's mail outbox), waits for mailpit to capture
// the SMTP delivery, and verifies the admin endpoints expose the
// same delivery via the typed list response.
//
// Resend on a `sent` row returns 409 (per OpenAPI/decision record);
// this test asserts that contract by attempting a resend on the
// captured (and now sent) delivery.
func TestMailFlow_LoginCodeAndAdminListing(t *testing.T) {
	plat := testenv.Bootstrap(t, testenv.BootstrapOptions{})
	ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second)
	defer cancel()

	// Trigger a login code, which writes one mail_deliveries row and
	// drains via the worker into mailpit.
	sess := testenv.RegisterSession(t, plat, "pilot+mail@example.com")
	if sess.DeviceSessionID == "" {
		t.Fatalf("session not established")
	}

	admin := testenv.NewBackendAdminClient(plat.Backend.HTTPURL, plat.Backend.AdminUser, plat.Backend.AdminPassword)
	raw, resp, err := admin.Do(ctx, http.MethodGet, "/api/v1/admin/mail/deliveries?page=1&page_size=10", nil)
	if err != nil {
		t.Fatalf("list deliveries: %v", err)
	}
	if resp.StatusCode != http.StatusOK {
		t.Fatalf("list deliveries: status %d body=%s", resp.StatusCode, string(raw))
	}
	var list struct {
		Items []struct {
			DeliveryID string `json:"delivery_id"`
			Status     string `json:"status"`
			TemplateID string `json:"template_id"`
		} `json:"items"`
	}
	if err := json.Unmarshal(raw, &list); err != nil {
		t.Fatalf("decode list: %v", err)
	}
	if len(list.Items) == 0 {
		t.Fatalf("admin list returned no deliveries; expected at least the login code row")
	}

	var sent string
	deadline := time.Now().Add(15 * time.Second)
	for time.Now().Before(deadline) && sent == "" {
		raw, resp, err = admin.Do(ctx, http.MethodGet, "/api/v1/admin/mail/deliveries?page=1&page_size=10", nil)
		if err != nil || resp.StatusCode != http.StatusOK {
			t.Fatalf("list deliveries during wait: %v status=%v", err, resp)
		}
		_ = json.Unmarshal(raw, &list)
		for _, it := range list.Items {
			if it.Status == "sent" {
				sent = it.DeliveryID
				break
			}
		}
		if sent == "" {
			time.Sleep(300 * time.Millisecond)
		}
	}
	if sent == "" {
		t.Fatalf("no delivery reached `sent` within 15s; admin list = %+v", list.Items)
	}

	// Resend on a sent row must return 409.
	raw, resp, err = admin.Do(ctx, http.MethodPost, "/api/v1/admin/mail/deliveries/"+sent+"/resend", nil)
	if err != nil {
		t.Fatalf("resend sent delivery: %v", err)
	}
	if resp.StatusCode != http.StatusConflict {
		t.Fatalf("resend on sent delivery: status %d body=%s, want 409", resp.StatusCode, string(raw))
	}
}
