package scenarios_test

// Bootstrap helpers — ensure standard objects and test data exist before tests run.
//
// Pattern: "ensure, don't assume". Each test that needs a standard object
// (Lead, Account, CampaignMemberStatus, etc.) calls ensureObject() which
// creates it if missing. This makes tests self-healing — they work regardless
// of whether the backend was freshly initialized or has existing data.

import (
	"net/http"
	"testing"

	"github.com/nexuscrm/tests/contract/internal/liveapi"
	"github.com/stretchr/testify/require"
)

// ensureObject checks if an object exists via describe. If not, creates it
// via Tooling API CustomObject. Returns true if the object is available.
func ensureObject(t testing.TB, objectName, label, labelPlural string) bool {
	t.Helper()

	client := liveapi.NewAuthenticatedClient(t)

	// Check if object already exists
	resp, err := client.Do(http.MethodGet, "/sobjects/"+objectName+"/describe", "", nil)
	require.NoError(t, err)

	if resp.StatusCode == http.StatusOK {
		resp.Body.Close()
		return true // already exists
	}
	resp.Body.Close()

	// Create the object
	t.Logf("bootstrap: creating object %s", objectName)
	createResp, err := client.DoJSON(http.MethodPost, "/tooling/sobjects/CustomObject", map[string]any{
		"name":        objectName,
		"label":       label,
		"labelPlural": labelPlural,
		"custom":      false,
		"description": "Auto-created by scenario test bootstrap",
	})
	require.NoError(t, err)

	body := liveapi.ReadBody(t, createResp)
	if createResp.StatusCode != http.StatusCreated {
		t.Logf("bootstrap: failed to create %s (status %d): %s", objectName, createResp.StatusCode, string(body))
		return false
	}

	t.Logf("bootstrap: created %s", objectName)
	return true
}

// ensureField checks if a field exists on an object. If not, creates it.
func ensureField(t testing.TB, objectName, fieldName, label, fieldType string) {
	t.Helper()

	client := liveapi.NewAuthenticatedClient(t)

	// Try to create — if it already exists, the API returns an error which we ignore
	createResp, err := client.DoJSON(http.MethodPost, "/tooling/sobjects/CustomField", map[string]any{
		"FullName":      objectName + "." + fieldName,
		"TableEnumOrId": objectName,
		"Metadata": map[string]any{
			"label": label,
			"type":  fieldType,
		},
	})
	if err != nil {
		t.Logf("bootstrap: field %s.%s creation request failed: %v", objectName, fieldName, err)
		return
	}

	body := liveapi.ReadBody(t, createResp)
	if createResp.StatusCode == http.StatusCreated {
		t.Logf("bootstrap: created field %s.%s", objectName, fieldName)
	} else if createResp.StatusCode == http.StatusBadRequest || createResp.StatusCode == http.StatusConflict {
		// Field likely already exists — ignore
	} else {
		t.Logf("bootstrap: field %s.%s status %d: %s", objectName, fieldName, createResp.StatusCode, string(body))
	}
}

// ensureLead ensures the Lead standard object and its required fields exist.
func ensureLead(t testing.TB) bool {
	t.Helper()
	if !ensureObject(t, "Lead", "Lead", "Leads") {
		return false
	}
	ensureField(t, "Lead", "LastName", "Last Name", "Text")
	ensureField(t, "Lead", "FirstName", "First Name", "Text")
	ensureField(t, "Lead", "Company", "Company", "Text")
	ensureField(t, "Lead", "Status", "Status", "Text")
	ensureField(t, "Lead", "IsConverted", "Converted", "Checkbox")
	ensureField(t, "Lead", "ConvertedAccountId", "Converted Account", "Text")
	ensureField(t, "Lead", "ConvertedContactId", "Converted Contact", "Text")
	ensureField(t, "Lead", "ConvertedOpportunityId", "Converted Opportunity", "Text")
	ensureField(t, "Lead", "ConvertedDate", "Converted Date", "DateTime")
	return true
}

// ensureAccount ensures the Account standard object exists.
func ensureAccount(t testing.TB) bool {
	t.Helper()
	return ensureObject(t, "Account", "Account", "Accounts")
}

// ensureCampaignMemberStatus ensures the CampaignMemberStatus object exists.
func ensureCampaignMemberStatus(t testing.TB) bool {
	t.Helper()
	return ensureObject(t, "CampaignMemberStatus", "Campaign Member Status", "Campaign Member Statuses")
}
