package dialectsfcrm

import (
	"context"

	"github.com/nexuscrm/shared/pkg/contract"
	"github.com/nexuscrm/shared/pkg/models"
)

// recordTypeUnavailableInEffectiveAccess reports whether a specific recordTypeID
// is present in the caller's effective access but flagged unavailable. A missing
// recordTypeID (not in the access set) is NOT treated as unavailable here — the
// caller's resolver decides; this gate fires only on an explicit "present but
// unavailable" verdict, matching the legacy layout-describe 403.
func recordTypeUnavailableInEffectiveAccess(access *contract.EffectiveObjectAccess, recordTypeID string) bool {
	if access == nil {
		return false
	}
	for _, rt := range access.RecordTypes {
		if rt.ID == recordTypeID {
			return !rt.Available
		}
	}
	return false
}

// convertStoredLayoutToSFFormat converts a stored PageLayout into the
// Salesforce-compatible JSON response shape used by the layouts describe routes.
// The wire projection (detail/edit/sections + related-list shell) is L1/CRM
// vocabulary and lives in this module; the raw *models.PageLayout it consumes is
// neutral substrate handed across the contract.
//
// Behavior-blind on purpose. sec.FieldBehaviors narrows the UI API layout
// response per mode (dialect-sf-crm/ui_api.go, NexusCRM#3506), and this
// converter deliberately does not apply it: describe/layouts reports the layout
// as authored, so an external client asking what a layout CONTAINS gets the
// stored answer, not one form's rendering of it. Owner ruling on #3506.
//
// The divergence is therefore visible and intended: with {"Rating__c":
// {"edit":"hidden"}} authored, GET /ui-api/layout?type=Edit omits the item while
// describe/layouts still lists Rating__c in editLayoutSections and in
// sections[].fields. This surface already answers a different question in the
// same direction — it derives required/createable/updateable from the schema and
// applies no FLS — so a caller that needs the rendered form must read the UI API
// endpoint, which is the only one that projects one.
func convertStoredLayoutToSFFormat(layout *models.PageLayout, schema *models.ObjectMetadata, relatedLists []map[string]any) map[string]any {
	// Build a field metadata lookup for the schema.
	fieldMap := make(map[string]models.FieldMetadata, len(schema.Fields))
	for _, f := range schema.Fields {
		fieldMap[f.APIName] = f
	}

	// Build SF-format sections from stored layout sections.
	sfDetailSections := make([]map[string]any, 0, len(layout.Sections))
	sfSections := make([]map[string]any, 0, len(layout.Sections))
	for _, sec := range layout.Sections {
		layoutItems := make([]map[string]interface{}, 0, len(sec.Fields))
		for _, fieldName := range sec.Fields {
			f, ok := fieldMap[fieldName]
			if !ok {
				continue
			}
			layoutItems = append(layoutItems, map[string]interface{}{
				"editableForNew":    f.Createable,
				"editableForUpdate": f.Updateable,
				"field":             f.APIName,
				"label":             f.Label,
				"required":          f.Required,
			})
		}
		sfDetailSections = append(sfDetailSections, map[string]any{
			"heading":    sec.Label,
			"columns":    sec.Columns,
			"rows":       len(layoutItems),
			"useHeading": true,
			"layoutRows": []map[string]any{
				{"layoutItems": layoutItems},
			},
		})
		sfSections = append(sfSections, map[string]any{
			"id":      sec.ID,
			"label":   sec.Label,
			"columns": sec.Columns,
			"fields":  sec.Fields,
		})
	}

	return map[string]any{
		"id":                   layout.ID,
		"name":                 layout.LayoutName,
		"detailLayoutSections": sfDetailSections,
		"editLayoutSections":   sfDetailSections,
		"relatedLists":         relatedLists,
		"sections":             sfSections,
	}
}

// storedLayoutRelatedListsToSFFormat converts stored RelatedListConfig items into
// the Salesforce-compatible wire shape used by layouts describe responses. The
// virtual-related-list "resolution" annotation is sourced through the neutral
// contract (ResolveRelatedListResolution); the CRM pack-rule SSoT stays in the
// backend pack-rule cache below the seam.
func storedLayoutRelatedListsToSFFormat(ctx context.Context, metadata contract.Metadata, rls []models.RelatedListConfig) []map[string]any {
	result := make([]map[string]any, 0, len(rls))
	for _, rl := range rls {
		entry := map[string]any{
			"accessLevel": nil,
			"buttons":     []interface{}{},
			"columns": []map[string]any{
				{"field": "name", "format": nil, "label": "Name", "lookupId": "id", "name": "name", "sortable": true, "type": "url"},
			},
			"custom":         false,
			"field":          rl.LookupField,
			"label":          rl.Label,
			"secondaryLabel": rl.SecondaryLabel,
			"limitRows":      5,
			"name":           rl.Label,
			"sobject":        rl.ObjectAPIName,
			"sort":           []interface{}{},
		}
		if res, ok := metadata.ResolveRelatedListResolution(ctx, rl.ObjectAPIName, rl.LookupField); ok && res != nil {
			entry["resolution"] = res
		}
		result = append(result, entry)
	}
	return result
}
