<?php

namespace EasyLinkAutomations\Actions\CleverReach;

if (!defined('ABSPATH')) {
    exit;
}

/**
 * Builds CleverReach receiver payloads from mapped action configuration.
 *
 * The receiver field mapping returns prefixed keys so a single mapping widget
 * can address the three distinct places CleverReach stores subscriber data:
 *
 *   email              → the receiver's address (top level, always required)
 *   global:<name>      → account-wide attributes ("global_attributes")
 *   attribute:<name>   → group-local attributes ("attributes")
 */
final class CleverReachReceiverHelper
{
    public const GLOBAL_PREFIX = 'global:';
    public const LOCAL_PREFIX  = 'attribute:';

    /**
     * Decode a field_mapping config value into an array.
     */
    public static function decodeMapping(mixed $value): array
    {
        if (is_string($value)) {
            $value = json_decode($value, true);
        }

        return is_array($value) ? $value : [];
    }

    /**
     * Split a decoded field mapping into a CleverReach receiver payload.
     *
     * Empty values are dropped so an unmapped field never overwrites existing
     * CleverReach data with a blank string.
     *
     * @return array{email: string, global_attributes: array, attributes: array}
     */
    public static function splitMapping(array $mapping): array
    {
        $email      = '';
        $globalAttr = [];
        $localAttr  = [];

        foreach ($mapping as $key => $value) {
            if (is_array($value)) {
                continue;
            }

            $value = is_string($value) ? trim($value) : $value;
            if ($value === '' || $value === null) {
                continue;
            }

            if ($key === 'email') {
                $email = (string) $value;
                continue;
            }

            if (str_starts_with($key, self::GLOBAL_PREFIX)) {
                $name = substr($key, strlen(self::GLOBAL_PREFIX));
                if ($name !== '') {
                    $globalAttr[$name] = $value;
                }
                continue;
            }

            if (str_starts_with($key, self::LOCAL_PREFIX)) {
                $name = substr($key, strlen(self::LOCAL_PREFIX));
                if ($name !== '') {
                    $localAttr[$name] = $value;
                }
                continue;
            }

            // Unprefixed keys are treated as global attributes so mappings
            // saved before a field was reclassified keep working.
            $localAttr[$key] = $value;
        }

        return [
            'email'             => $email,
            'global_attributes' => $globalAttr,
            'attributes'        => $localAttr,
        ];
    }

    /**
     * Build the receiver object sent to CleverReach.
     *
     * `activated` is only set when the automation explicitly opts out of the
     * double opt-in flow; leaving it unset keeps the receiver inactive, which
     * is what CleverReach expects before a DOI mailing is triggered.
     */
    public static function buildReceiver(array $config, array $split): array
    {
        $receiver = ['email' => $split['email']];

        if ($split['global_attributes']) {
            $receiver['global_attributes'] = $split['global_attributes'];
        }
        if ($split['attributes']) {
            $receiver['attributes'] = $split['attributes'];
        }

        $source = trim((string) ($config['source'] ?? ''));
        if ($source !== '') {
            $receiver['source'] = $source;
        }

        $tags = self::parseTags($config['tags'] ?? '');
        if ($tags) {
            $receiver['tags'] = $tags;
        }

        $receiver['registered'] = time();

        if (!empty($config['activate'])) {
            $receiver['activated'] = time();
        }

        return $receiver;
    }

    /**
     * Parse a comma-separated tag list into CleverReach-safe tag values.
     *
     * CleverReach restricts tags to letters, digits, underscore and hyphen.
     */
    public static function parseTags(mixed $value): array
    {
        if (is_array($value)) {
            $parts = $value;
        } else {
            $parts = explode(',', (string) $value);
        }

        $tags = [];
        foreach ($parts as $part) {
            $tag = trim((string) $part);
            if ($tag === '') {
                continue;
            }
            $tags[] = $tag;
        }

        return array_values(array_unique($tags));
    }

    /**
     * Reject tag values CleverReach will not accept.
     *
     * @return array<string> The offending tags, empty when all are valid.
     */
    public static function invalidTags(array $tags): array
    {
        $invalid = [];
        foreach ($tags as $tag) {
            if (!preg_match('/^[\p{L}0-9_\-]+$/u', $tag)) {
                $invalid[] = $tag;
            }
        }

        return $invalid;
    }
}
