<?php

namespace WPSN\Admin;

use WPSN\Core\Capabilities;
use WPSN\Integrations\CustomFields\CustomFieldResolver;

defined('ABSPATH') || exit;

/**
 * AJAX helper for debugging custom field template tokens.
 *
 * Used on Settings → Integrations → Custom Fields.
 */
final class CustomFieldsTokenTester
{
    private const POST_NONCE_ACTION = 'wpsn_cf_token_test_post';
    private const RESULT_TRANSIENT_PREFIX = 'wpsn_cf_token_test_result_';

    public static function handle(): void
    {
        if (!Capabilities::canManageSettings()) {
            wp_send_json_error([
                'message' => __('You do not have permission to perform this action.', 'wp-seo-next'),
            ], 403);
        }

        check_ajax_referer('wpsn_cf_token_test', 'nonce');

        $result = self::execute($_POST);
        if (empty($result['success'])) {
            wp_send_json_error([
                'message' => (string) ($result['message'] ?? __('Request failed.', 'wp-seo-next')),
            ], (int) ($result['status'] ?? 400));
        }

        wp_send_json_success($result);
    }

    public static function handlePost(): void
    {
        if (!Capabilities::canManageSettings()) {
            wp_die(esc_html__('You do not have permission to perform this action.', 'wp-seo-next'));
        }

        check_admin_referer(self::POST_NONCE_ACTION, 'wpsn_cf_nonce');

        $result = self::execute($_POST);
        $reportId = wp_generate_password(12, false, false);
        set_transient(self::RESULT_TRANSIENT_PREFIX . $reportId, $result, 10 * MINUTE_IN_SECONDS);

        $redirect = add_query_arg([
            'page' => 'wp-seo-next',
            'tab' => 'integrations',
            'section' => 'custom-fields',
            'wpsn_cf_report' => $reportId,
        ], admin_url('admin.php'));

        wp_safe_redirect($redirect . '#wpsn-cf-token-tester');
        exit;
    }

    public static function getResultTransientPrefix(): string
    {
        return self::RESULT_TRANSIENT_PREFIX;
    }

    public static function getPostNonceAction(): string
    {
        return self::POST_NONCE_ACTION;
    }

    /**
     * @param array<string,mixed> $input
     * @return array<string,mixed>
     */
    public static function execute(array $input): array
    {
        $objectType = isset($input['object_type']) ? sanitize_key((string) wp_unslash($input['object_type'])) : 'post';
        if (!in_array($objectType, ['post', 'term'], true)) {
            $objectType = 'post';
        }

        $objectId = isset($input['object_id']) ? (int) $input['object_id'] : 0;
        if ($objectId <= 0) {
            return [
                'success' => false,
                'status' => 400,
                'message' => __('Invalid object ID.', 'wp-seo-next'),
            ];
        }

        $taxonomy = isset($input['taxonomy']) ? sanitize_key((string) wp_unslash($input['taxonomy'])) : '';

        $token = isset($input['token']) ? (string) wp_unslash($input['token']) : '';
        $token = trim($token);
        if ($token === '') {
            return [
                'success' => false,
                'status' => 400,
                'message' => __('Token is empty.', 'wp-seo-next'),
            ];
        }
        if (function_exists('mb_strlen') && mb_strlen($token) > 200) {
            $token = (string) mb_substr($token, 0, 200);
        } elseif (strlen($token) > 200) {
            $token = substr($token, 0, 200);
        }

        $parsed = self::parseToken($token);
        if ($parsed === null) {
            return [
                'success' => false,
                'status' => 400,
                'message' => __('Token format is invalid. Example: %cf:hero_text%', 'wp-seo-next'),
            ];
        }

        $prefix = $parsed['prefix'];
        $key = $parsed['key'];
        $tokenNormalized = $parsed['token_normalized'];
        $providerWanted = $parsed['provider'];

        if ($objectType === 'post') {
            $p = get_post($objectId);
            if (!$p) {
                return [
                    'success' => false,
                    'status' => 404,
                    'message' => __('Post not found.', 'wp-seo-next'),
                ];
            }
        } else {
            $term = get_term($objectId);
            if (!$term || is_wp_error($term)) {
                return [
                    'success' => false,
                    'status' => 404,
                    'message' => __('Term not found.', 'wp-seo-next'),
                ];
            }
            if ($taxonomy === '' && isset($term->taxonomy)) {
                $taxonomy = sanitize_key((string) $term->taxonomy);
            }
        }

        $resolver = new CustomFieldResolver();

        $value = '';
        $providerUsed = $providerWanted;

        if ($providerWanted === CustomFieldResolver::PROVIDER_AUTO) {
            $candidates = [
                CustomFieldResolver::PROVIDER_ACF,
                CustomFieldResolver::PROVIDER_MB,
                CustomFieldResolver::PROVIDER_JET,
                CustomFieldResolver::PROVIDER_META,
            ];

            foreach ($candidates as $cand) {
                if ($objectType === 'post') {
                    $v = $resolver->resolvePostField($objectId, $cand, $key);
                } else {
                    $v = $resolver->resolveTermField($objectId, $taxonomy, $cand, $key);
                }

                $v = is_string($v) ? $v : '';
                if ($v !== '') {
                    $value = $v;
                    $providerUsed = $cand;
                    break;
                }
            }

            if ($value === '') {
                if ($objectType === 'post') {
                    $value = $resolver->resolvePostField($objectId, CustomFieldResolver::PROVIDER_META, $key);
                } else {
                    $value = $resolver->resolveTermField($objectId, $taxonomy, CustomFieldResolver::PROVIDER_META, $key);
                }
                $value = is_string($value) ? $value : '';
                $providerUsed = $value !== '' ? CustomFieldResolver::PROVIDER_META : CustomFieldResolver::PROVIDER_AUTO;
            }
        } else {
            if ($objectType === 'post') {
                $value = $resolver->resolvePostField($objectId, $providerWanted, $key);
            } else {
                $value = $resolver->resolveTermField($objectId, $taxonomy, $providerWanted, $key);
            }

            $value = is_string($value) ? $value : '';
        }

        return [
            'success' => true,
            'object_type' => $objectType,
            'object_id' => $objectId,
            'taxonomy' => $taxonomy,
            'token_input' => $token,
            'token_normalized' => $tokenNormalized,
            'prefix' => $prefix,
            'key' => $key,
            'provider' => $providerWanted,
            'provider_used' => $providerUsed,
            'value' => $value,
        ];
    }

    /**
     * Parse tokens like:
     * - %acf:field%
     * - %acf:group:field%
     * - %meta:key%
     * - %cf:key% (auto)
     *
     * @return array{prefix:string,key:string,provider:string,token_normalized:string}|null
     */
    private static function parseToken(string $token): ?array
    {
        $token = trim($token);
        if ($token === '') {
            return null;
        }

        // Allow users to paste with or without % wrappers.
        if ($token[0] === '%' && substr($token, -1) === '%') {
            $token = substr($token, 1, -1);
            $token = trim($token);
        }

        if ($token === '' || strpos($token, ':') === false) {
            return null;
        }

        $parts = explode(':', $token);
        $parts = array_values(array_filter(array_map('trim', $parts), static fn($v) => $v !== ''));
        if (count($parts) < 2) {
            return null;
        }

        $prefix = strtolower((string) array_shift($parts));
        $key = implode(':', $parts);

        // 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';
        }

        $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 'meta':
                $provider = CustomFieldResolver::PROVIDER_META;
                break;
            case 'cf':
                $provider = CustomFieldResolver::PROVIDER_AUTO;
                break;
            default:
                return null;
        }

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

        $tokenNormalized = '%' . $prefix . ':' . $key . '%';

        return [
            'prefix' => $prefix,
            'key' => $key,
            'provider' => $provider,
            'token_normalized' => $tokenNormalized,
        ];
    }
}
