<?php

namespace WPSN\Modules\CustomFields;

use WPSN\Core\AbstractModule;
use WPSN\Core\Container;
use WPSN\Integrations\CustomFields\CustomFieldResolver;

defined('ABSPATH') || exit;

/**
 * Integrations: custom fields (ACF / Meta Box / JetEngine).
 *
 * Provides:
 * - Dynamic template tokens: %acf:field%, %mb:field%, %jet:field%, %meta:...%
 * - Optional: include selected custom fields into analysis text (AI/local suggestions).
 */
final class CustomFieldsModule extends AbstractModule
{
    private CustomFieldResolver $resolver;

    public function __construct(Container $container)
    {
        parent::__construct($container);
        $this->resolver = new CustomFieldResolver();
    }

    public function id(): string
    {
        return 'custom_fields';
    }

    public function name(): string
    {
        return __('Custom Fields Integration', 'wp-seo-next');
    }

    public function description(): string
    {
        return __('Adds template variables and content extraction support for ACF (incl. Options Pages), Meta Box, JetEngine, Pods, and WooCommerce.', 'wp-seo-next');
    }

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

    public function register(): void
    {
        if (!(bool) $this->settings->get('integrations.custom_fields.enabled', true)) {
            return;
        }

        // New API: variable providers.
        add_filter('wpsn/variables/resolve', [$this, 'resolveVariableProvider'], 10, 4);

        // Dynamic template tokens: %acf:field%, %mb:field%, %jet:field%, %meta:key%, %cf:key%.
        add_filter('wpsn/template_dynamic_variable', [$this, 'resolveDynamicVariable'], 10, 4);

        // Optional extra content for analysis.
        add_filter('wpsn/content/extra_text', [$this, 'addExtraContentText'], 10, 3);
    }

    /**
     * @param string $value
     * @param string $prefix
     * @param string $key
     * @param \WPSN\Domain\SeoDocumentContext $ctx
     */
    public function resolveDynamicVariable(string $value, string $prefix, string $key, $ctx): string
    {
        $prefix = strtolower(trim($prefix));
        $key = trim($key);

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

        // Normalize aliases.
        if (in_array($prefix, ['acf_group', 'acf-group', 'acfgroup'], true)) {
            $prefix = 'acf';
        }
        if (in_array($prefix, ['metabox', 'meta_box'], true)) {
            $prefix = 'mb';
        }
        if (in_array($prefix, ['jetengine', 'jet-engine'], true)) {
            $prefix = 'jet';
        }
        if (in_array($prefix, ['acfopt', 'acf_opt', 'acf-option', 'acf_option', 'acfoptions', 'acf-options'], true)) {
            $prefix = 'acfopt';
        }
        if (in_array($prefix, ['woocommerce', 'wc'], true)) {
            $prefix = 'woo';
        }
        if ($prefix === 'pod') {
            $prefix = 'pods';
        }
        if ($prefix === 'field') {
            $prefix = 'cf';
        }

        // Accepted prefixes.
        $provider = '';
        switch ($prefix) {
            case 'acf':
                $provider = CustomFieldResolver::PROVIDER_ACF;
                break;
            case 'mb':
                $provider = CustomFieldResolver::PROVIDER_MB;
                break;
            case 'jet':
                $provider = CustomFieldResolver::PROVIDER_JET;
                break;
            case 'pods':
                $provider = CustomFieldResolver::PROVIDER_PODS;
                break;
            case 'woo':
                $provider = CustomFieldResolver::PROVIDER_WOO;
                break;
            case 'acfopt':
                $provider = CustomFieldResolver::PROVIDER_ACF_OPTION;
                break;
            case 'meta':
                $provider = CustomFieldResolver::PROVIDER_META;
                break;
            case 'cf':
                $provider = CustomFieldResolver::PROVIDER_AUTO;
                break;
            default:
                return $value;
        }

        try {
            $resolved = $this->resolver->resolveForContext($ctx, $provider, $key);
            return is_string($resolved) ? $resolved : '';
        } catch (\Throwable $e) {
            return '';
        }
    }

    /**
     * Variable Providers API.
     *
     * Hook: wpsn/variables/resolve
     *
     * Return:
     * - null (or passthrough) => not handled
     * - string => handled (non-empty)
     * - array{handled:bool,value:string} => handled even if empty
     *
     * @param mixed $res
     * @return mixed
     */
    public function resolveVariableProvider($res, string $prefix, string $key, $ctx)
    {
        // Respect earlier providers in the chain.
        if (is_array($res) && !empty($res['handled'])) {
            return $res;
        }
        if (is_string($res) && trim($res) !== '') {
            return $res;
        }

        if (!$ctx instanceof \WPSN\Domain\SeoDocumentContext) {
            return $res;
        }

        $prefix = strtolower(trim((string) $prefix));
        $key = trim((string) $key);
        if ($key === '') {
            return $res;
        }

        // Normalize aliases.
        if (in_array($prefix, ['acf_group', 'acf-group', 'acfgroup'], true)) {
            $prefix = 'acf';
        }
        if (in_array($prefix, ['metabox', 'meta_box'], true)) {
            $prefix = 'mb';
        }
        if (in_array($prefix, ['jetengine', 'jet-engine'], true)) {
            $prefix = 'jet';
        }
        if ($prefix === 'field') {
            $prefix = 'cf';
        }

        // Accepted prefixes for this module.
        $provider = '';
        switch ($prefix) {
            case 'acf':
                $provider = CustomFieldResolver::PROVIDER_ACF;
                break;
            case 'mb':
                $provider = CustomFieldResolver::PROVIDER_MB;
                break;
            case 'jet':
                $provider = CustomFieldResolver::PROVIDER_JET;
                break;
            case 'pods':
                $provider = CustomFieldResolver::PROVIDER_PODS;
                break;
            case 'woo':
                $provider = CustomFieldResolver::PROVIDER_WOO;
                break;
            case 'acfopt':
                $provider = CustomFieldResolver::PROVIDER_ACF_OPTION;
                break;
            case 'cf':
                $provider = CustomFieldResolver::PROVIDER_AUTO;
                break;
            default:
                return $res;
        }

        try {
            $resolved = $this->resolver->resolveForContext($ctx, $provider, $key);
            $resolved = is_string($resolved) ? $resolved : '';
        } catch (\Throwable $e) {
            $resolved = '';
        }

        return [
            'handled' => true,
            'value' => $resolved,
        ];
    }

    /**
     * @param string|array<int,string> $extra
     * @return string|array<int,string>
     */
    public function addExtraContentText($extra, int $postId, string $context)
    {
        // Only for posts for now.
        if ($postId <= 0) {
            return $extra;
        }

        $enabled = (bool) $this->settings->get('integrations.custom_fields.include_in_analysis', false);
        if (!$enabled) {
            return $extra;
        }

        $keysText = (string) $this->settings->get('integrations.custom_fields.analysis_keys', '');
        $keysText = trim($keysText);
        if ($keysText === '') {
            return $extra;
        }

        $keys = preg_split('/\r\n|\r|\n/', $keysText) ?: [];
        $keys = array_values(array_unique(array_filter(array_map('trim', array_map('strval', $keys)))));
        if (!$keys) {
            return $extra;
        }

        $maxChars = (int) $this->settings->get('integrations.custom_fields.max_value_chars', 500);
        if ($maxChars <= 0) {
            $maxChars = 500;
        }

        $out = [];
        foreach ($keys as $k) {
            if ($k === '') {
                continue;
            }
            $v = $this->resolver->resolvePostField($postId, CustomFieldResolver::PROVIDER_AUTO, $k);
            $v = is_string($v) ? trim($v) : '';
            if ($v === '') {
                continue;
            }
            // Keep values small to avoid huge prompts.
            if (function_exists('mb_strlen') && function_exists('mb_substr')) {
                if (mb_strlen($v) > $maxChars) {
                    $v = (string) mb_substr($v, 0, $maxChars);
                }
            } else {
                if (strlen($v) > $maxChars) {
                    $v = substr($v, 0, $maxChars);
                }
            }
            $out[] = $k . ': ' . $v;
        }

        if (!$out) {
            return $extra;
        }

        if (is_array($extra)) {
            return array_values(array_merge($extra, $out));
        }

        $extra = is_string($extra) ? trim($extra) : '';
        $addon = implode("\n", $out);
        return $extra !== '' ? ($extra . "\n" . $addon) : $addon;
    }
}
