package main

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

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

func classifyRecipients(recipientsJSON string) []RecipientInventoryItem {
	recipientsJSON = strings.TrimSpace(recipientsJSON)
	if recipientsJSON == "" || recipientsJSON == "[]" {
		return nil
	}
	var entries []recipientEntry
	if err := json.Unmarshal([]byte(recipientsJSON), &entries); err != nil {
		return []RecipientInventoryItem{{
			Classification: "unsupported",
			BlockedReason:  fmt.Sprintf("Recipients JSON is invalid: %v", err),
		}}
	}
	out := make([]RecipientInventoryItem, 0, len(entries))
	for _, entry := range entries {
		item := RecipientInventoryItem{
			Type:      strings.TrimSpace(entry.Type),
			Recipient: strings.TrimSpace(entry.Recipient),
			Field:     strings.TrimSpace(entry.Field),
		}
		switch strings.ToLower(item.Type) {
		case "email":
			if item.Recipient != "" {
				address, ok := validateCanonicalSendEmailAddress(item.Recipient)
				if !ok {
					item.Classification = "unsupported"
					item.BlockedReason = fmt.Sprintf("literal email recipient %q is not valid for canonical sendEmail.to", item.Recipient)
					break
				}
				item.Recipient = address
				item.Classification = "literal_email"
				item.TargetHint = "direct sendEmail.to literal"
			} else if item.Field != "" {
				item.Classification = "needs_resolver"
				item.TargetHint = "resolveEmailRecipients emails:Record." + item.Field
			} else {
				item.Classification = "unsupported"
				item.BlockedReason = "email recipient has neither a literal address nor a field path"
			}
		case "user":
			if item.Recipient == "" {
				item.Classification = "unsupported"
				item.BlockedReason = "user recipient is missing a User identifier"
			} else if strings.Contains(item.Recipient, "@") {
				address, ok := validateCanonicalSendEmailAddress(item.Recipient)
				if !ok {
					item.Classification = "unsupported"
					item.BlockedReason = fmt.Sprintf("user recipient %q looks like a literal email but is not valid for canonical sendEmail.to", item.Recipient)
					break
				}
				item.Recipient = address
				item.Classification = "literal_email"
				item.TargetHint = "direct sendEmail.to literal"
			} else if !isSingleRecipientIdentifier(item.Recipient) {
				item.Classification = "unsupported"
				item.BlockedReason = fmt.Sprintf("user recipient %q is not a single User ID value for resolveEmailRecipients userIds", item.Recipient)
			} else {
				item.Classification = "needs_resolver"
				item.TargetHint = "resolveEmailRecipients userIds:" + item.Recipient
			}
		case "owner":
			item.Field = constants.FieldOwnerID
			item.Classification = "needs_resolver"
			item.TargetHint = "resolveEmailRecipients userIds:Record." + constants.FieldOwnerID
		case "role":
			if item.Recipient == "" {
				item.Classification = "unsupported"
				item.BlockedReason = "role recipient is missing a role name"
			} else {
				item.Classification = "unsupported"
				item.BlockedReason = fmt.Sprintf("role recipient %q uses a legacy role name, but resolveEmailRecipients only accepts role IDs", item.Recipient)
			}
		case "group":
			if item.Recipient == "" {
				item.Classification = "unsupported"
				item.BlockedReason = "group recipient is missing a group name"
			} else {
				item.Classification = "unsupported"
				item.BlockedReason = fmt.Sprintf("group recipient %q uses a legacy group name, but resolveEmailRecipients only accepts group IDs", item.Recipient)
			}
		case "userlookup":
			if item.Field == "" {
				item.Classification = "unsupported"
				item.BlockedReason = "userlookup recipient is missing a field path"
			} else if strings.Contains(item.Field, ".") {
				item.Classification = "unsupported"
				item.BlockedReason = fmt.Sprintf("userlookup recipient field %s uses dotted path traversal, but WorkflowAlert userlookup runtime and resolveEmailRecipients only accept direct User ID fields", item.Field)
			} else {
				item.Classification = "needs_resolver"
				item.TargetHint = "resolveEmailRecipients userIds:Record." + item.Field
			}
		default:
			item.Classification = "unsupported"
			item.BlockedReason = fmt.Sprintf("recipient type %q is not supported by the migration classifier", item.Type)
		}
		out = append(out, item)
	}
	return out
}

func isSingleRecipientIdentifier(value string) bool {
	value = strings.TrimSpace(value)
	return value != "" && !strings.ContainsAny(value, " \t\r\n,<>;")
}

func isLiteralUserIDRecipient(recipient RecipientInventoryItem) bool {
	return strings.EqualFold(strings.TrimSpace(recipient.Type), "user") &&
		recipient.Classification == "needs_resolver" &&
		recipient.BlockedReason == "" &&
		strings.TrimSpace(recipient.Recipient) != "" &&
		!strings.Contains(recipient.Recipient, "@")
}

func workflowAlertRequiresRecipientFanout(alert WorkflowAlertInventory) bool {
	knownEmails := map[string]struct{}{}
	unknownDeliverableSources := 0
	for _, recipient := range alert.RecipientInventory {
		if recipient.BlockedReason != "" {
			continue
		}
		switch recipient.Classification {
		case "literal_email":
			address, ok := validateCanonicalSendEmailAddress(recipient.Recipient)
			if !ok {
				unknownDeliverableSources++
				continue
			}
			knownEmails[strings.ToLower(address)] = struct{}{}
		case "needs_resolver":
			if recipient.ResolvedRecipientEmail != "" {
				address, ok := validateCanonicalSendEmailAddress(recipient.ResolvedRecipientEmail)
				if ok {
					knownEmails[strings.ToLower(address)] = struct{}{}
					continue
				}
			}
			unknownDeliverableSources++
		}
	}
	return len(knownEmails)+unknownDeliverableSources > 1
}

func fieldYieldsSingleStringValue(field ObjectFieldInventory) bool {
	fieldType := constants.NormalizeFieldType(field.Type)
	if fieldType == constants.FieldTypeFormula {
		return isScalarTextLikeFieldType(constants.NormalizeFieldType(field.ReturnType))
	}
	return isScalarTextLikeFieldType(fieldType)
}

func isScalarTextLikeFieldType(fieldType constants.SchemaFieldType) bool {
	switch constants.NormalizeFieldType(string(fieldType)) {
	case constants.FieldTypeString,
		constants.FieldTypeTextarea,
		constants.FieldTypeRichtextarea,
		constants.FieldTypeEmail,
		constants.FieldTypePhone,
		constants.FieldTypeUrl,
		constants.FieldTypePicklist,
		constants.FieldTypeEncryptedString,
		constants.FieldTypeAutonumber:
		return true
	default:
		return false
	}
}

func recipientRequiresUserScopedResolver(recipient RecipientInventoryItem) bool {
	return recipient.Classification == "needs_resolver" &&
		strings.HasPrefix(strings.TrimSpace(recipient.TargetHint), "resolveEmailRecipients userIds:")
}

func recipientRequiresRelatedEmailResolver(recipient RecipientInventoryItem) bool {
	return strings.EqualFold(strings.TrimSpace(recipient.Type), "email") &&
		recipient.Classification == "needs_resolver" &&
		strings.TrimSpace(recipient.Field) != "" &&
		strings.Contains(strings.TrimSpace(recipient.Field), ".")
}

func recipientDescription(recipient RecipientInventoryItem) string {
	if strings.TrimSpace(recipient.Field) != "" {
		return fmt.Sprintf("%s recipient field %q", strings.TrimSpace(recipient.Type), strings.TrimSpace(recipient.Field))
	}
	if strings.TrimSpace(recipient.Recipient) != "" {
		return fmt.Sprintf("%s recipient %q", strings.TrimSpace(recipient.Type), strings.TrimSpace(recipient.Recipient))
	}
	return fmt.Sprintf("%s recipient", strings.TrimSpace(recipient.Type))
}
