<?php

namespace Formatrica\Submission\Integrations\Dispatchers;

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

use Formatrica\Submission\Integrations\Http_Client;
use Formatrica\Submission\Integrations\Integration_Dispatcher_Interface;
use Formatrica\Submission\Rendering\Template_Renderer;
use Formatrica\Support\Secrets;

/**
 * Dispatcher for Mailchimp integration
 */
final class Mailchimp_Dispatcher implements Integration_Dispatcher_Interface
{
    private Http_Client $client;
    private Template_Renderer $renderer;

    public function __construct(?Http_Client $client = null, ?Template_Renderer $renderer = null)
    {
        $this->client = $client ?? new Http_Client();
        $this->renderer = $renderer ?? new Template_Renderer();
    }

    public function dispatch(array $settings, array $form, array $payload, array $context, array $field_meta): void
    {
        $encrypted_key = isset($settings['api_key']) ? (string) $settings['api_key'] : '';
        $api_key = $encrypted_key !== '' ? Secrets::decrypt($encrypted_key) : '';

        if ($api_key === '') {
            return;
        }

        $list_id = isset($settings['list_id']) ? trim((string) $settings['list_id']) : '';
        if ($list_id === '') {
            return;
        }

        $email_field = isset($settings['email_field']) ? (string) $settings['email_field'] : '';
        if ($email_field === '' || !isset($payload[$email_field])) {
            return;
        }

        $email = trim((string) $payload[$email_field]);
        if ($email === '' || !is_email($email)) {
            return;
        }

        $data_center = $this->extract_datacenter($api_key);
        if ($data_center === '') {
            return;
        }

        $member_hash = md5(strtolower($email));
        $endpoint = sprintf(
            'https://%s.api.mailchimp.com/3.0/lists/%s/members/%s',
            $data_center,
            rawurlencode($list_id),
            $member_hash
        );

        $double_opt_in = !empty($settings['double_opt_in']);
        $status = $double_opt_in ? 'pending' : 'subscribed';

        $body = [
            'email_address' => $email,
            'status_if_new' => $status,
            'status' => $status,
            'email_type' => 'html',
            'merge_fields' => [],
        ];

        $first_field = isset($settings['first_name_field']) ? (string) $settings['first_name_field'] : '';
        if ($first_field !== '' && isset($payload[$first_field])) {
            $body['merge_fields']['FNAME'] = $this->renderer->normalise_value($payload[$first_field]);
        }

        $last_field = isset($settings['last_name_field']) ? (string) $settings['last_name_field'] : '';
        if ($last_field !== '' && isset($payload[$last_field])) {
            $body['merge_fields']['LNAME'] = $this->renderer->normalise_value($payload[$last_field]);
        }

        // Tags should be a simple array of strings when creating/updating members
        if (isset($settings['tags']) && is_array($settings['tags']) && !empty($settings['tags'])) {
            $tags_payload = [];
            foreach ($settings['tags'] as $tag) {
                $tag_value = sanitize_text_field((string) $tag);
                if ($tag_value !== '') {
                    $tags_payload[] = $tag_value;
                }
            }
            if (!empty($tags_payload)) {
                $body['tags'] = $tags_payload;
            }
        }

        /**
         * Filter the Mailchimp payload before it is sent.
         *
         * @param array<string, mixed> $body
         * @param array<string, mixed> $form
         * @param array<string, mixed> $payload
         * @param array<string, mixed> $context
         * @param array<int, array<string, mixed>> $field_meta
         */
        $body = apply_filters('formatrica_mailchimp_payload', $body, $form, $payload, $context, $field_meta);

        $headers = [
            'Authorization' => 'Basic ' . base64_encode('formatrica:' . $api_key),
        ];

        $this->client->send_json($endpoint, $body, 'mailchimp', $form, $payload, $context, 'PUT', $headers);
    }

    /**
     * Extract data center from API key
     *
     * @param string $api_key
     * @return string
     */
    private function extract_datacenter(string $api_key): string
    {
        if (strpos($api_key, '-') === false) {
            return '';
        }

        $parts = explode('-', $api_key);
        $data_center = strtolower(trim((string) end($parts)));

        if ($data_center === '') {
            return '';
        }

        $sanitised = preg_replace('/[^a-z0-9]/', '', $data_center);

        return is_string($sanitised) ? $sanitised : '';
    }
}
