<?php
/**
 * Revalidation on-demand du front Next.js.
 *
 * Constantes attendues dans wp-config.php :
 * - COVALBA_FRONT_URLS       : CSV d'URLs de fronts (https://covalba.fr,https://preview.covalba.fr)
 * - COVALBA_REVALIDATE_SECRET : secret partagé, envoyé en header x-revalidate-secret
 *
 * POST {front}/api/revalidate avec body JSON { tags: [...], paths: [...] }.
 */

defined('ABSPATH') || exit;

/** Types de contenu qui déclenchent une revalidation à la publication. */
function cvb_revalidated_post_types(): array {
    return ['page', 'produit', 'toiture', 'industrie', 'reference', 'lieu', 'formulaire_hubspot', 'post'];
}

/**
 * Tags « listing » émis selon le type sauvegardé : les pages d'agrégation qui
 * embarquent ce contenu (home, listes) s'y abonnent côté front (cf.
 * LISTING_TAGS_BY_URI dans src/lib/wp/queries/page.ts). Permet de revalider une
 * grille sans purger tout le site.
 */
function cvb_listing_tags_for_type(string $type, string $lang = 'fr'): array {
    $map = [
        'produit'   => ['listing:produits'],
        'reference' => ['listing:references'],
        'industrie' => ['listing:secteurs'],
    ];
    $tags = $map[$type] ?? [];
    // FR : tags historiques. EN/ES : tags qualifiés par langue.
    if ($lang === 'fr') return $tags;
    return array_map(static fn(string $t): string => $t . ':' . $lang, $tags);
}

/**
 * Tags PRÉCIS pour un post : sa propre route + les listings qui l'embarquent.
 * Le front s'ancre TOUJOURS sur l'identité FR (URI/slug FR), quelle que soit la
 * langue affichée (cf. getWpPage(frUri, locale) / getProduit(frSlug, locale)).
 * On émet donc le tag avec l'URI/slug du post FR + la langue du post sauvegardé :
 * - FR    : `page:/{uri}` / `{type}:{slug}` (inchangé).
 * - EN/ES : `page:{lang}:/{uri}` / `{type}:{lang}:{slug}`.
 */
function cvb_tags_for_post(WP_Post $post): array {
    $type = $post->post_type;
    $lang = function_exists('pll_get_post_language') ? (pll_get_post_language($post->ID) ?: 'fr') : 'fr';

    if ($type === 'formulaire_hubspot') {
        return ['wordpress'];
    }

    // Ancre FR : la traduction FR du post (ou lui-même si déjà FR / Polylang absent).
    $fr_id   = function_exists('pll_get_post') ? (pll_get_post($post->ID, 'fr') ?: $post->ID) : $post->ID;
    $fr_post = get_post($fr_id) ?: $post;

    if ($type === 'page') {
        $uri = '/' . trim(get_page_uri($fr_post), '/'); // ex. /contact, /accueil (URI FR)
        $tags = [$lang === 'fr' ? 'page:' . $uri : 'page:' . $lang . ':' . $uri];
    } else {
        $slug = $fr_post->post_name; // slug FR
        $tags = [$lang === 'fr' ? $type . ':' . $slug : $type . ':' . $lang . ':' . $slug];
    }

    return array_merge($tags, cvb_listing_tags_for_type($type, $lang));
}

/** URLs des fronts depuis COVALBA_FRONT_URLS (CSV), normalisées sans slash final. */
function cvb_front_urls(): array {
    if (!defined('COVALBA_FRONT_URLS') || !COVALBA_FRONT_URLS) {
        return [];
    }

    $urls = array_map(static fn(string $url): string => rtrim(trim($url), '/'), explode(',', COVALBA_FRONT_URLS));

    return array_values(array_filter($urls));
}

/**
 * Poste {tags, paths} sur /api/revalidate de chaque front.
 * Non-bloquant par défaut (save_post) ; bloquant pour le bouton admin (résultats).
 *
 * @return array<string, array{ok: bool, status?: int, error?: string}> résultats par URL (mode bloquant)
 */
function cvb_send_revalidate(array $tags, array $paths = [], bool $blocking = false): array {
    $secret  = defined('COVALBA_REVALIDATE_SECRET') ? (string) COVALBA_REVALIDATE_SECRET : '';
    $results = [];

    foreach (cvb_front_urls() as $base) {
        $response = wp_remote_post($base . '/api/revalidate', [
            'blocking' => $blocking,
            'timeout'  => $blocking ? 10 : 1,
            'headers'  => [
                'Content-Type'        => 'application/json',
                'x-revalidate-secret' => $secret,
            ],
            'body'     => wp_json_encode(['tags' => $tags, 'paths' => $paths]),
        ]);

        if (!$blocking) {
            continue;
        }

        if (is_wp_error($response)) {
            $results[$base] = ['ok' => false, 'error' => $response->get_error_message()];
        } else {
            $status         = (int) wp_remote_retrieve_response_code($response);
            $results[$base] = ['ok' => $status >= 200 && $status < 400, 'status' => $status];
        }
    }

    return $results;
}

// ── 1) Revalidation automatique ──────────────────────────────────────────────

add_action('save_post', 'cvb_revalidate_on_save', 20, 2);

function cvb_revalidate_on_save(int $post_id, WP_Post $post): void {
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
        return;
    }
    if (wp_is_post_revision($post_id) || $post->post_status !== 'publish') {
        return;
    }
    if (!in_array($post->post_type, cvb_revalidated_post_types(), true)) {
        return;
    }

    // Tags précis : route du post + listings qui l'embarquent (pas de purge globale).
    cvb_send_revalidate(cvb_tags_for_post($post));
}

add_action('acf/save_post', 'cvb_revalidate_on_options_save', 20);

function cvb_revalidate_on_options_save($post_id): void {
    if ($post_id !== 'options') {
        return;
    }

    // Ciblé : seules les données globales (nav, footer, CTA) sont concernées —
    // plus de purge de tout le site à chaque sauvegarde d'options.
    cvb_send_revalidate(['options']);
}

// ── 2) Bouton admin bar « Publier sur le site » ─────────────────────────────

add_action('admin_bar_menu', 'cvb_admin_bar_revalidate', 90);

function cvb_admin_bar_revalidate(WP_Admin_Bar $admin_bar): void {
    if (!current_user_can('edit_posts') || !cvb_front_urls()) {
        return;
    }

    $admin_bar->add_node([
        'id'    => 'cvb-revalidate',
        'title' => '<span id="cvb-revalidate-label">🚀 Publier sur le site</span>',
        'href'  => '#',
        'meta'  => ['title' => 'Revalide tout le cache du front Next.js'],
    ]);
}

add_action('wp_ajax_covalba_revalidate', 'cvb_ajax_revalidate');

function cvb_ajax_revalidate(): void {
    check_ajax_referer('covalba_revalidate', 'nonce');

    if (!current_user_can('edit_posts')) {
        wp_send_json(['success' => false, 'message' => 'Permission refusée.'], 403);
    }

    $results = cvb_send_revalidate(['wordpress'], [], true);
    $ok      = !empty($results) && !in_array(false, array_column($results, 'ok'), true);

    wp_send_json(['success' => $ok, 'results' => $results]);
}

add_action('admin_footer', 'cvb_revalidate_admin_js');

function cvb_revalidate_admin_js(): void {
    if (!current_user_can('edit_posts') || !cvb_front_urls()) {
        return;
    }

    $nonce = wp_create_nonce('covalba_revalidate');
    ?>
    <script>
    (function () {
        var link = document.querySelector('#wp-admin-bar-cvb-revalidate > a');
        var label = document.getElementById('cvb-revalidate-label');
        if (!link || !label) return;

        var initial = label.textContent;
        var busy = false;

        function reset() {
            setTimeout(function () { label.textContent = initial; busy = false; }, 3000);
        }

        link.addEventListener('click', function (event) {
            event.preventDefault();
            if (busy) return;
            busy = true;
            label.textContent = '⏳ Publication en cours…';

            var body = new FormData();
            body.append('action', 'covalba_revalidate');
            body.append('nonce', '<?php echo esc_js($nonce); ?>');

            fetch(ajaxurl, { method: 'POST', credentials: 'same-origin', body: body })
                .then(function (response) { return response.json(); })
                .then(function (data) {
                    label.textContent = data.success ? '✅ Site à jour' : '❌ Erreur de publication';
                })
                .catch(function () {
                    label.textContent = '❌ Erreur réseau';
                })
                .finally(reset);
        });
    })();
    </script>
    <?php
}
