package rest_api_test

// Docs:
// - Endpoint: https://developer.salesforce.com/docs/atlas.en-us.254.0.api_rest.meta/api_rest/resources_sobject_flowinterview.htm
// - Request: https://developer.salesforce.com/docs/atlas.en-us.254.0.api_rest.meta/api_rest/resources_sobject_flowinterview.htm
// - Response: https://developer.salesforce.com/docs/atlas.en-us.254.0.api_rest.meta/api_rest/resources_sobject_flowinterview.htm
// - Sub-schema: https://developer.salesforce.com/docs/atlas.en-us.254.0.api_rest.meta/api_rest/resources_sobject_flowinterview.htm
// - Errors: https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/intro_rest.htm

import (
	"net/http"
	"testing"

	"github.com/nexuscrm/tests/contract/internal/contracttest"
	"github.com/nexuscrm/tests/contract/internal/liveapi"
	"github.com/nexuscrm/tests/contract/rest_api/internal/arrange"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestFlowInterviewList(t *testing.T) {
	contracttest.EnsureLocalRESTBaseline(t)

	client := liveapi.NewAuthenticatedClient(t)
	// Doc: https://developer.salesforce.com/docs/atlas.en-us.254.0.api_rest.meta/api_rest/resources_sobject_flowinterview.htm
	resp, err := client.DoJSON(http.MethodGet, "/sobjects/FlowInterview", nil)
	require.NoError(t, err)

	if resp.StatusCode == http.StatusInternalServerError {
		var body map[string]any
		liveapi.DecodeJSON(t, resp, &body)
		assert.Equal(t, "InternalServerError", body["code"])
		return
	}

	require.Equal(t, http.StatusOK, resp.StatusCode)
	contracttest.AssertJSONContentType(t, resp)

	var listBody struct {
		TotalSize int                      `json:"totalSize"`
		Done      bool                     `json:"done"`
		Records   []map[string]interface{} `json:"records"`
	}
	liveapi.DecodeJSON(t, resp, &listBody)
	assert.True(t, listBody.Done)
	assert.GreaterOrEqual(t, listBody.TotalSize, 0)
	for _, record := range listBody.Records {
		if id, ok := record["Id"].(string); ok {
			contracttest.AssertSalesforceID(t, id)
		}
		if attributes, ok := record["attributes"].(map[string]any); ok {
			assert.Equal(t, "FlowInterview", attributes["type"])
			assert.Contains(t, attributes["url"], "/sobjects/FlowInterview/")
		}
	}
}

func TestFlowInterviewGetDelete(t *testing.T) {
	contracttest.EnsureLocalRESTBaseline(t)

	flow := arrange.CreateInvocableFlow(t, arrange.UniqueName("Interview Flow"))
	interviewID := arrange.CreatePausedFlowInterview(t, flow.VersionID, "AssignVar")
	t.Cleanup(func() { arrange.DeleteSObjectIfPresent(t, "FlowInterview", interviewID) })

	client := liveapi.NewAuthenticatedClient(t)

	// Doc: https://developer.salesforce.com/docs/atlas.en-us.254.0.api_rest.meta/api_rest/resources_sobject_flowinterview.htm
	getResp, err := client.DoJSON(http.MethodGet, "/sobjects/FlowInterview/"+interviewID, nil)
	require.NoError(t, err)
	require.Equal(t, http.StatusOK, getResp.StatusCode)
	contracttest.AssertJSONContentType(t, getResp)

	var getBody map[string]any
	liveapi.DecodeJSON(t, getResp, &getBody)
	assert.Equal(t, interviewID, getBody["Id"])
	assert.Equal(t, flow.VersionID, getBody["FlowVersionId"])
	if attributes, ok := getBody["attributes"].(map[string]any); ok {
		assert.Equal(t, "FlowInterview", attributes["type"])
		assert.Contains(t, attributes["url"], interviewID)
	}

	// Doc: https://developer.salesforce.com/docs/atlas.en-us.254.0.api_rest.meta/api_rest/resources_sobject_flowinterview.htm
	deleteResp, err := client.Do(http.MethodDelete, "/sobjects/FlowInterview/"+interviewID, "", nil)
	require.NoError(t, err)
	require.Equal(t, http.StatusNoContent, deleteResp.StatusCode)
	require.NoError(t, deleteResp.Body.Close())

	afterResp, err := client.DoJSON(http.MethodGet, "/sobjects/FlowInterview/"+interviewID, nil)
	require.NoError(t, err)
	require.Equal(t, http.StatusNotFound, afterResp.StatusCode)
	var errBody map[string]any
	liveapi.DecodeJSON(t, afterResp, &errBody)
	assert.Equal(t, "ResourceNotFound", errBody["code"])
}
