package favorites_test

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

	uiclient "github.com/nexuscrm/tests/contract/ui_api/client"
	"github.com/nexuscrm/tests/contract/ui_api/internal/arrange"
	"github.com/nexuscrm/tests/contract/ui_api/internal/asserts"
	"github.com/stretchr/testify/require"
)

func createFavorite(t testing.TB, client *uiclient.Client) string {
	t.Helper()

	accountID := createFavoriteAccount(t, client)
	payload := map[string]any{
		"name":       "UI API Favorite",
		"sortOrder":  1,
		"target":     accountID,
		"targetType": "Record",
	}

	resp, err := client.PostJSON("/ui-api/favorites", payload)
	require.NoError(t, err)
	if resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusOK {
		body := asserts.DecodeAny(t, resp)
		t.Fatalf("create favorite status=%d body=%v", resp.StatusCode, body)
	}

	return decodeFavoriteID(t, resp)
}

func decodeFavoriteID(t testing.TB, resp *http.Response) string {
	t.Helper()
	payload := asserts.DecodeAny(t, resp)

	switch typed := payload.(type) {
	case map[string]any:
		if id, ok := typed["id"].(string); ok && strings.TrimSpace(id) != "" {
			return id
		}
		if id, ok := typed["favoriteId"].(string); ok && strings.TrimSpace(id) != "" {
			return id
		}
	case []any:
		if len(typed) == 0 {
			break
		}
		first := asserts.RequireMap(t, typed[0])
		if id, ok := first["id"].(string); ok && strings.TrimSpace(id) != "" {
			return id
		}
		if id, ok := first["favoriteId"].(string); ok && strings.TrimSpace(id) != "" {
			return id
		}
	}

	t.Fatalf("favorite id not found in response")
	return ""
}

func createFavoriteAccount(t testing.TB, client *uiclient.Client) string {
	t.Helper()

	arrange.EnsureLocalStandardObjects(t)

	payload := map[string]any{
		"Name": "UI API Favorite " + time.Now().UTC().Format("20060102150405"),
	}

	resp, err := client.PostJSON("/sobjects/Account", payload)
	require.NoError(t, err)
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusOK {
		body := asserts.DecodeAny(t, resp)
		t.Fatalf("create account status=%d body=%v", resp.StatusCode, body)
	}

	var created struct {
		ID string `json:"id"`
	}
	require.NoError(t, json.NewDecoder(resp.Body).Decode(&created))
	require.NotEmpty(t, strings.TrimSpace(created.ID))
	return created.ID
}

func assertFavoriteItem(t testing.TB, favorite map[string]any) {
	t.Helper()

	if idRaw, ok := favorite["id"].(string); ok && idRaw != "" {
		asserts.RequireSalesforceID(t, idRaw)
	}
	if idRaw, ok := favorite["favoriteId"].(string); ok && idRaw != "" {
		asserts.RequireSalesforceID(t, idRaw)
	}

	_ = asserts.RequireStringFieldAny(t, favorite, "name", "label")
	_ = asserts.RequireStringFieldAny(t, favorite, "target", "recordId")
	_ = asserts.RequireStringFieldAny(t, favorite, "targetType", "type")

	asserts.RequireNumberIfPresent(t, favorite, "sortOrder")
	asserts.RequireBoolIfPresent(t, favorite, "isDefault")
	asserts.RequireStringIfPresent(t, favorite, "iconUrl")
	asserts.RequireStringIfPresent(t, favorite, "listViewId")
	asserts.RequireStringIfPresent(t, favorite, "objectApiName")
	asserts.RequireMapIfPresent(t, favorite, "attributes")
}
