package metadata

import (
	"context"
	"encoding/json"
	"fmt"
	"reflect"
	"strings"

	apperrors "github.com/nexuscrm/kernel/pkg/errors"
	"github.com/nexuscrm/kernel/pkg/utils"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/contract"
	"github.com/nexuscrm/shared/pkg/events"
	"github.com/nexuscrm/shared/pkg/models"
)

type listViewAuthoringService interface {
	CreatePrivateWithID(ctx context.Context, user *models.UserSession, input *models.ListView, id string) (*models.ListView, error)
	ValidatePrivateWrite(ctx context.Context, user *models.UserSession) error
	GetPrivateForWrite(ctx context.Context, user *models.UserSession, id string) (*models.ListView, error)
	UpdatePrivate(ctx context.Context, user *models.UserSession, id string, patch models.ListViewPatch) (*models.ListView, error)
	DeletePrivate(ctx context.Context, user *models.UserSession, id string) error
	FindPrivateByDeveloperNameForWrite(ctx context.Context, user *models.UserSession, objectAPIName string, developerName string) (*models.ListView, bool, error)
}

type ListViewAuthoringContract struct {
	listViews listViewAuthoringService
	lifecycle contract.RecordLifecycleCoordinator
}

func NewListViewAuthoringContract(listViews listViewAuthoringService, lifecycle contract.RecordLifecycleCoordinator) *ListViewAuthoringContract {
	return &ListViewAuthoringContract{listViews: listViews, lifecycle: lifecycle}
}

func (s *ListViewAuthoringContract) CreatePrivate(ctx context.Context, user *models.UserSession, input *models.ListView) (*models.ListView, error) {
	if s == nil || s.listViews == nil {
		return nil, apperrors.NewInternalError("list view authoring service unavailable", nil)
	}
	if err := s.listViews.ValidatePrivateWrite(ctx, user); err != nil {
		return nil, err
	}
	generatedID := utils.GenerateID()
	var view *models.ListView
	err := s.runTransaction(ctx, func(txCtx context.Context) error {
		lifecycleRecord := listViewCreateLifecycleRecord(input, generatedID)
		if err := s.publishRecordEvent(txCtx, events.RecordBeforeCreate, lifecycleRecord, nil, user); err != nil {
			return err
		}
		lifecycleInput, err := listViewInputFromCreateLifecycleRecord(lifecycleRecord, generatedID)
		if err != nil {
			return err
		}
		created, err := s.listViews.CreatePrivateWithID(txCtx, user, lifecycleInput, generatedID)
		if err != nil {
			return err
		}
		view = created
		createdRecord := listViewToRecord(view)
		if err := s.runLifecycleHooks(txCtx, contract.RecordLifecycleAfterCreateInTx, contract.RecordLifecycleEvent{
			ObjectName:  constants.TableListView,
			RecordID:    listViewID(view),
			Record:      createdRecord,
			CurrentUser: user,
		}); err != nil {
			return err
		}
		return s.publishAfterSaveEvent(txCtx, events.RecordCreated, createdRecord, nil, user)
	})
	return view, err
}

func (s *ListViewAuthoringContract) UpdatePrivate(ctx context.Context, user *models.UserSession, id string, patch models.ListViewPatch) (*models.ListView, error) {
	if s == nil || s.listViews == nil {
		return nil, apperrors.NewInternalError("list view authoring service unavailable", nil)
	}
	var updated *models.ListView
	err := s.runTransaction(ctx, func(txCtx context.Context) error {
		existing, err := s.listViews.GetPrivateForWrite(txCtx, user, id)
		if err != nil {
			return err
		}
		oldRecord := listViewToRecord(existing)
		oldRecordForEvent := cloneRecord(oldRecord)
		lifecycleRecord := cloneRecord(oldRecord)
		applyListViewPatchToLifecycleRecord(lifecycleRecord, patch)
		if err := s.publishRecordEvent(txCtx, events.RecordBeforeUpdate, lifecycleRecord, &oldRecordForEvent, user); err != nil {
			return err
		}
		finalPatch, err := listViewPatchFromUpdateLifecycleRecord(lifecycleRecord, oldRecord)
		if err != nil {
			return err
		}
		txCtx, err = s.stageAfterSaveOldProjection(txCtx, id, user)
		if err != nil {
			return err
		}
		updated, err = s.listViews.UpdatePrivate(txCtx, user, id, finalPatch)
		if err != nil {
			return err
		}
		updatedRecord := listViewToRecord(updated)
		if err := s.runLifecycleHooks(txCtx, contract.RecordLifecycleAfterUpdateInTx, contract.RecordLifecycleEvent{
			ObjectName:  constants.TableListView,
			RecordID:    id,
			Record:      updatedRecord,
			OldRecord:   cloneRecord(oldRecord),
			CurrentUser: user,
		}); err != nil {
			return err
		}
		oldRecordForOutbox := cloneRecord(oldRecord)
		return s.publishAfterSaveEvent(txCtx, events.RecordUpdated, updatedRecord, &oldRecordForOutbox, user)
	})
	return updated, err
}

func (s *ListViewAuthoringContract) DeletePrivate(ctx context.Context, user *models.UserSession, id string) error {
	if s == nil || s.listViews == nil {
		return apperrors.NewInternalError("list view authoring service unavailable", nil)
	}
	return s.runTransaction(ctx, func(txCtx context.Context) error {
		existing, err := s.listViews.GetPrivateForWrite(txCtx, user, id)
		if err != nil {
			return err
		}
		oldRecord := listViewToRecord(existing)
		if err := s.publishRecordEvent(txCtx, events.RecordBeforeDelete, cloneRecord(oldRecord), nil, user); err != nil {
			return err
		}
		if err := s.listViews.DeletePrivate(txCtx, user, id); err != nil {
			return err
		}
		if err := s.runLifecycleHooks(txCtx, contract.RecordLifecycleAfterDeleteInTx, contract.RecordLifecycleEvent{
			ObjectName:  constants.TableListView,
			RecordID:    id,
			OldRecord:   cloneRecord(oldRecord),
			CurrentUser: user,
		}); err != nil {
			return err
		}
		return s.publishAfterSaveEvent(txCtx, events.RecordDeleted, cloneRecord(oldRecord), nil, user)
	})
}

func (s *ListViewAuthoringContract) UpsertPrivateByDeveloperName(ctx context.Context, user *models.UserSession, objectAPIName string, developerName string, input *models.ListView, patch models.ListViewPatch) (*models.ListView, bool, error) {
	if s == nil || s.listViews == nil {
		return nil, false, apperrors.NewInternalError("list view authoring service unavailable", nil)
	}
	objectAPIName = strings.TrimSpace(objectAPIName)
	if objectAPIName == "" {
		return nil, false, apperrors.NewValidationError(constants.FieldSysListView_ObjectAPIName, "object API name is required")
	}
	developerName = strings.TrimSpace(developerName)
	if developerName == "" {
		return nil, false, apperrors.NewValidationError(constants.FieldSysListView_DeveloperName, "developer name is required")
	}
	if err := s.listViews.ValidatePrivateWrite(ctx, user); err != nil {
		return nil, false, err
	}
	var view *models.ListView
	var created bool
	err := s.runTransaction(ctx, func(txCtx context.Context) error {
		existing, found, err := s.listViews.FindPrivateByDeveloperNameForWrite(txCtx, user, objectAPIName, developerName)
		if err != nil {
			return err
		}
		if !found {
			createInput := cloneListView(input)
			if createInput == nil {
				createInput = &models.ListView{}
			}
			createInput.ObjectAPIName = objectAPIName
			createInput.DeveloperName = &developerName
			generatedID := utils.GenerateID()
			lifecycleRecord := listViewCreateLifecycleRecord(createInput, generatedID)
			if err := s.publishRecordEvent(txCtx, events.RecordBeforeCreate, lifecycleRecord, nil, user); err != nil {
				return err
			}
			lifecycleInput, err := listViewInputFromCreateLifecycleRecord(lifecycleRecord, generatedID)
			if err != nil {
				return err
			}
			createdView, err := s.listViews.CreatePrivateWithID(txCtx, user, lifecycleInput, generatedID)
			if err != nil {
				return err
			}
			view = createdView
			created = true
			createdRecord := listViewToRecord(view)
			if err := s.runLifecycleHooks(txCtx, contract.RecordLifecycleAfterCreateInTx, contract.RecordLifecycleEvent{
				ObjectName:  constants.TableListView,
				RecordID:    listViewID(view),
				Record:      createdRecord,
				CurrentUser: user,
			}); err != nil {
				return err
			}
			return s.publishAfterSaveEvent(txCtx, events.RecordCreated, createdRecord, nil, user)
		}

		oldRecord := listViewToRecord(existing)
		oldRecordForEvent := cloneRecord(oldRecord)
		lifecycleRecord := cloneRecord(oldRecord)
		patch.DeveloperName = nil
		applyListViewPatchToLifecycleRecord(lifecycleRecord, patch)
		if err := s.publishRecordEvent(txCtx, events.RecordBeforeUpdate, lifecycleRecord, &oldRecordForEvent, user); err != nil {
			return err
		}
		finalPatch, err := listViewPatchFromUpdateLifecycleRecord(lifecycleRecord, oldRecord)
		if err != nil {
			return err
		}
		txCtx, err = s.stageAfterSaveOldProjection(txCtx, existing.ID, user)
		if err != nil {
			return err
		}
		updated, err := s.listViews.UpdatePrivate(txCtx, user, existing.ID, finalPatch)
		if err != nil {
			return err
		}
		view = updated
		created = false
		updatedRecord := listViewToRecord(updated)
		if err := s.runLifecycleHooks(txCtx, contract.RecordLifecycleAfterUpdateInTx, contract.RecordLifecycleEvent{
			ObjectName:  constants.TableListView,
			RecordID:    existing.ID,
			Record:      updatedRecord,
			OldRecord:   cloneRecord(oldRecord),
			CurrentUser: user,
		}); err != nil {
			return err
		}
		oldRecordForOutbox := cloneRecord(oldRecord)
		return s.publishAfterSaveEvent(txCtx, events.RecordUpdated, updatedRecord, &oldRecordForOutbox, user)
	})
	return view, created, err
}

func (s *ListViewAuthoringContract) runTransaction(ctx context.Context, fn func(context.Context) error) error {
	if s == nil || s.lifecycle == nil {
		return fn(ctx)
	}
	return s.lifecycle.RunInPessimisticTransaction(ctx, fn)
}

func (s *ListViewAuthoringContract) publishRecordEvent(ctx context.Context, eventType events.EventType, record contract.Record, oldRecord *contract.Record, user *models.UserSession) error {
	if s == nil || s.lifecycle == nil {
		return nil
	}
	return s.lifecycle.PublishRecordLifecycleEvent(listViewAuthoringLifecycleContext(ctx), eventType, constants.TableListView, record, oldRecord, user)
}

func (s *ListViewAuthoringContract) runLifecycleHooks(ctx context.Context, phase contract.RecordLifecyclePhase, event contract.RecordLifecycleEvent) error {
	if s == nil || s.lifecycle == nil {
		return nil
	}
	return s.lifecycle.RunRecordLifecycleHooks(listViewAuthoringLifecycleContext(ctx), phase, event)
}

func (s *ListViewAuthoringContract) stageAfterSaveOldProjection(ctx context.Context, recordID string, user *models.UserSession) (context.Context, error) {
	if s == nil || s.lifecycle == nil {
		return ctx, nil
	}
	return s.lifecycle.StageRecordAfterSaveOldProjection(listViewAuthoringLifecycleContext(ctx), constants.TableListView, recordID, user)
}

func (s *ListViewAuthoringContract) publishAfterSaveEvent(ctx context.Context, eventType events.EventType, record contract.Record, oldRecord *contract.Record, user *models.UserSession) error {
	if s == nil || s.lifecycle == nil {
		return nil
	}
	return s.lifecycle.PublishRecordAfterSaveEvent(listViewAuthoringLifecycleContext(ctx), eventType, constants.TableListView, record, oldRecord, user)
}

func listViewAuthoringLifecycleContext(ctx context.Context) context.Context {
	return constants.WithSecurityContext(ctx, constants.SystemContext, "private list view authoring lifecycle")
}

func listViewCreateLifecycleRecord(input *models.ListView, generatedID string) contract.Record {
	record := listViewToRecord(input)
	if record == nil {
		record = contract.Record{}
	}
	record[constants.FieldID] = generatedID
	return record
}

func listViewInputFromCreateLifecycleRecord(record contract.Record, generatedID string) (*models.ListView, error) {
	if err := validateListViewLifecycleGeneratedID(record, generatedID); err != nil {
		return nil, err
	}
	createRecord := cloneRecord(record)
	removeListViewRecordField(createRecord, constants.FieldID)
	return listViewFromRecord(createRecord)
}

func validateListViewLifecycleGeneratedID(record contract.Record, generatedID string) error {
	id, ok := listViewRecordString(record, constants.FieldID)
	if !ok || strings.TrimSpace(id) == "" {
		return apperrors.NewValidationError(constants.FieldID, "Id cannot be removed by private list view lifecycle")
	}
	if strings.TrimSpace(id) != strings.TrimSpace(generatedID) {
		return apperrors.NewValidationError(constants.FieldID, "Id cannot be changed by private list view lifecycle")
	}
	return nil
}

func applyListViewPatchToLifecycleRecord(record contract.Record, patch models.ListViewPatch) {
	if record == nil {
		return
	}
	if patch.Label != nil {
		record[constants.FieldSysListView_Label] = *patch.Label
	}
	if patch.FilterExpr != nil {
		record[constants.FieldSysListView_FilterExpr] = *patch.FilterExpr
	}
	if patch.FilterLogic != nil {
		record[constants.FieldSysListView_FilterLogic] = *patch.FilterLogic
	}
	if patch.SortField != nil {
		record[constants.FieldSysListView_SortField] = *patch.SortField
	}
	if patch.SortDirection != nil {
		record[constants.FieldSysListView_SortDirection] = *patch.SortDirection
	}
	if patch.Fields != nil {
		record[constants.FieldSysListView_Fields] = copyStringSlice(*patch.Fields)
	}
	if patch.DeveloperName != nil {
		record[constants.FieldSysListView_DeveloperName] = *patch.DeveloperName
	}
}

func listViewPatchFromUpdateLifecycleRecord(record contract.Record, oldRecord contract.Record) (models.ListViewPatch, error) {
	if err := validateListViewUpdateLifecycleRecord(record, oldRecord); err != nil {
		return models.ListViewPatch{}, err
	}
	var patch models.ListViewPatch
	if listViewLifecycleStringChanged(record, oldRecord, constants.FieldSysListView_Label) {
		value, _ := listViewRecordString(record, constants.FieldSysListView_Label)
		patch.Label = &value
	}
	if listViewLifecycleStringChanged(record, oldRecord, constants.FieldSysListView_FilterExpr) {
		value, _ := listViewRecordString(record, constants.FieldSysListView_FilterExpr)
		patch.FilterExpr = &value
	}
	if listViewLifecycleStringChanged(record, oldRecord, constants.FieldSysListView_FilterLogic) {
		value, _ := listViewRecordString(record, constants.FieldSysListView_FilterLogic)
		patch.FilterLogic = &value
	}
	if listViewLifecycleStringChanged(record, oldRecord, constants.FieldSysListView_SortField) {
		value, _ := listViewRecordString(record, constants.FieldSysListView_SortField)
		patch.SortField = &value
	}
	if listViewLifecycleStringChanged(record, oldRecord, constants.FieldSysListView_SortDirection) {
		value, _ := listViewRecordString(record, constants.FieldSysListView_SortDirection)
		patch.SortDirection = &value
	}
	fieldsChanged, fields, err := listViewLifecycleFieldsChanged(record, oldRecord)
	if err != nil {
		return models.ListViewPatch{}, err
	}
	if fieldsChanged {
		patch.Fields = &fields
	}
	if listViewLifecycleStringChanged(record, oldRecord, constants.FieldSysListView_DeveloperName) {
		value, _ := listViewRecordString(record, constants.FieldSysListView_DeveloperName)
		patch.DeveloperName = &value
	}
	return patch, nil
}

func validateListViewUpdateLifecycleRecord(record contract.Record, oldRecord contract.Record) error {
	for key := range record {
		if key == "attributes" || key == models.ObjectTypeMetadataKey {
			continue
		}
		switch {
		case strings.EqualFold(key, constants.FieldID):
			if listViewLifecycleStringChanged(record, oldRecord, constants.FieldID) {
				return apperrors.NewValidationError(constants.FieldID, "Id cannot be updated")
			}
		case strings.EqualFold(key, constants.FieldSysListView_ObjectAPIName):
			if listViewLifecycleStringChanged(record, oldRecord, constants.FieldSysListView_ObjectAPIName) {
				return apperrors.NewValidationError(constants.FieldSysListView_ObjectAPIName, "ObjectApiName cannot be updated")
			}
		case strings.EqualFold(key, constants.FieldSysListView_OwnerID):
			if listViewLifecycleStringChanged(record, oldRecord, constants.FieldSysListView_OwnerID) {
				return apperrors.NewValidationError(constants.FieldSysListView_OwnerID, "OwnerId cannot be authored for private list views")
			}
		case strings.EqualFold(key, constants.FieldSysListView_Visibility):
			if listViewLifecycleStringChanged(record, oldRecord, constants.FieldSysListView_Visibility) {
				return apperrors.NewValidationError(constants.FieldSysListView_Visibility, "Visibility cannot be updated")
			}
		case strings.EqualFold(key, constants.FieldSysListView_Label),
			strings.EqualFold(key, constants.FieldSysListView_FilterExpr),
			strings.EqualFold(key, constants.FieldSysListView_FilterLogic),
			strings.EqualFold(key, constants.FieldSysListView_SortField),
			strings.EqualFold(key, constants.FieldSysListView_SortDirection),
			strings.EqualFold(key, constants.FieldSysListView_Fields),
			strings.EqualFold(key, constants.FieldSysListView_DeveloperName):
		default:
			return apperrors.NewValidationError(key, fmt.Sprintf("field %q is not supported for private list view authoring", key))
		}
	}
	return nil
}

func listViewLifecycleStringChanged(record contract.Record, oldRecord contract.Record, field string) bool {
	value, ok := listViewRecordString(record, field)
	oldValue, oldOK := listViewRecordString(oldRecord, field)
	if !ok && !oldOK {
		return false
	}
	return ok != oldOK || value != oldValue
}

func listViewLifecycleFieldsChanged(record contract.Record, oldRecord contract.Record) (bool, []string, error) {
	fields, ok, err := listViewRecordFields(record, constants.FieldSysListView_Fields)
	if err != nil {
		return false, nil, err
	}
	oldFields, oldOK, err := listViewRecordFields(oldRecord, constants.FieldSysListView_Fields)
	if err != nil {
		return false, nil, err
	}
	if !ok && !oldOK {
		return false, nil, nil
	}
	if !reflect.DeepEqual(fields, oldFields) {
		return true, copyStringSlice(fields), nil
	}
	return false, nil, nil
}

func removeListViewRecordField(record contract.Record, field string) {
	for key := range record {
		if strings.EqualFold(strings.TrimSpace(key), field) {
			delete(record, key)
		}
	}
}

func listViewID(view *models.ListView) string {
	if view == nil {
		return ""
	}
	return view.ID
}

func listViewFromRecord(record contract.Record) (*models.ListView, error) {
	if err := validateListViewRecordFields(record, false); err != nil {
		return nil, err
	}
	view := &models.ListView{}
	if value, ok := listViewRecordString(record, constants.FieldID); ok {
		view.ID = value
	}
	if value, ok := listViewRecordString(record, constants.FieldSysListView_ObjectAPIName); ok {
		view.ObjectAPIName = value
	}
	if value, ok := listViewRecordString(record, constants.FieldSysListView_Label); ok {
		view.Label = value
	}
	if value, ok := listViewRecordString(record, constants.FieldSysListView_FilterExpr); ok {
		view.FilterExpr = value
	}
	if value, ok := listViewRecordString(record, constants.FieldSysListView_FilterLogic); ok {
		view.FilterLogic = value
	}
	if value, ok := listViewRecordString(record, constants.FieldSysListView_SortField); ok {
		view.SortField = value
	}
	if value, ok := listViewRecordString(record, constants.FieldSysListView_SortDirection); ok {
		view.SortDirection = value
	}
	if fields, ok, err := listViewRecordFields(record, constants.FieldSysListView_Fields); err != nil {
		return nil, err
	} else if ok {
		view.Fields = fields
	}
	if value, ok := listViewRecordString(record, constants.FieldSysListView_Visibility); ok {
		view.Visibility = &value
	}
	if value, ok := listViewRecordString(record, constants.FieldSysListView_DeveloperName); ok {
		view.DeveloperName = &value
	}
	return view, nil
}

func validateListViewRecordFields(record contract.Record, allowID bool) error {
	for key := range record {
		if key == "attributes" || key == models.ObjectTypeMetadataKey {
			continue
		}
		switch {
		case strings.EqualFold(key, constants.FieldSysListView_ObjectAPIName),
			strings.EqualFold(key, constants.FieldSysListView_Label),
			strings.EqualFold(key, constants.FieldSysListView_FilterExpr),
			strings.EqualFold(key, constants.FieldSysListView_FilterLogic),
			strings.EqualFold(key, constants.FieldSysListView_SortField),
			strings.EqualFold(key, constants.FieldSysListView_SortDirection),
			strings.EqualFold(key, constants.FieldSysListView_Fields),
			strings.EqualFold(key, constants.FieldSysListView_DeveloperName):
		case strings.EqualFold(key, constants.FieldSysListView_Visibility):
		case strings.EqualFold(key, constants.FieldID):
			if !allowID {
				return apperrors.NewValidationError(constants.FieldID, "Id cannot be authored for private list views")
			}
		case strings.EqualFold(key, constants.FieldSysListView_OwnerID):
			return apperrors.NewValidationError(constants.FieldSysListView_OwnerID, "OwnerId cannot be authored for private list views")
		default:
			return apperrors.NewValidationError(key, fmt.Sprintf("field %q is not supported for private list view authoring", key))
		}
	}
	return nil
}

func listViewRecordString(record contract.Record, field string) (string, bool) {
	value, ok := listViewRecordValue(record, field)
	if !ok || value == nil {
		return "", ok
	}
	switch typed := value.(type) {
	case string:
		return typed, true
	default:
		return fmt.Sprintf("%v", typed), true
	}
}

func listViewRecordFields(record contract.Record, field string) ([]string, bool, error) {
	value, ok := listViewRecordValue(record, field)
	if !ok {
		return nil, false, nil
	}
	switch typed := value.(type) {
	case nil:
		return nil, true, nil
	case []string:
		return copyStringSlice(typed), true, nil
	case []interface{}:
		out := make([]string, 0, len(typed))
		for _, item := range typed {
			s, ok := item.(string)
			if !ok {
				return nil, true, apperrors.NewValidationError(field, "Fields must be an array of strings")
			}
			out = append(out, s)
		}
		return out, true, nil
	case string:
		raw := strings.TrimSpace(typed)
		if raw == "" {
			return []string{}, true, nil
		}
		var decoded []string
		if err := json.Unmarshal([]byte(raw), &decoded); err != nil {
			return nil, true, apperrors.NewValidationError(field, "Fields must be an array of strings")
		}
		return decoded, true, nil
	default:
		return nil, true, apperrors.NewValidationError(field, "Fields must be an array of strings")
	}
}

func listViewRecordValue(record contract.Record, field string) (interface{}, bool) {
	if record == nil {
		return nil, false
	}
	for key, value := range record {
		if strings.EqualFold(strings.TrimSpace(key), field) {
			return value, true
		}
	}
	return nil, false
}

func listViewToRecord(view *models.ListView) contract.Record {
	if view == nil {
		return nil
	}
	record := contract.Record{
		constants.FieldID:                        view.ID,
		constants.FieldSysListView_ObjectAPIName: view.ObjectAPIName,
		constants.FieldSysListView_Label:         view.Label,
		constants.FieldSysListView_FilterExpr:    view.FilterExpr,
		constants.FieldSysListView_FilterLogic:   view.FilterLogic,
		constants.FieldSysListView_SortField:     view.SortField,
		constants.FieldSysListView_SortDirection: view.SortDirection,
		constants.FieldSysListView_Fields:        copyStringSlice(view.Fields),
	}
	if view.OwnerID != nil {
		record[constants.FieldSysListView_OwnerID] = *view.OwnerID
	}
	if view.Visibility != nil {
		record[constants.FieldSysListView_Visibility] = *view.Visibility
	}
	if view.DeveloperName != nil {
		record[constants.FieldSysListView_DeveloperName] = *view.DeveloperName
	}
	return record
}

func cloneRecord(record contract.Record) contract.Record {
	if record == nil {
		return nil
	}
	out := make(contract.Record, len(record))
	for key, value := range record {
		out[key] = value
	}
	return out
}
