package permissions

import (
	"context"
	"log"
	"strings"

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

// isApprovalLockedForOperation enforces pending-approval record editability.
// The lock is dynamic: records are considered locked while a ProcessInstance is
// pending, and automatically unlock once the instance leaves Pending.
func (ps *PermissionService) isApprovalLockedForOperation(ctx context.Context, record models.SObject, operation string, user *models.UserSession) bool {
	if operation == constants.PermRead || user == nil || ps.repo == nil || ps.canBypassApprovalLock(ctx, user) {
		return false
	}

	recordID, _ := record[constants.FieldID].(string)
	if strings.TrimSpace(recordID) == "" {
		return false
	}
	if cache := recordAccessEvaluationCacheFromContext(ctx); cache != nil {
		return cache.approvalLock(ctx, recordID, user.ID, func() bool {
			return ps.loadApprovalLockedForOperation(ctx, recordID, user)
		})
	}
	return ps.loadApprovalLockedForOperation(ctx, recordID, user)
}

func (ps *PermissionService) loadApprovalLockedForOperation(ctx context.Context, recordID string, user *models.UserSession) bool {

	processInstanceID, lockType, err := ps.repo.GetPendingApprovalLockInfo(ctx, recordID)
	if err != nil {
		// A DB error means we cannot confirm the record is unlocked — fail closed.
		// Log so operators can detect infrastructure issues; do not silently bypass
		// pending-approval locks on repository failures.
		log.Printf("Warning: GetPendingApprovalLockInfo failed for record %s: %v; treating as locked (fail-closed)", recordID, err)
		return true
	}
	if strings.TrimSpace(lockType) == "" {
		return false
	}

	switch strings.ToLower(strings.TrimSpace(lockType)) {
	case "workitem":
		if strings.TrimSpace(processInstanceID) == "" {
			return true
		}
		hasWorkitem, workitemErr := ps.repo.HasPendingApprovalWorkitemForUser(ctx, processInstanceID, user.ID)
		if workitemErr != nil {
			log.Printf("Warning: HasPendingApprovalWorkitemForUser error for processInstance %s: %v", processInstanceID, workitemErr)
			return true
		}
		return !hasWorkitem
	case "admin":
		return true
	default:
		return true
	}
}
