package records

import (
	"context"
	"strings"

	"github.com/nexuscrm/kernel/pkg/utils"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/models"
)

type recycleBinDeleteLineage struct {
	operationID             string
	objectName              string
	recordID                string
	rootObjectName          string
	rootRecordID            string
	cascadeParentObjectName string
	cascadeParentRecordID   string
	cascadeFieldAPIName     string
	cascadeDepth            int
}

type recycleBinDeleteLineageKey struct{}

func recycleBinDeleteLineageFromContext(ctx context.Context) (recycleBinDeleteLineage, bool) {
	lineage, ok := ctx.Value(recycleBinDeleteLineageKey{}).(recycleBinDeleteLineage)
	return lineage, ok
}

func withRecycleBinRootDeleteLineage(ctx context.Context, objectName, recordID string) context.Context {
	objectName = strings.TrimSpace(objectName)
	recordID = strings.TrimSpace(recordID)
	if lineage, ok := recycleBinDeleteLineageFromContext(ctx); ok && lineage.appliesTo(objectName, recordID) {
		return ctx
	}
	return context.WithValue(ctx, recycleBinDeleteLineageKey{}, recycleBinDeleteLineage{
		operationID:    utils.GenerateID(),
		objectName:     objectName,
		recordID:       recordID,
		rootObjectName: objectName,
		rootRecordID:   recordID,
		cascadeDepth:   0,
	})
}

func withRecycleBinCascadeDeleteLineage(ctx context.Context, childObjectName, childRecordID, parentObjectName, parentRecordID, fieldAPIName string) context.Context {
	parentLineage, ok := recycleBinDeleteLineageFromContext(ctx)
	if !ok || parentLineage.operationID == "" {
		parentLineage = recycleBinDeleteLineage{
			operationID:    utils.GenerateID(),
			rootObjectName: strings.TrimSpace(parentObjectName),
			rootRecordID:   strings.TrimSpace(parentRecordID),
			cascadeDepth:   0,
		}
	}
	return context.WithValue(ctx, recycleBinDeleteLineageKey{}, recycleBinDeleteLineage{
		operationID:             parentLineage.operationID,
		objectName:              strings.TrimSpace(childObjectName),
		recordID:                strings.TrimSpace(childRecordID),
		rootObjectName:          parentLineage.rootObjectName,
		rootRecordID:            parentLineage.rootRecordID,
		cascadeParentObjectName: strings.TrimSpace(parentObjectName),
		cascadeParentRecordID:   strings.TrimSpace(parentRecordID),
		cascadeFieldAPIName:     strings.TrimSpace(fieldAPIName),
		cascadeDepth:            parentLineage.cascadeDepth + 1,
	})
}

func (l recycleBinDeleteLineage) appliesTo(objectName, recordID string) bool {
	return strings.EqualFold(strings.TrimSpace(l.objectName), strings.TrimSpace(objectName)) &&
		strings.EqualFold(strings.TrimSpace(l.recordID), strings.TrimSpace(recordID))
}

func recycleBinLineageFieldsFromContext(ctx context.Context) models.SObject {
	lineage, ok := recycleBinDeleteLineageFromContext(ctx)
	if !ok || lineage.operationID == "" {
		return nil
	}
	fields := models.SObject{
		constants.FieldSysRecycleBin_DeleteOperationID:       lineage.operationID,
		constants.FieldSysRecycleBin_DeleteRootObjectAPIName: lineage.rootObjectName,
		constants.FieldSysRecycleBin_DeleteRootRecordID:      lineage.rootRecordID,
		constants.FieldSysRecycleBin_CascadeDepth:            lineage.cascadeDepth,
	}
	if lineage.cascadeParentObjectName != "" {
		fields[constants.FieldSysRecycleBin_CascadeParentObjectAPIName] = lineage.cascadeParentObjectName
	}
	if lineage.cascadeParentRecordID != "" {
		fields[constants.FieldSysRecycleBin_CascadeParentRecordID] = lineage.cascadeParentRecordID
	}
	if lineage.cascadeFieldAPIName != "" {
		fields[constants.FieldSysRecycleBin_CascadeFieldAPIName] = lineage.cascadeFieldAPIName
	}
	return fields
}
