<?php
declare(strict_types=1);
// ==================================================
// Nuclear Fancy Pants Edition™ — NUCLEAR+++
// File: /home/ploi/automarketer-ai.com/public/wp-content/plugins/automarketer-ai/includes/class-content-freshness.php
// Description: Content Health dashboard — posts needing attention and stale posts - NUCLEAR+++
// Last Edited: 2026-04-26
// ==================================================

namespace AutoMarketerAI;

defined('ABSPATH') || exit;

class ContentFreshness
{
    private const STALE_DAYS  = 180;
    private const SCORE_FLOOR = 80;

    // --------------------------------------------------
    // Register hooks
    // --------------------------------------------------
    public static function register(): void
    {
        add_action('admin_enqueue_scripts', [self::class, 'enqueueAssets']);
        add_action('wp_ajax_amai_content_health_refresh', [self::class, 'handleRefresh']);
        add_action('wp_ajax_amai_content_health_rescan',  [self::class, 'handleRescan']);
    }

    // --------------------------------------------------
    // Enqueue assets on this page only
    // --------------------------------------------------
    public static function enqueueAssets(string $hook): void
    {
        if ($hook !== 'automarketer-ai_page_automarketer-ai-content') {
            return;
        }
        wp_enqueue_style(
            'amai-content-freshness',
            AMAI_PLUGIN_URL . 'assets/css/content-freshness.css',
            [],
            (string) filemtime(AMAI_PLUGIN_DIR . 'assets/css/content-freshness.css')
        );
        wp_enqueue_script(
            'amai-content-freshness',
            AMAI_PLUGIN_URL . 'assets/js/amai-content-freshness.js',
            [],
            (string) filemtime(AMAI_PLUGIN_DIR . 'assets/js/amai-content-freshness.js'),
            true
        );
        wp_localize_script('amai-content-freshness', 'amaiContentHealth', [
            'ajaxurl' => admin_url('admin-ajax.php'),
            'nonce'   => wp_create_nonce('amai_content_health'),
        ]);
    }

    // --------------------------------------------------
    // Render the dashboard page
    // --------------------------------------------------
    public static function render(): void
    {
        if (!in_array('content-optimizer', (array) get_option('amai_active_modules', []), true)) {
            wp_die('Content Health requires the Content Optimizer module to be active.');
        }
        $live_budget     = 20;
        $needs_attention = self::getPostsNeedingAttention($live_budget);
        $stale_posts     = self::getStalePosts($live_budget);
        $total_published = (int) wp_count_posts('post')->publish;
        $license_status  = (string) get_option('automarketer_ai_license_status', 'free');
        $ga4_eligible    = !in_array($license_status, ['free', 'inactive'], true);
        $ga4_connected   = $ga4_eligible && \AutoMarketerAI\Ga4Auth::isConnected();
        $decaying_posts  = $ga4_connected ? \AutoMarketerAI\Ga4Sync::getDecayingPosts() : [];
        require_once AMAI_PLUGIN_DIR . 'templates/content-freshness.php';
    }

    // --------------------------------------------------
    // Get published posts with low scores
    // Live re-analyzes posts with stale or missing scores (capped at $budget)
    // --------------------------------------------------
    public static function getPostsNeedingAttention(int &$budget = 20): array
    {
        $threshold = time() - 86400;
        $posts = get_posts([
            'post_type'      => 'post',
            'post_status'    => 'publish',
            'posts_per_page' => 100,
            'orderby'        => 'modified',
            'order'          => 'DESC',
        ]);

        $results = [];
        foreach ($posts as $post) {
            $data     = SeoData::getAll($post->ID);
            $analyzed = (int) ($data['analyzed_at'] ?? 0);
            // Live re-analyze if score is stale or missing
            if (($analyzed === 0 || $analyzed < $threshold) && $budget > 0) {
                $result   = SeoAnalyzer::analyze($post->ID);
                $budget--;
                $data     = SeoData::getAll($post->ID);
            }
            $score_seo  = (int) ($data['score_seo']        ?? 0);
            $score_read = (int) ($data['score_readability'] ?? 0);
            $analyzed   = (int) ($data['analyzed_at']       ?? 0);
            if ($analyzed === 0) {
                continue;
            }
            if ($score_seo >= self::SCORE_FLOOR && $score_read >= self::SCORE_FLOOR) {
                continue;
            }
            $results[] = [
                'post'        => $post,
                'score_seo'   => $score_seo,
                'score_read'  => $score_read,
                'issue_count' => (int) ($data['issue_count'] ?? 0),
                'analyzed_at' => $analyzed,
            ];
        }

        usort($results, static fn(array $a, array $b): int => $a['score_seo'] <=> $b['score_seo']);
        return $results;
    }

    // --------------------------------------------------
    // Get published posts not updated in 6+ months
    // Live re-analyzes posts with stale or missing scores (shared budget)
    // --------------------------------------------------
    public static function getStalePosts(int &$budget = 20): array
    {
        $threshold = time() - 86400;
        $cutoff    = gmdate('Y-m-d H:i:s', strtotime('-' . self::STALE_DAYS . ' days'));
        $posts     = get_posts([
            'post_type'      => 'post',
            'post_status'    => 'publish',
            'posts_per_page' => 50,
            'orderby'        => 'modified',
            'order'          => 'ASC',
            'date_query'     => [
                [
                    'column' => 'post_modified_gmt',
                    'before' => $cutoff,
                ],
            ],
        ]);

        $results = [];
        foreach ($posts as $post) {
            $data     = SeoData::getAll($post->ID);
            $analyzed = (int) ($data['analyzed_at'] ?? 0);
            if (($analyzed === 0 || $analyzed < $threshold) && $budget > 0) {
                SeoAnalyzer::analyze($post->ID);
                $budget--;
                $data = SeoData::getAll($post->ID);
            }
            $score_seo  = (int) ($data['score_seo']        ?? 0);
            $score_read = (int) ($data['score_readability'] ?? 0);
            $results[]  = [
                'post'        => $post,
                'score_seo'   => $score_seo,
                'score_read'  => $score_read,
                'issue_count' => (int) ($data['issue_count'] ?? 0),
                'analyzed_at' => (int) ($data['analyzed_at'] ?? 0),
                'days_stale'  => (int) round((time() - strtotime($post->post_modified_gmt)) / 86400),
            ];
        }

        return $results;
    }

    // --------------------------------------------------
    // AJAX — refresh a stale post via Core AI rewrite
    // --------------------------------------------------
    public static function handleRefresh(): void
    {
        check_ajax_referer('amai_content_health', 'nonce');

        if (!current_user_can('edit_posts')) {
            wp_send_json_error(['message' => 'Unauthorized.'], 403);
        }

        $post_id = (int) ($_POST['post_id'] ?? 0);
        if ($post_id <= 0 || !current_user_can('edit_post', $post_id)) {
            wp_send_json_error(['message' => 'Invalid post.'], 400);
        }

        $post = get_post($post_id);
        if (!$post instanceof \WP_Post || $post->post_status !== 'publish') {
            wp_send_json_error(['message' => 'Post not found.'], 404);
        }

        $plain   = wp_strip_all_tags($post->post_content);
        $plain   = html_entity_decode($plain, ENT_QUOTES | ENT_HTML5, 'UTF-8');
        $plain   = trim((string) preg_replace('/\s+/', ' ', $plain));
        $excerpt = mb_substr($plain, 0, 6000);

        $prompt = 'Refresh and update this blog post to make it feel current and relevant for today\'s readers. '
            . 'Preserve all the original headings, structure, and key points. '
            . 'Update any dated references, improve clarity, tighten the writing, and ensure it reads naturally. '
            . 'Do not add new sections or change the meaning. '
            . 'Return the complete refreshed post as valid HTML using only <p> and <h2> and <h3> tags. '
            . 'Every paragraph must be wrapped in <p> tags. '
            . 'No plain text outside of tags. No other HTML tags. No preamble, no explanation. '
            . 'Use hyphens only, never em-dashes. '
            . 'Post title: "' . $post->post_title . '". '
            . 'Current content: "' . $excerpt . '"';

        $result = self::callCoreFixIt($prompt);
        if ($result === null) {
            wp_send_json_error(['message' => 'AI refresh failed. Please try again.'], 502);
        }

        $result = str_replace("\r", '', $result);
        wp_update_post(['ID' => $post_id, 'post_content' => $result]);
        SeoAnalyzer::analyze($post_id);

        wp_send_json_success(['message' => 'Post refreshed successfully.']);
    }

    // --------------------------------------------------
    // AJAX — rescan all published posts
    // --------------------------------------------------
    public static function handleRescan(): void
    {
        check_ajax_referer('amai_content_health', 'nonce');
        if (!current_user_can('edit_posts')) {
            wp_send_json_error(['message' => 'Unauthorized.'], 403);
        }
        $posts = get_posts([
            'post_type'      => 'post',
            'post_status'    => 'publish',
            'posts_per_page' => 100,
            'fields'         => 'ids',
        ]);
        foreach ($posts as $post_id) {
            SeoAnalyzer::analyze((int) $post_id);
        }
        wp_send_json_success(['count' => count($posts)]);
    }

    // --------------------------------------------------
    // Call Core /api/seo/fix-field
    // --------------------------------------------------
    private static function callCoreFixIt(string $fix_prompt): ?string
    {
        if (!defined('AMAI_HMAC_SECRET') || AMAI_HMAC_SECRET === '') {
            return null;
        }
        if (!defined('AMAI_CORE_URL') || AMAI_CORE_URL === '') {
            return null;
        }

        $method    = 'POST';
        $path      = '/api/seo/fix-field';
        $url       = rtrim(AMAI_CORE_URL, '/') . $path;
        $timestamp = (string) time();
        $nonce     = bin2hex(random_bytes(16));
        $tenant    = amai_tenant_id();
        $key_id    = 'WP_PROXY';

        $payload   = ['prompt' => $fix_prompt];
        $body      = (string) json_encode($payload);
        $raw_secret = (string) get_option('amai_tenant_hmac_secret', '');
        if ($raw_secret === '') {
            return null;
        }
        $secret    = hex2bin($raw_secret);
        $body_b64  = base64_encode(hash('sha256', $body, true));
        $canonical = implode('|', [$method, $path, $timestamp, $nonce, $tenant, $key_id, $body_b64]);
        $signature = rtrim(base64_encode(hash_hmac('sha256', $canonical, $secret, true)), "\n");

        $response = wp_remote_post($url, [
            'timeout' => 60,
            'headers' => [
                'Content-Type'       => 'application/json',
                'X-Amai-Tenant'      => $tenant,
                'X-Amai-Key-Id'      => $key_id,
                'X-Amai-Timestamp'   => $timestamp,
                'X-Amai-Nonce'       => $nonce,
                'X-Amai-Body-SHA256' => $body_b64,
                'X-Amai-Signature'   => $signature,
            ],
            'body' => $body,
        ]);

        if (is_wp_error($response)) {
            error_log('[AutoMarketer AI] ContentFreshness::callCoreFixIt - wp_error: ' . $response->get_error_message());
            return null;
        }

        $code = (int) wp_remote_retrieve_response_code($response);
        $data = json_decode(wp_remote_retrieve_body($response), true);

        if ($code !== 200 || !is_array($data) || empty($data['result'])) {
            error_log('[AutoMarketer AI] ContentFreshness::callCoreFixIt - bad response ' . $code);
            return null;
        }

        return trim((string) $data['result']);
    }
}