package dialectsfcrm

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
	"strings"

	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/models"
	semantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/recordsv1"
)

// SelectedRootReadFunc is the app-blind semantic call supplied by the L0
// Runtime transport client. The sfcrm adapter owns only product projection.
type SelectedRootReadFunc func(context.Context, semantic.Request) (semantic.Response, error)

// RuntimeSelectedRootClient is the dormant P4 sfcrm consumer. It is not
// registered as a route owner; P5 must explicitly fence any route cutover.
type RuntimeSelectedRootClient struct {
	read SelectedRootReadFunc
}

func NewRuntimeSelectedRootClient(read SelectedRootReadFunc) (*RuntimeSelectedRootClient, error) {
	if read == nil {
		return nil, errors.New("sfcrm selected-root client: Runtime reader is required")
	}
	return &RuntimeSelectedRootClient{read: read}, nil
}

// Read calls Runtime exactly once and projects the complete authorized root
// result into the Salesforce record shape. Lookup labels, related records,
// relationship nesting, decoration, and activity tracking remain out of scope.
func (c *RuntimeSelectedRootClient) Read(ctx context.Context, apiVersion, objectID, recordID string, selectedRootFields []string, minCatalogRevision *uint64) (models.SObject, semantic.Receipts, error) {
	if c == nil || c.read == nil {
		return nil, semantic.Receipts{}, &semantic.Failure{Category: semantic.FailureUnavailable}
	}
	response, err := c.read(ctx, semantic.Request{
		ObjectID: objectID, RecordID: recordID,
		SelectedRootFields: append([]string(nil), selectedRootFields...),
		MinCatalogRevision: minCatalogRevision,
	})
	if err != nil {
		return nil, semantic.Receipts{}, err
	}
	record := make(models.SObject, len(response.Fields)+2)
	record[constants.FieldID] = response.RecordID
	for _, field := range response.Fields {
		value, err := selectedRootCRMValue(field)
		if err != nil {
			return nil, semantic.Receipts{}, err
		}
		record[field.Name] = value
	}
	stampSObjectRecordResponseAttributes(record, objectID, response.RecordID, apiVersion)
	return record, response.Receipts, nil
}

func selectedRootCRMValue(field semantic.Field) (any, error) {
	if field.Null {
		return nil, nil
	}
	switch field.Kind {
	case semantic.ValueKindString:
		if field.String != nil {
			return *field.String, nil
		}
	case semantic.ValueKindBoolean:
		if field.Boolean != nil {
			return *field.Boolean, nil
		}
	case semantic.ValueKindInteger:
		if field.Integer != nil {
			return *field.Integer, nil
		}
	case semantic.ValueKindDecimal:
		if field.Decimal != nil {
			value, err := formatSelectedRootDecimal(*field.Decimal)
			return json.Number(value), err
		}
	case semantic.ValueKindDate:
		if field.Date != nil {
			return *field.Date, nil
		}
	case semantic.ValueKindDateTime:
		if field.DateTime != nil {
			return *field.DateTime, nil
		}
	case semantic.ValueKindReference:
		if field.Reference != nil {
			return *field.Reference, nil
		}
	}
	return nil, fmt.Errorf("sfcrm selected-root client: invalid value for field %q", field.Name)
}

func formatSelectedRootDecimal(value semantic.Decimal) (string, error) {
	coefficient := value.Coefficient
	negative := strings.HasPrefix(coefficient, "-")
	digits := strings.TrimPrefix(coefficient, "-")
	if digits == "" {
		return "", errors.New("sfcrm selected-root client: decimal coefficient is empty")
	}
	if value.Scale == 0 {
		return coefficient, nil
	}
	plainPrefixBytes := uint64(2) // "0."
	if negative {
		plainPrefixBytes++
	}
	if uint64(value.Scale)+plainPrefixBytes > uint64(semantic.MaxSemanticResponseBytes) {
		return coefficient + "e-" + strconv.FormatUint(uint64(value.Scale), 10), nil
	}
	scale := int(value.Scale)
	if len(digits) <= scale {
		digits = strings.Repeat("0", scale-len(digits)+1) + digits
	}
	point := len(digits) - scale
	result := digits[:point] + "." + digits[point:]
	if negative {
		result = "-" + result
	}
	return result, nil
}
