<?php

namespace GriffinForms\Includes\Integrations\Mailchimp;

use GriffinForms\Includes\Integrations\FormControls\Factory;
use GriffinForms\Includes\Integrations\FormSettingsManager;
use WP_Error;

/**
 * Mailchimp marketing integration.
 */
class Main extends \GriffinForms\Includes\Integrations\Format
{
    protected $client;

    protected function setMeta()
    {
        $this->meta         = 'mailchimp';
        $this->id           = 'mailchimp';
        $this->option_group = 'marketing';
        $this->client       = new Client();
    }

    protected function buildInfo(): array
    {
        return [
            'id'          => 'mailchimp',
            'name'        => 'Mailchimp',
            'category'    => 'Marketing',
            'description' => __('Connect Mailchimp to sync form submissions into audiences with reusable global account settings.', 'griffinforms-form-builder'),
            'scope'       => [
                'is_global'      => true,
                'allow_override' => true,
            ],
        ];
    }

    public function getStatus(): array
    {
        $configured = $this->isConfigured();
        $audiences = $this->getCachedAudiences();
        $message = __('Not configured', 'griffinforms-form-builder');
        if ($configured) {
            if (!empty($audiences)) {
                /* translators: %d: number of discovered audiences */
                $message = sprintf(__('Configured • %d audiences discovered', 'griffinforms-form-builder'), count($audiences));
            } else {
                $message = __('Configured', 'griffinforms-form-builder');
            }
        }

        return [
            'configured' => $configured,
            'active'     => $configured,
            'message'    => $message,
        ];
    }

    public function getConfigFields(): array
    {
        return [
            ['name' => 'mailchimp_api_key', 'label' => __('API Key', 'griffinforms-form-builder'), 'type' => 'password', 'required' => true],
            ['name' => 'mailchimp_default_audience_id', 'label' => __('Default Audience', 'griffinforms-form-builder'), 'type' => 'select', 'required' => false],
            ['name' => 'mailchimp_default_status', 'label' => __('Default Subscription Mode', 'griffinforms-form-builder'), 'type' => 'select', 'required' => true],
        ];
    }

    protected function saveConfiguration(array $config): bool
    {
        $api_key = isset($config['mailchimp_api_key']) ? trim((string) $config['mailchimp_api_key']) : '';
        $default_audience_id = isset($config['mailchimp_default_audience_id']) ? sanitize_text_field((string) $config['mailchimp_default_audience_id']) : '';
        $default_status = isset($config['mailchimp_default_status']) ? sanitize_key((string) $config['mailchimp_default_status']) : 'subscribed';
        $valid_statuses = ['subscribed', 'pending'];
        if (!in_array($default_status, $valid_statuses, true)) {
            $default_status = 'subscribed';
        }

        $data_center = $this->client->resolveDataCenter($api_key);
        if ($api_key === '' || $data_center === '') {
            $this->log->add(
                'error',
                'integration',
                0,
                get_current_user_id(),
                'Mailchimp configuration save rejected because the API key is missing or invalid.',
                'Integration (mailchimp)'
            );
            return false;
        }

        $this->settings->updateOption('mailchimp_api_key', $api_key, 'marketing');
        $this->settings->updateOption('mailchimp_data_center', $data_center, 'marketing');
        $this->settings->updateOption('mailchimp_default_status', $default_status, 'marketing');

        $audience_result = $this->refreshAudienceCache($api_key);
        if (!is_wp_error($audience_result)) {
            $known_ids = array_map(static function (array $audience): string {
                return (string) ($audience['id'] ?? '');
            }, $audience_result);

            if ($default_audience_id !== '' && !in_array($default_audience_id, $known_ids, true)) {
                $default_audience_id = '';
                $this->log->add(
                    'warning',
                    'integration',
                    0,
                    get_current_user_id(),
                    'Mailchimp default audience was cleared because it was not found in the latest audience discovery payload.',
                    'Integration (mailchimp)'
                );
            }
        } else {
            $this->log->add(
                'warning',
                'integration',
                0,
                get_current_user_id(),
                'Mailchimp configuration saved, but audience discovery did not complete during save.',
                'Integration (mailchimp)'
            );
        }

        $this->settings->updateOption('mailchimp_default_audience_id', $default_audience_id, 'marketing');
        $this->log->add(
            'info',
            'integration',
            0,
            get_current_user_id(),
            'Mailchimp configuration saved.',
            'Integration (mailchimp)'
        );

        return true;
    }

    protected function validateConnection(): array
    {
        $api_key = $this->getApiKey();
        $item_id = $this->resolveFormContextId();
        $item_type = $item_id > 0 ? 'form' : 'integration';

        if ($api_key === '') {
            return [
                'success' => false,
                'message' => __('Mailchimp API key is required before testing.', 'griffinforms-form-builder'),
            ];
        }

        $ping = $this->client->ping($api_key);
        if (is_wp_error($ping)) {
            $status = (int) ($ping->get_error_data()['status'] ?? 0);
            $message = $status === 401
                ? __('Invalid Mailchimp API key. Please verify the key and try again.', 'griffinforms-form-builder')
                : __('Unable to reach Mailchimp. Please verify the API key and network connectivity.', 'griffinforms-form-builder');

            $this->log->add(
                'error',
                $item_type,
                $item_id,
                get_current_user_id(),
                'Mailchimp connection test failed: ' . $this->sanitizeErrorForLog($ping),
                'Integration (mailchimp)'
            );

            return [
                'success' => false,
                'message' => $message,
            ];
        }

        $root = $this->client->getRoot($api_key);
        if (!is_wp_error($root)) {
            $account_name = sanitize_text_field((string) ($root['body']['account_name'] ?? ''));
            $account_id = sanitize_text_field((string) ($root['body']['account_id'] ?? ''));
            if ($account_name !== '') {
                $this->settings->updateOption('mailchimp_account_name', $account_name, 'marketing');
            }
            if ($account_id !== '') {
                $this->settings->updateOption('mailchimp_account_id', $account_id, 'marketing');
            }
        }

        $audience_result = $this->refreshAudienceCache($api_key);
        if (is_wp_error($audience_result)) {
            $this->log->add(
                'warning',
                $item_type,
                $item_id,
                get_current_user_id(),
                'Mailchimp connection test succeeded, but audience discovery failed: ' . $this->sanitizeErrorForLog($audience_result),
                'Integration (mailchimp)'
            );

            return [
                'success' => true,
                'message' => __('Mailchimp credentials verified, but audience discovery could not be completed right now.', 'griffinforms-form-builder'),
            ];
        }

        $this->log->add(
            'success',
            $item_type,
            $item_id,
            get_current_user_id(),
            sprintf('Mailchimp connection test successful. %d audiences discovered.', count($audience_result)),
            'Integration (mailchimp)'
        );

        return [
            'success' => true,
            'message' => __('Mailchimp is properly configured and audience discovery is working.', 'griffinforms-form-builder'),
        ];
    }

    public function isLibraryInstalled(): bool
    {
        return true;
    }

    public function getLibraryInstructions(): string
    {
        return __('Uses the WordPress HTTP API; no additional library is required.', 'griffinforms-form-builder');
    }

    public function isConfigured(): bool
    {
        return $this->getApiKey() !== '' && $this->getDataCenter() !== '';
    }

    public function getConfigurationFormHtml(): string
    {
        $api_key = $this->getApiKey();
        $default_audience_id = (string) $this->getOption('default_audience_id', '');
        $default_status = (string) $this->getOption('default_status', 'subscribed');
        $audience_options = $this->getAudienceChoices();

        $fields_html = '';
        $fields_html .= Factory::create('password', 'mailchimp_api_key', $api_key, 'mailchimp', [
            'label' => __('API Key', 'griffinforms-form-builder'),
            'required' => true,
            'description' => __('Generate a Marketing API key in Mailchimp. The datacenter suffix on the key is used automatically.', 'griffinforms-form-builder'),
        ])->render();

        $fields_html .= Factory::create('select', 'mailchimp_default_audience_id', $default_audience_id, 'mailchimp', [
            'label' => __('Default Audience', 'griffinforms-form-builder'),
            'options' => $audience_options,
            'placeholder' => __('No default audience', 'griffinforms-form-builder'),
            'description' => __('Optional: choose a default audience that form-level settings can inherit later.', 'griffinforms-form-builder'),
        ])->render();

        $fields_html .= Factory::create('select', 'mailchimp_default_status', $default_status, 'mailchimp', [
            'label' => __('Default Subscription Mode', 'griffinforms-form-builder'),
            'options' => [
                'subscribed' => __('Subscribed', 'griffinforms-form-builder'),
                'pending' => __('Pending (double opt-in)', 'griffinforms-form-builder'),
            ],
            'description' => __('Optional global default for downstream form-level subscriber sync behavior.', 'griffinforms-form-builder'),
        ])->render();

        if ($this->isConfigured() && empty($audience_options)) {
            $fields_html = '<div class="alert alert-warning">' .
                esc_html__('Mailchimp is configured, but no audiences are currently cached. Save or test the connection again to refresh audience discovery.', 'griffinforms-form-builder') .
                '</div>' . $fields_html;
        }

        return $this->renderConfigurationFormTemplate(
            'griffinforms-mailchimp-config',
            $this->id,
            $fields_html
        );
    }

    public function getConfigurationJs(): string
    {
        return "(function(){\n" .
            "const form=document.getElementById('griffinforms-mailchimp-config');\n" .
            "if(!form){return;}\n" .
            "const cancelBtn=form.querySelector('.gf-integration-btn-cancel');\n" .
            "if(cancelBtn){cancelBtn.addEventListener('click',function(e){e.preventDefault();window.loadIntegrationInfo('mailchimp');});}\n" .
            "form.addEventListener('submit',function(e){\n" .
            "e.preventDefault();\n" .
            "const formId=window.griffinformsResolveActiveFormId?window.griffinformsResolveActiveFormId():null;\n" .
            "const formData=new FormData(form);\n" .
            "const apiKey=(formData.get('mailchimp_api_key')||'').trim();\n" .
            "if(!apiKey){window.showIntegrationsMessage('danger','" . esc_js(__('Please enter your Mailchimp API key.', 'griffinforms-form-builder')) . "');return;}\n" .
            "jQuery.ajax({url:ajaxurl,type:'POST',dataType:'json',data:{action:'saveIntegrationConfiguration',integration_id:'mailchimp',nonce:window.griffinformsIntegrationsNonce||'',form_id:formId||'',mailchimp_api_key:apiKey,mailchimp_default_audience_id:formData.get('mailchimp_default_audience_id')||'',mailchimp_default_status:formData.get('mailchimp_default_status')||'subscribed'},success:function(response){if(response.success){window.showIntegrationsMessage('success',response.data.message||'" . esc_js(__('Mailchimp configuration saved.', 'griffinforms-form-builder')) . "');setTimeout(function(){window.loadIntegrationInfo('mailchimp');},500);}else{const msg=(response.data&&response.data.msg)?response.data.msg:'" . esc_js(__('Failed to save Mailchimp configuration.', 'griffinforms-form-builder')) . "';window.showIntegrationsMessage('danger',msg);}},error:function(){window.showIntegrationsMessage('danger','" . esc_js(__('Failed to save Mailchimp configuration.', 'griffinforms-form-builder')) . "');}});\n" .
            "});\n" .
            "})();";
    }

    public function getAudienceChoices(bool $refresh = false): array
    {
        $audiences = $refresh ? $this->refreshAudienceCache() : $this->getCachedAudiences();
        if (is_wp_error($audiences) || empty($audiences) || !is_array($audiences)) {
            return [];
        }

        $choices = [];
        foreach ($audiences as $audience) {
            if (!is_array($audience)) {
                continue;
            }

            $id = sanitize_text_field((string) ($audience['id'] ?? ''));
            $name = sanitize_text_field((string) ($audience['name'] ?? ''));
            if ($id === '' || $name === '') {
                continue;
            }

            $member_count = isset($audience['member_count']) ? max(0, (int) $audience['member_count']) : 0;
            $choices[$id] = sprintf('%s (%d)', $name, $member_count);
        }

        return $choices;
    }

    public function getFormSettingsSchema(): array
    {
        $mapping_options = $this->getFormFieldOptionsForMapping();
        $consent_options = $this->getConsentFieldOptions();

        return [
            [
                'name' => '__gf_form_settings_mode',
                'type' => 'hidden',
                'default' => 'custom',
            ],
            [
                'name' => 'disable_mailchimp_sync',
                'type' => 'checkbox',
                'label' => __('Disable Mailchimp on this form', 'griffinforms-form-builder'),
                'description' => __('Use this to opt this form out of Mailchimp while keeping the global connection intact.', 'griffinforms-form-builder'),
                'default' => false,
            ],
            [
                'name' => 'audience_id',
                'type' => 'select',
                'label' => __('Audience Override', 'griffinforms-form-builder'),
                'options' => $this->getAudienceChoices(),
                'placeholder' => __('Use global default audience', 'griffinforms-form-builder'),
                'description' => __('Optional. Leave blank to inherit the globally configured default audience.', 'griffinforms-form-builder'),
                'default' => '',
            ],
            [
                'name' => 'subscription_status',
                'type' => 'select',
                'label' => __('Subscription Mode Override', 'griffinforms-form-builder'),
                'options' => [
                    'subscribed' => __('Subscribed', 'griffinforms-form-builder'),
                    'pending' => __('Pending (double opt-in)', 'griffinforms-form-builder'),
                ],
                'placeholder' => __('Use global default subscription mode', 'griffinforms-form-builder'),
                'description' => __('Optional. Leave blank to inherit the globally configured subscription mode.', 'griffinforms-form-builder'),
                'default' => '',
            ],
            [
                'name' => 'subscriber_email_field',
                'type' => 'select',
                'label' => __('Subscriber Email Field', 'griffinforms-form-builder'),
                'options' => $mapping_options,
                'placeholder' => __('Select the email field', 'griffinforms-form-builder'),
                'description' => __('Required when Mailchimp sync is enabled for this form.', 'griffinforms-form-builder'),
                'default' => '',
            ],
            [
                'name' => 'first_name_field',
                'type' => 'select',
                'label' => __('First Name Field', 'griffinforms-form-builder'),
                'options' => $mapping_options,
                'placeholder' => __('Optional first name field', 'griffinforms-form-builder'),
                'description' => __('Optional. Map an existing GriffinForms field to Mailchimp first name.', 'griffinforms-form-builder'),
                'default' => '',
            ],
            [
                'name' => 'last_name_field',
                'type' => 'select',
                'label' => __('Last Name Field', 'griffinforms-form-builder'),
                'options' => $mapping_options,
                'placeholder' => __('Optional last name field', 'griffinforms-form-builder'),
                'description' => __('Optional. Map an existing GriffinForms field to Mailchimp last name.', 'griffinforms-form-builder'),
                'default' => '',
            ],
            [
                'name' => 'static_tags',
                'type' => 'textarea',
                'label' => __('Static Tags', 'griffinforms-form-builder'),
                'description' => __('Optional. Enter one tag per line or separate tags with commas. These tags will be applied to every synced contact from this form.', 'griffinforms-form-builder'),
                'default' => '',
            ],
            [
                'name' => 'consent_field_id',
                'type' => 'select',
                'label' => __('Consent Source Field', 'griffinforms-form-builder'),
                'options' => $consent_options,
                'placeholder' => __('No consent field required', 'griffinforms-form-builder'),
                'description' => __('Optional. Choose an existing checkbox-style or Terms & Conditions field to require explicit opt-in before syncing. Use Terms & Conditions here only when its copy is written as marketing consent.', 'griffinforms-form-builder'),
                'default' => '',
            ],
        ];
    }

    public function getDefaultFormSettings(): array
    {
        return [
            'disable_mailchimp_sync' => false,
            'audience_id' => '',
            'subscription_status' => '',
            'subscriber_email_field' => '',
            'first_name_field' => '',
            'last_name_field' => '',
            'static_tags' => '',
            'consent_field_id' => '',
        ];
    }

    public function validateFormSettings(array $settings)
    {
        $form_id = $this->resolveFormContextId();
        $all_fields = $this->getFormFieldOptionsForMapping();
        $email_fields = $this->getEligibleFieldOptions(['inputemail']);
        $name_fields = $this->getNameFieldOptions();
        $consent_fields = $this->getConsentFieldOptions();

        $disable_sync = $this->toBoolean($settings['disable_mailchimp_sync'] ?? false);
        $audience_id = sanitize_text_field((string) ($settings['audience_id'] ?? ''));
        $subscription_status = sanitize_key((string) ($settings['subscription_status'] ?? ''));
        $subscriber_email_field = $this->sanitizeMappedFieldId(
            $settings['subscriber_email_field'] ?? '',
            $email_fields,
            'Mailchimp subscriber email'
        );
        $first_name_field = $this->sanitizeMappedFieldId(
            $settings['first_name_field'] ?? '',
            $name_fields,
            'Mailchimp first name'
        );
        $last_name_field = $this->sanitizeMappedFieldId(
            $settings['last_name_field'] ?? '',
            $name_fields,
            'Mailchimp last name'
        );
        $consent_field_id = $this->sanitizeMappedFieldId(
            $settings['consent_field_id'] ?? '',
            $consent_fields,
            'Mailchimp consent source'
        );

        if ($audience_id !== '' && !isset($this->getAudienceChoices()[$audience_id])) {
            $this->log->add(
                'warning',
                'form',
                $form_id,
                get_current_user_id(),
                sprintf('Mailchimp audience override references an unknown audience ID (%s). Falling back to the global audience when available.', $audience_id),
                'Integration (mailchimp)'
            );
            $audience_id = '';
        }

        if ($subscription_status !== '' && !in_array($subscription_status, ['subscribed', 'pending'], true)) {
            $subscription_status = '';
        }

        if (!$disable_sync && $subscriber_email_field === '') {
            return new WP_Error(
                'mailchimp_missing_email_mapping',
                __('Select a subscriber email field or disable Mailchimp for this form.', 'griffinforms-form-builder')
            );
        }

        $static_tags = $this->sanitizeTagsForStorage($settings['static_tags'] ?? '');

        if ($disable_sync) {
            $subscriber_email_field = '';
            $first_name_field = '';
            $last_name_field = '';
            $static_tags = '';
            $consent_field_id = '';
        }

        return [
            'disable_mailchimp_sync' => $disable_sync,
            'audience_id' => $audience_id,
            'subscription_status' => $subscription_status,
            'subscriber_email_field' => $subscriber_email_field,
            'first_name_field' => $first_name_field,
            'last_name_field' => $last_name_field,
            'static_tags' => $static_tags,
            'consent_field_id' => $consent_field_id,
        ];
    }

    public function getEffectiveFormSettings(int $form_id): array
    {
        $global = [
            'audience_id' => (string) $this->getOption('default_audience_id', ''),
            'subscription_status' => (string) $this->getOption('default_status', 'subscribed'),
            'subscriber_email_field' => '',
            'first_name_field' => '',
            'last_name_field' => '',
            'static_tags' => [],
            'consent_field_id' => '',
        ];

        $form_settings = FormSettingsManager::getInstance()->getIntegrationSettings($form_id, $this->id);
        $effective = FormSettingsManager::getInstance()->mergeSettings($global, $form_settings, true);

        if (($effective['mode'] ?? '') === 'disabled') {
            return ['mode' => 'disabled'];
        }

        $effective['static_tags'] = $this->sanitizeTags($effective['static_tags'] ?? []);
        $effective['audience_id'] = sanitize_text_field((string) ($effective['audience_id'] ?? ''));
        $effective['subscription_status'] = sanitize_key((string) ($effective['subscription_status'] ?? 'subscribed'));
        if (!in_array($effective['subscription_status'], ['subscribed', 'pending'], true)) {
            $effective['subscription_status'] = 'subscribed';
        }

        foreach (['subscriber_email_field', 'first_name_field', 'last_name_field', 'consent_field_id'] as $key) {
            $effective[$key] = $this->normalizeFieldId($effective[$key] ?? '');
        }

        return $effective;
    }

    public function isEnabledForForm(int $form_id): bool
    {
        $effective = $this->getEffectiveFormSettings($form_id);
        if (($effective['mode'] ?? '') === 'disabled') {
            return false;
        }

        return !empty($effective['subscriber_email_field']);
    }

    public function getCachedAudiences(): array
    {
        $audiences = $this->getOption('audiences_cache', []);
        return is_array($audiences) ? $audiences : [];
    }

    public function refreshAudienceCache(?string $api_key = null)
    {
        $api_key = $api_key !== null ? trim($api_key) : $this->getApiKey();
        if ($api_key === '') {
            return new WP_Error(
                'mailchimp_missing_api_key',
                __('Mailchimp API key is required before audiences can be discovered.', 'griffinforms-form-builder')
            );
        }

        $response = $this->client->getAudiences($api_key);
        if (is_wp_error($response)) {
            return $response;
        }

        $audiences = $this->client->normalizeAudiences((array) ($response['body'] ?? []));
        $this->settings->updateOption('mailchimp_audiences_cache', $audiences, 'marketing');
        $this->settings->updateOption('mailchimp_audiences_cached_at', gmdate('c'), 'marketing');

        return $audiences;
    }

    protected function getApiKey(): string
    {
        return trim((string) $this->getOption('api_key', ''));
    }

    protected function getDataCenter(): string
    {
        $stored = strtolower(trim((string) $this->getOption('data_center', '')));
        if ($stored !== '') {
            return $stored;
        }

        return $this->client->resolveDataCenter($this->getApiKey());
    }

    protected function sanitizeErrorForLog(WP_Error $error): string
    {
        $status = (int) ($error->get_error_data()['status'] ?? 0);
        $message = sanitize_text_field($error->get_error_message());

        if ($status > 0) {
            return sprintf('HTTP %d: %s', $status, $message);
        }

        return $message;
    }

    protected function getNameFieldOptions(): array
    {
        return $this->getEligibleFieldOptions([
            'inputtext',
            'inputemail',
            'inputphone',
            'inputurl',
            'selectfield',
            'textarea',
        ]);
    }

    protected function sanitizeTags($raw_tags): array
    {
        if (is_array($raw_tags)) {
            $candidates = $raw_tags;
        } else {
            $normalized = str_replace(["\r\n", "\r"], "\n", (string) $raw_tags);
            $normalized = str_replace(',', "\n", $normalized);
            $candidates = explode("\n", $normalized);
        }

        $tags = [];
        foreach ($candidates as $candidate) {
            $tag = sanitize_text_field((string) $candidate);
            $tag = trim($tag);
            if ($tag === '') {
                continue;
            }
            $tags[] = $tag;
        }

        $tags = array_values(array_unique($tags));
        return array_slice($tags, 0, 50);
    }

    protected function sanitizeTagsForStorage($raw_tags): string
    {
        $tags = $this->sanitizeTags($raw_tags);
        return implode("\n", $tags);
    }

}
