<?php
declare(strict_types=1);
// ==================================================
// Nuclear Fancy Pants Edition™
// File: /home/ploi/automarketer-ai.com/public/wp-content/plugins/automarketer-ai/includes/class-comment-responder.php
// Description: Comment responder -- AI draft generation and platform reply posting for Facebook, Instagram, X, WordPress, and WooCommerce - NUCLEAR+++
// Last Edited: 2026-05-15
// ==================================================

namespace AutoMarketerAI;

use AutoMarketerAI\FacebookAuth;
use AutoMarketerAI\XAuth;
use AutoMarketerAI\KeyVault;

// Abort if called directly.
if (!defined('ABSPATH')) {
    exit;
}

class CommentResponder
{
    // --------------------------------------------------
    // Graph API base URL.
    // --------------------------------------------------
    private const GRAPH_BASE = 'https://graph.facebook.com/v19.0';

    // --------------------------------------------------
    // X API base URL.
    // --------------------------------------------------
    private const X_API_BASE = 'https://api.x.com/2';

    // --------------------------------------------------
    // Claude API endpoint.
    // --------------------------------------------------
    private const CLAUDE_API_URL = 'https://api.anthropic.com/v1/messages';

    // --------------------------------------------------
    // Claude model for reply generation.
    // --------------------------------------------------
    private const CLAUDE_MODEL = 'claude-opus-4-20250514';

    // --------------------------------------------------
    // Default tones per channel when no wp_option is set.
    // --------------------------------------------------
    private const DEFAULT_TONES = [
        'facebook'    => 'friendly',
        'instagram'   => 'warm',
        'x'           => 'professional',
        'wordpress'   => 'friendly',
        'woocommerce' => 'friendly',
    ];

    // --------------------------------------------------
    // Tone guidance used inside the prompt.
    // --------------------------------------------------
    private const TONE_GUIDANCE = [
        'friendly'     => 'conversational, warm, and approachable -- like a helpful neighbor',
        'warm'         => 'genuine and personal -- use the commenter\'s name if available, keep it human',
        'professional' => 'polished and concise -- no slang, stay on-brand and confident',
        'playful'      => 'light-hearted, upbeat, and fun -- a touch of personality goes a long way',
        'formal'       => 'respectful and measured -- complete sentences, no contractions',
    ];

    // --------------------------------------------------
    // Channels that reply via wp_insert_comment().
    // --------------------------------------------------
    private const WP_CHANNELS = ['wordpress', 'woocommerce'];

    // --------------------------------------------------
    // Entry point called by CommentFetcher after a new
    // comment row is inserted. Dispatches based on the
    // reply mode set for the comment's channel.
    // --------------------------------------------------
    public static function handleNew(int $comment_id): void
    {
        global $wpdb;
        $table = $wpdb->prefix . 'amai_social_comments';

        $row = $wpdb->get_row(
            $wpdb->prepare(
                "SELECT * FROM `{$table}` WHERE id = %d LIMIT 1",
                $comment_id
            ),
            ARRAY_A
        );

        if (!is_array($row)) {
            return;
        }

        $channel = (string) ($row['channel'] ?? '');
        $allowed = ['facebook', 'instagram', 'x', 'wordpress', 'woocommerce'];
        if (!in_array($channel, $allowed, true)) {
            return;
        }

        $mode = (string) get_option('amai_comment_reply_mode_' . $channel, 'manual');

        if ($mode === 'manual') {
            // Nothing to do -- client acts from the inbox UI.
            return;
        }

        $draft = self::generateDraft($row);
        if ($draft === '') {
            // AI generation failed -- leave as new so client can reply manually.
            return;
        }

        if ($mode === 'ai_assisted') {
            $wpdb->update(
                $table,
                [
                    'ai_draft'   => $draft,
                    'status'     => 'pending_review',
                    'updated_at' => gmdate('Y-m-d H:i:s'),
                ],
                ['id' => $comment_id],
                ['%s', '%s', '%s'],
                ['%d']
            );
            return;
        }

        if ($mode === 'autopilot') {
            $posted = self::dispatchReply($channel, $row, $draft);
            if ($posted) {
                $wpdb->update(
                    $table,
                    [
                        'status'         => 'replied',
                        'reply_content'  => $draft,
                        'replied_at'     => gmdate('Y-m-d H:i:s'),
                        'updated_at'     => gmdate('Y-m-d H:i:s'),
                    ],
                    ['id' => $comment_id],
                    ['%s', '%s', '%s', '%s'],
                    ['%d']
                );
            }
            // On failure: leave as new. Next fetch cycle will not re-trigger
            // handleNew() for existing rows (upsert skips existing).
        }
    }

    // --------------------------------------------------
    // Public: post a reply for a comment row. Called from
    // AJAX when the client approves a pending_review draft
    // or submits a manual reply from the inbox UI.
    // Returns true on success, false on failure.
    // --------------------------------------------------
    public static function postReply(int $comment_id, string $reply_text): bool
    {
        global $wpdb;
        $table = $wpdb->prefix . 'amai_social_comments';

        $reply_text = trim($reply_text);
        if ($reply_text === '') {
            return false;
        }

        $row = $wpdb->get_row(
            $wpdb->prepare(
                "SELECT * FROM `{$table}` WHERE id = %d LIMIT 1",
                $comment_id
            ),
            ARRAY_A
        );

        if (!is_array($row)) {
            return false;
        }

        $channel = (string) ($row['channel'] ?? '');
        $allowed = ['facebook', 'instagram', 'x', 'wordpress', 'woocommerce'];
        if (!in_array($channel, $allowed, true)) {
            return false;
        }

        $posted = self::dispatchReply($channel, $row, $reply_text);

        if ($posted) {
            $wpdb->update(
                $table,
                [
                    'status'        => 'replied',
                    'reply_content' => $reply_text,
                    'replied_at'    => gmdate('Y-m-d H:i:s'),
                    'updated_at'    => gmdate('Y-m-d H:i:s'),
                ],
                ['id' => $comment_id],
                ['%s', '%s', '%s', '%s'],
                ['%d']
            );
        }

        return $posted;
    }

    // --------------------------------------------------
    // Generate an AI reply draft for a comment row.
    // Returns the reply string or empty string on failure.
    // --------------------------------------------------
    private static function generateDraft(array $row): string
    {
        $channel      = (string) ($row['channel'] ?? '');
        $comment_text = (string) ($row['content'] ?? '');
        $author_name  = (string) ($row['author_name'] ?? '');
        $post_content = self::lookupPostContent((string) ($row['platform_post_id'] ?? ''), $channel);

        $tone_key  = (string) get_option('amai_comment_reply_tone_' . $channel, self::DEFAULT_TONES[$channel] ?? 'friendly');
        $tone_desc = self::TONE_GUIDANCE[$tone_key] ?? self::TONE_GUIDANCE['friendly'];

        $channel_label = match ($channel) {
            'facebook'    => 'Facebook',
            'instagram'   => 'Instagram',
            'x'           => 'X (Twitter)',
            'wordpress'   => 'your website blog',
            'woocommerce' => 'your WooCommerce product page',
            default       => $channel,
        };

        $post_context = $post_content !== ''
            ? "The original post or product the comment was left on:\n\"\"\"\n{$post_content}\n\"\"\"\n\n"
            : '';

        $author_ref = $author_name !== '' ? "The commenter's name is {$author_name}." : '';

        $char_limit = $channel === 'x' ? 'under 280 characters' : 'under 300 characters';

        $wp_extra = '';
        if (in_array($channel, ['wordpress', 'woocommerce'], true)) {
            $wp_extra = "- This is a reply on a website blog or product page -- keep it short, genuine, and human. 1-3 sentences maximum.\n- Do not pitch, sell, or promote anything.\n- Do not say things like 'we appreciate your support' or 'thank you for being part of our community'.\n- Sound like a real person, not a marketing department.\n";
        }

        $prompt = <<<PROMPT
You are replying to a comment left on {$channel_label}.

{$post_context}The comment:
"""
{$comment_text}
"""

{$author_ref}

Tone: {$tone_desc}.

Rules:
- {$char_limit} maximum. Shorter is better.
- {$wp_extra}- Do not use hashtags.
- Do not invent features, services, or capabilities the business does not have.
- Do not use em-dashes. Use plain hyphens if a dash is needed.
- Reply ONLY with the reply text -- no preamble, no explanation, no quotation marks around it.
PROMPT;

        $api_key_enc = (string) get_option('amai_api_key_ai-claude', '');
        if ($api_key_enc === '') {
            return '';
        }
        $api_key = KeyVault::decrypt($api_key_enc);
        if ($api_key === '') {
            return '';
        }

        $response = wp_remote_post(
            self::CLAUDE_API_URL,
            [
                'timeout' => 60,
                'headers' => [
                    'x-api-key'         => $api_key,
                    'anthropic-version' => '2023-06-01',
                    'Content-Type'      => 'application/json',
                ],
                'body' => wp_json_encode([
                    'model'      => self::CLAUDE_MODEL,
                    'max_tokens' => 1024,
                    'messages'   => [
                        ['role' => 'user', 'content' => $prompt],
                    ],
                ]),
            ]
        );

        if (is_wp_error($response)) {
            return '';
        }

        $code = (int) wp_remote_retrieve_response_code($response);
        if ($code !== 200) {
            return '';
        }

        $body = json_decode(wp_remote_retrieve_body($response), true);
        if (!is_array($body) || empty($body['content'][0]['text'])) {
            return '';
        }

        return trim((string) $body['content'][0]['text']);
    }

    // --------------------------------------------------
    // Route a reply to the correct platform API.
    // Returns true if the platform accepted the reply.
    // --------------------------------------------------
    private static function dispatchReply(string $channel, array $row, string $reply_text): bool
    {
        return match ($channel) {
            'facebook'               => self::replyFacebook($row, $reply_text),
            'instagram'              => self::replyInstagram($row, $reply_text),
            'x'                      => self::replyX($row, $reply_text),
            'wordpress', 'woocommerce' => self::replyWordPress($row, $reply_text),
            default                  => false,
        };
    }

    // --------------------------------------------------
    // Post a reply to a Facebook comment.
    // Endpoint: POST /{comment-id}/comments
    // --------------------------------------------------
    private static function replyFacebook(array $row, string $reply_text): bool
    {
        $token = FacebookAuth::getPageToken();
        if ($token === null) {
            return false;
        }

        $comment_id = (string) ($row['platform_comment_id'] ?? '');
        if ($comment_id === '') {
            return false;
        }

        $url = self::GRAPH_BASE . '/' . $comment_id . '/comments';

        $response = wp_remote_post(
            $url,
            [
                'timeout' => 30,
                'headers' => [
                    'Content-Type' => 'application/json',
                ],
                'body' => wp_json_encode([
                    'message'      => $reply_text,
                    'access_token' => $token,
                ]),
            ]
        );

        if (is_wp_error($response)) {
            return false;
        }

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

        return $code === 200 && is_array($body) && !empty($body['id']);
    }

    // --------------------------------------------------
    // Post a reply to an Instagram comment.
    // Endpoint: POST /{comment-id}/replies
    // --------------------------------------------------
    private static function replyInstagram(array $row, string $reply_text): bool
    {
        $token = FacebookAuth::getPageToken();
        if ($token === null) {
            return false;
        }

        $comment_id = (string) ($row['platform_comment_id'] ?? '');
        if ($comment_id === '') {
            return false;
        }

        $url = self::GRAPH_BASE . '/' . $comment_id . '/replies';

        $response = wp_remote_post(
            $url,
            [
                'timeout' => 30,
                'headers' => [
                    'Content-Type' => 'application/json',
                ],
                'body' => wp_json_encode([
                    'message'      => $reply_text,
                    'access_token' => $token,
                ]),
            ]
        );

        if (is_wp_error($response)) {
            return false;
        }

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

        return $code === 200 && is_array($body) && !empty($body['id']);
    }

    // --------------------------------------------------
    // Post a reply to an X tweet.
    // Endpoint: POST /2/tweets with reply.in_reply_to_tweet_id
    // --------------------------------------------------
    private static function replyX(array $row, string $reply_text): bool
    {
        $token = XAuth::getAccessToken();
        if ($token === null) {
            return false;
        }

        $tweet_id = (string) ($row['platform_comment_id'] ?? '');
        if ($tweet_id === '') {
            return false;
        }

        $response = wp_remote_post(
            self::X_API_BASE . '/tweets',
            [
                'timeout' => 30,
                'headers' => [
                    'Authorization' => 'Bearer ' . $token,
                    'Content-Type'  => 'application/json',
                ],
                'body' => wp_json_encode([
                    'text'  => $reply_text,
                    'reply' => [
                        'in_reply_to_tweet_id' => $tweet_id,
                    ],
                ]),
            ]
        );

        if (is_wp_error($response)) {
            return false;
        }

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

        return $code === 201 && is_array($body) && !empty($body['data']['id']);
    }

    // --------------------------------------------------
    // Post a reply to a WordPress comment or WooCommerce review.
    // Uses wp_insert_comment() -- no platform token needed.
    // The wp_comment_id column on the row contains the parent
    // comment ID being replied to.
    // --------------------------------------------------
    private static function replyWordPress(array $row, string $reply_text): bool
    {
        $wp_comment_id = (int) ($row['wp_comment_id'] ?? 0);
        if ($wp_comment_id <= 0) {
            return false;
        }

        $parent_comment = get_comment($wp_comment_id);
        if (!$parent_comment instanceof \WP_Comment) {
            return false;
        }

        $post_id = (int) $parent_comment->comment_post_ID;
        if ($post_id <= 0) {
            return false;
        }

        $site_name = (string) get_bloginfo('name');
        $admin_email = (string) get_option('admin_email', '');

        $inserted_id = wp_insert_comment([
            'comment_post_ID'      => $post_id,
            'comment_author'       => $site_name !== '' ? $site_name : 'Site Admin',
            'comment_author_email' => $admin_email,
            'comment_author_url'   => (string) get_bloginfo('url'),
            'comment_content'      => $reply_text,
            'comment_parent'       => $wp_comment_id,
            'comment_approved'     => 1,
            'comment_type'         => ($row['channel'] === 'woocommerce') ? 'review' : '',
        ]);

        return $inserted_id !== false && $inserted_id > 0;
    }

    // --------------------------------------------------
    // Look up the original post content from
    // wp_amai_scheduled_posts by platform_post_id.
    // For WordPress/WooCommerce channels, falls back to
    // the actual post_content from wp_posts.
    // Returns empty string if not found.
    // --------------------------------------------------
    private static function lookupPostContent(string $platform_post_id, string $channel): string
    {
        if ($platform_post_id === '') {
            return '';
        }

        // WordPress and WooCommerce: platform_post_id is the WP post ID.
        if (in_array($channel, self::WP_CHANNELS, true)) {
            $post = get_post((int) $platform_post_id);
            if (!$post instanceof \WP_Post) {
                return '';
            }
            return wp_strip_all_tags((string) $post->post_content);
        }

        global $wpdb;
        $table = $wpdb->prefix . 'amai_scheduled_posts';

        // Map channel to the correct platform ID column.
        $column_map = [
            'facebook'  => 'facebook_post_id',
            'instagram' => 'instagram_media_id',
            'x'         => 'x_post_id',
        ];
        $column = $column_map[$channel] ?? '';
        if ($column === '') {
            return '';
        }

        $content = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT post_content FROM `{$table}` WHERE `{$column}` = %s LIMIT 1",
                $platform_post_id
            )
        );

        return is_string($content) ? $content : '';
    }

    // --------------------------------------------------
    // Public wrapper for on-demand draft generation from
    // the AJAX handler in class-settings-page.php.
    // --------------------------------------------------
    public static function generateDraftPublic(array $row): string
    {
        return self::generateDraft($row);
    }
}