package integration

import (
	"encoding/json"
	"fmt"
	"io"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

// ==============================================================================
// Process/Approvals API Tests
// ==============================================================================

// TestApprovalsAPI tests the /process/approvals endpoints
func TestApprovalsAPI(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping integration test")
	}

	client := newHTTPClient(t)

	t.Run("Get_Pending_Approvals", func(t *testing.T) {
		resp, err := client.request("GET", "/services/data/v63.0/process/approvals", nil)
		require.NoError(t, err)
		defer resp.Body.Close()

		// Accept 200 OK or 404 (if endpoint not fully registered)
		assert.True(t, resp.StatusCode == 200 || resp.StatusCode == 404,
			"Expected 200 or 404, got %d", resp.StatusCode)

		body, _ := io.ReadAll(resp.Body)
		t.Logf("Approvals response: %s", string(body)[:min(200, len(body))])
	})

	t.Run("Submit_Approval_Request", func(t *testing.T) {
		sf := newGoSFClient(t)

		// Create a test record
		account := map[string]interface{}{"Name": "Approval Test Account"}
		res, err := sf.InsertOne("Account", account)
		if err != nil {
			t.Skipf("Could not create test account: %v", err)
		}

		// Try to submit for approval
		payload := map[string]interface{}{
			"actionType":          "Submit",
			"contextId":           res.Id,
			"comments":            "SDK Test submission",
			"nextApproverIds":     []string{},
			"processDefinitionId": "", // Auto-select
		}

		resp, err := client.request("POST", "/services/data/v63.0/process/approvals", payload)
		require.NoError(t, err)
		defer resp.Body.Close()

		body, _ := io.ReadAll(resp.Body)
		t.Logf("Submit approval response (%d): %s", resp.StatusCode, string(body)[:min(300, len(body))])

		// Accept various responses - approval may not be configured
		assert.True(t, resp.StatusCode == 200 || resp.StatusCode == 201 || resp.StatusCode == 400 || resp.StatusCode == 404,
			"Expected 200/201/400/404, got %d", resp.StatusCode)

		// Cleanup
		sf.DeleteOne("Account", map[string]interface{}{"Id": res.Id})
	})
}

// ==============================================================================
// Chatter/Feed API Tests
// ==============================================================================

// TestChatterAPI tests the /chatter/feeds endpoints
func TestChatterAPI(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping integration test")
	}

	client := newHTTPClient(t)
	sf := newGoSFClient(t)

	// Create a test record to attach feed items to
	account := map[string]interface{}{"Name": "Chatter Test Account"}
	res, err := sf.InsertOne("Account", account)
	if err != nil {
		t.Skipf("Could not create test account: %v", err)
	}

	t.Run("Get_Record_Feed", func(t *testing.T) {
		resp, err := client.request("GET", "/services/data/v63.0/chatter/feeds/record/"+res.Id+"/feed-elements", nil)
		require.NoError(t, err)
		defer resp.Body.Close()

		// Accept 200 OK (empty feed is fine) or 404
		assert.True(t, resp.StatusCode == 200 || resp.StatusCode == 404,
			"Expected 200 or 404, got %d", resp.StatusCode)
	})

	t.Run("Post_Feed_Comment", func(t *testing.T) {
		payload := map[string]interface{}{
			"body": map[string]interface{}{
				"messageSegments": []map[string]interface{}{
					{"type": "Text", "text": "SDK Integration Test Comment"},
				},
			},
			"feedElementType": "FeedItem",
			"subjectId":       res.Id,
		}

		resp, err := client.request("POST", "/services/data/v63.0/chatter/feed-elements", payload)
		require.NoError(t, err)
		defer resp.Body.Close()

		body, _ := io.ReadAll(resp.Body)
		t.Logf("Post comment response (%d): %s", resp.StatusCode, string(body)[:min(200, len(body))])

		// Accept 201 Created, 200 OK, or 400/404 if not configured
		assert.True(t, resp.StatusCode == 201 || resp.StatusCode == 200 || resp.StatusCode == 400 || resp.StatusCode == 404,
			"Expected 200/201/400/404, got %d", resp.StatusCode)
	})

	// Cleanup
	sf.DeleteOne("Account", map[string]interface{}{"Id": res.Id})
}

// ==============================================================================
// Tree API Tests - Nested record creation
// ==============================================================================

// TestTreeAPI tests the /composite/tree endpoint for nested record creation
func TestTreeAPI(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping integration test")
	}

	client := newHTTPClient(t)

	t.Run("Create_Account_With_Contacts", func(t *testing.T) {
		// Create an Account with nested Contacts
		payload := map[string]interface{}{
			"records": []map[string]interface{}{
				{
					"attributes": map[string]string{"type": "Account", "referenceId": "ref1"},
					"Name":       fmt.Sprintf("Tree API Account %d", time.Now().UnixNano()%100000),
					"Contacts": map[string]interface{}{
						"records": []map[string]interface{}{
							{
								"attributes": map[string]string{"type": "Contact", "referenceId": "ref2"},
								"FirstName":  "Tree",
								"LastName":   "Contact1",
							},
							{
								"attributes": map[string]string{"type": "Contact", "referenceId": "ref3"},
								"FirstName":  "Tree",
								"LastName":   "Contact2",
							},
						},
					},
				},
			},
		}

		resp, err := client.request("POST", "/services/data/v63.0/composite/tree/Account", payload)
		require.NoError(t, err)
		defer resp.Body.Close()

		body, _ := io.ReadAll(resp.Body)
		t.Logf("Tree create response (%d): %s", resp.StatusCode, string(body)[:min(300, len(body))])

		// Accept 201 Created, 200 OK, or 400 if invalid structure
		assert.True(t, resp.StatusCode == 201 || resp.StatusCode == 200 || resp.StatusCode == 400,
			"Expected 200/201/400, got %d", resp.StatusCode)

		// If successful, parse and cleanup
		if resp.StatusCode == 200 || resp.StatusCode == 201 {
			var result struct {
				Results []struct {
					ID          string `json:"id"`
					ReferenceId string `json:"referenceId"`
				} `json:"results"`
			}
			json.Unmarshal(body, &result)

			sf := newGoSFClient(t)
			for _, r := range result.Results {
				if r.ID != "" {
					sf.DeleteOne("Account", map[string]interface{}{"Id": r.ID})
				}
			}
		}
	})
}

// ==============================================================================
// Versions API Test
// ==============================================================================

// TestVersionsAPI tests the /services/data endpoint
func TestVersionsAPI(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping integration test")
	}

	client := newHTTPClient(t)

	t.Run("Get_API_Versions", func(t *testing.T) {
		resp, err := client.request("GET", "/services/data/", nil)
		require.NoError(t, err)
		defer resp.Body.Close()

		assert.Equal(t, 200, resp.StatusCode, "Should return 200 OK")

		var versions []map[string]interface{}
		json.NewDecoder(resp.Body).Decode(&versions)

		assert.NotEmpty(t, versions, "Should return at least one API version")
		t.Logf("Found %d API versions", len(versions))
	})
}
