package metadata

import (
	"context"
	"fmt"
	"strings"

	apperrors "github.com/nexuscrm/backend/pkg/errors"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/models"
)

// --- Validation Rule CRUD ---

// CreateValidationRule creates a new validation rule
func (ms *MetadataService) CreateValidationRule(ctx context.Context, rule *models.ValidationRule) error {
	ms.mu.Lock()
	defer ms.mu.Unlock()

	// Validate
	rule.ObjectAPIName = strings.ToLower(rule.ObjectAPIName)
	if rule.ObjectAPIName == "" {
		return apperrors.NewValidationError("object_api_name", "object API name is required")
	}
	if rule.Name == "" {
		return apperrors.NewValidationError("name", "rule name is required")
	}
	if rule.Condition == "" {
		return apperrors.NewValidationError("condition", "error condition formula is required")
	}
	if rule.ErrorMessage == "" {
		return apperrors.NewValidationError("error_message", "error message is required")
	}

	if rule.Description != nil {
		trimmed := strings.TrimSpace(*rule.Description)
		if trimmed == "" {
			rule.Description = nil
		} else {
			rule.Description = &trimmed
		}
	}
	if rule.ErrorDisplayField != nil {
		trimmed := strings.TrimSpace(*rule.ErrorDisplayField)
		if trimmed == "" {
			rule.ErrorDisplayField = nil
		} else {
			rule.ErrorDisplayField = &trimmed
		}
	}

	if rule.ID == "" {
		rule.ID = GenerateID()
	}
	rule.IsCustomized = true

	// Check for duplicate (object_api_name, name) - this matches the unique constraint
	exists, err := ms.repo.CheckValidationRuleExists(ctx, rule.ObjectAPIName, rule.Name)
	if err != nil {
		return apperrors.NewInternalError("failed to check for existing validation rule", err)
	}
	if exists {
		return apperrors.NewConflictError("ValidationRule", constants.FieldName, rule.Name)
	}

	if err := ms.repo.CreateValidationRule(ctx, rule); err != nil {
		return apperrors.NewInternalError("failed to insert validation rule", err)
	}

	// Invalidate cache
	ms.invalidateCacheLocked()
	return nil
}

// UpdateValidationRule updates an existing validation rule
func (ms *MetadataService) UpdateValidationRule(ctx context.Context, id string, updates *models.ValidationRule) error {
	ms.mu.Lock()
	defer ms.mu.Unlock()

	// Find the rule in DB
	existingRule, err := ms.repo.GetValidationRule(ctx, id)
	if err != nil {
		return apperrors.NewInternalError("failed to get validation rule", err)
	}
	if existingRule == nil {
		return apperrors.NewNotFoundError("ValidationRule", id)
	}

	// If name is changing, check for conflicts
	if updates.Name != "" && updates.Name != existingRule.Name {
		exists, err := ms.repo.CheckValidationRuleExists(ctx, existingRule.ObjectAPIName, updates.Name)
		if err != nil {
			return apperrors.NewInternalError("failed to check for existing validation rule", err)
		}
		if exists {
			return apperrors.NewConflictError("ValidationRule", constants.FieldName, updates.Name)
		}
		existingRule.Name = updates.Name
	}

	// Active is boolean
	existingRule.Active = updates.Active
	existingRule.IsCustomized = true

	if updates.Condition != "" {
		existingRule.Condition = updates.Condition
	}
	if updates.ErrorMessage != "" {
		existingRule.ErrorMessage = updates.ErrorMessage
	}
	if updates.Description != nil {
		trimmed := strings.TrimSpace(*updates.Description)
		if trimmed == "" {
			existingRule.Description = nil
		} else {
			existingRule.Description = &trimmed
		}
	}
	if updates.ErrorDisplayField != nil {
		trimmed := strings.TrimSpace(*updates.ErrorDisplayField)
		if trimmed == "" {
			existingRule.ErrorDisplayField = nil
		} else {
			existingRule.ErrorDisplayField = &trimmed
		}
	}

	// Update DB
	if err := ms.repo.UpdateValidationRule(ctx, id, existingRule); err != nil {
		return apperrors.NewInternalError("failed to update validation rule", err)
	}

	// Invalidate cache
	ms.invalidateCacheLocked()
	return nil
}

// DeleteValidationRule deletes a validation rule
func (ms *MetadataService) DeleteValidationRule(ctx context.Context, id string) error {
	ms.mu.Lock()
	defer ms.mu.Unlock()

	if err := ms.repo.DeleteValidationRule(ctx, id); err != nil {
		return apperrors.NewInternalError("failed to delete validation rule", err)
	}

	// Invalidate cache
	ms.invalidateCacheLocked()
	return nil
}

// ValidateMaxMasterDetailFields checks if an object can accept another Master-Detail field
// Limit is 2 per object (Standard PaaS limit)
// Returns error if limit reached
func (ms *MetadataService) ValidateMaxMasterDetailFields(obj *models.ObjectMetadata, excludeField string) error {
	count := 0
	for _, f := range obj.Fields {
		// Build a count of EXISTING master-detail fields
		if f.IsMasterDetail {
			// If we are updating a field, don't count itself (if it was already MD)
			// But usually this logic is for "Add New" or "Change Type to MD"
			if excludeField != "" && strings.EqualFold(f.APIName, excludeField) {
				continue
			}
			count++
		}
	}

	if count >= 2 {
		return apperrors.NewValidationError("is_master_detail", fmt.Sprintf("Object '%s' already has the maximum of 2 Master-Detail relationships", obj.APIName))
	}

	return nil
}
