package dialectsfcrm

import (
	"context"
	"net/http"
	"strings"
	"testing"

	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/dialect"
	"github.com/nexuscrm/shared/pkg/models"
)

// TestUIAPIRecordUIPercentDisplayUsesResolvedScale pins pack#4831 seam 1: the
// percent displayValue was formatted with a hardcoded "%.0f%%", so a field
// declaring 2 decimals still rendered whole percentages. It now formats to the
// same scale the describe projection reports for that field.
//
// What this does NOT do is invent a scale for a field that declares none —
// those still render exactly as before. Moving undeclared percent fields to 2
// needs D2's exception list, which needs the substrate; see #4831.
func TestUIAPIRecordUIPercentDisplayUsesResolvedScale(t *testing.T) {
	percent := models.FieldType(constants.FieldTypePercent)
	scale := func(v int) *int { return &v }

	for _, tc := range []struct {
		name         string
		field        models.FieldMetadata
		value        float64
		want         string
		wantDecimals int
	}{
		{
			name: "a computed percent field declaring 2 renders 2 — the case this PR changes",
			field: models.FieldMetadata{
				APIName:    "Average_Discount__c",
				Label:      "Average Discount",
				Type:       constants.FieldTypeFormula,
				ReturnType: &percent,
				Scale:      scale(2),
			},
			value: 67.083333,
			want:  "67.08%",
		},
		{
			name: "a percent field declaring nothing renders as it always has, with no invented decimals",
			field: models.FieldMetadata{
				APIName:    "Undeclared_Percent__c",
				Label:      "Undeclared Percent",
				Type:       constants.FieldTypeFormula,
				ReturnType: &percent,
			},
			value: 67.083333,
			want:  "67%",
		},
		{
			name: "declared zero decimals renders a whole percentage",
			field: models.FieldMetadata{
				APIName: "Whole_Percent__c",
				Label:   "Whole Percent",
				Type:    constants.FieldTypePercent,
				Scale:   scale(0),
			},
			value: 67.083333,
			want:  "67%",
		},
		{
			name: "declared scale beyond the default is honoured",
			field: models.FieldMetadata{
				APIName: "Fine_Percent__c",
				Label:   "Fine Percent",
				Type:    constants.FieldTypePercent,
				Scale:   scale(4),
			},
			value: 67.083333,
			want:  "67.0833%",
		},
		{
			// Asserted as a decimal count, not a literal: at scale 18 a float64
			// cannot represent 67.083333 exactly, and pinning the expansion would
			// enshrine those binary artifacts as intended output. What this case
			// exists to prove is that a declared 1000000 does not size the string.
			name: "an out-of-range declared scale is bounded before it sizes an allocation",
			field: models.FieldMetadata{
				APIName: "Absurd_Percent__c",
				Label:   "Absurd Percent",
				Type:    constants.FieldTypePercent,
				Scale:   scale(1000000),
			},
			value:        67.083333,
			wantDecimals: maxDeclaredScale,
		},
		{
			name: "a value that needs no rounding is padded to the declared scale",
			field: models.FieldMetadata{
				APIName: "Flat_Percent__c",
				Label:   "Flat Percent",
				Type:    constants.FieldTypePercent,
				Scale:   scale(2),
			},
			value: 31.5,
			want:  "31.50%",
		},
	} {
		t.Run(tc.name, func(t *testing.T) {
			stub := newUIAPITestContracts()
			stub.schema.Fields = append(stub.schema.Fields, tc.field)
			stub.records["001-a"][tc.field.APIName] = tc.value

			resp, err := uiAPIRecordUINeutralHandler(context.Background(), &dialect.Request{
				Version: "v63.0",
				Params:  map[string]string{"recordIds": "001-a"},
				Query:   map[string][]string{"type": {"Account"}},
			}, uiAPIDeps(stub, nil), nil, nil)
			if err != nil {
				t.Fatalf("handler error: %v", err)
			}
			if resp.Status != http.StatusOK {
				t.Fatalf("status = %d, want 200; body=%#v", resp.Status, resp.Body)
			}
			recordUI, ok := resp.Body.(*uiAPIRecordUI)
			if !ok {
				t.Fatalf("body type = %T, want *uiAPIRecordUI", resp.Body)
			}
			field := recordUI.Records["001-a"].Fields[tc.field.APIName]
			if field.DisplayValue == nil {
				t.Fatalf("%s displayValue is nil; body=%s", tc.field.APIName, mustJSON(t, resp.Body))
			}
			got := *field.DisplayValue
			if tc.want != "" && got != tc.want {
				t.Fatalf("%s displayValue = %q, want %q; body=%s", tc.field.APIName, got, tc.want, mustJSON(t, resp.Body))
			}
			if tc.wantDecimals > 0 {
				digits := strings.TrimSuffix(got, "%")
				idx := strings.Index(digits, ".")
				if idx < 0 {
					t.Fatalf("%s displayValue = %q, want %d decimals", tc.field.APIName, got, tc.wantDecimals)
				}
				if n := len(digits) - idx - 1; n != tc.wantDecimals {
					t.Fatalf("%s displayValue = %q has %d decimals, want %d", tc.field.APIName, got, n, tc.wantDecimals)
				}
			}
		})
	}
}
