<?php
/**
 * Tool: write_blog_draft
 *
 * Generate a complete blog post draft (title + Gutenberg content +
 * excerpt + meta description + optional featured image) and write it
 * straight into the post the user has open. Targets post_type=post
 * specifically — for pages, use design_page_preview instead.
 *
 * v0.25.0 (Joost 2026-05-17). Gap-fix: the Co-pilot had no way to
 * draft article content, so "write me a short article about yoga"
 * from inside the post editor did nothing.
 */
if (!defined('ABSPATH')) exit;

function swcp_tool_write_blog_draft($input, $ctx) {
    $topic         = isset($input['topic']) ? trim((string) $input['topic']) : '';
    $length        = isset($input['length']) ? strtolower((string) $input['length']) : 'medium';
    $include_image = !empty($input['include_image']);
    $include_seo   = !isset($input['include_seo']) || !empty($input['include_seo']);
    $target_post_id = isset($input['post_id']) && (int) $input['post_id'] > 0
        ? (int) $input['post_id']
        : (isset($ctx['post_id']) ? (int) $ctx['post_id'] : 0);
    error_log('[swcp blog-draft] ENTRY topic="' . substr($topic, 0, 60) . '" ctx_post_id=' . (isset($ctx['post_id']) ? (int)$ctx['post_id'] : -1) . ' input_post_id=' . (isset($input['post_id']) ? (int)$input['post_id'] : -1) . ' target=' . $target_post_id . ' user_id=' . get_current_user_id());

    if ($topic === '') {
        return ['ok' => false, 'message' => 'I need a topic to write about.'];
    }
    if (!in_array($length, ['short', 'medium', 'long'], true)) {
        $length = 'medium';
    }

    // Verify the post exists and is editable. If not, create a fresh
    // draft so the user gets a starting point either way.
    $created_new = false;
    $post = $target_post_id ? get_post($target_post_id) : null;
    if (!$post || $post->post_type !== 'post' || $post->post_status === 'trash') {
        // Don't silently overwrite a page when the user is on the editor
        // for a non-post type. Create a new Posts draft.
        $new_id = wp_insert_post([
            'post_type'   => 'post',
            'post_status' => 'draft',
            'post_title'  => $topic,
        ], true);
        if (is_wp_error($new_id) || !$new_id) {
            return ['ok' => false, 'message' => 'Could not create a new draft to write into.'];
        }
        $target_post_id = (int) $new_id;
        $post = get_post($target_post_id);
        $created_new = true;
    }

    // Capability is already gated at the REST route (cookie auth → edit_posts,
    // license-key → site-scoped). No per-post re-check here because that
    // breaks the license-key path (no current user → false negative).

    // Call the proxy to generate the draft. Proxy returns:
    //   { ok, title, gutenberg_content, excerpt, meta_description, featured_image_prompt }
    $brand_profile = (class_exists('SailWP_Copilot_Brand_Profile'))
        ? SailWP_Copilot_Brand_Profile::for_proxy()
        : null;

    $url = SailWP_Copilot_Plugin::get_ai_proxy_url() . '/copilot/write-blog-draft';
    $resp = wp_remote_post($url, [
        'timeout' => 90,
        'headers' => array_filter([
            'Content-Type'   => 'application/json',
            'X-License-Key'  => SailWP_Copilot_Plugin::get_license_key() ?: null,
            'X-Site-API-Key' => SailWP_Copilot_Plugin::get_site_api_key() ?: null,
        ]),
        'body' => wp_json_encode([
            'topic'         => $topic,
            'length'        => $length,
            'include_image' => $include_image,
            'include_seo'   => $include_seo,
            'brand_profile' => $brand_profile,
            'locale'        => get_locale(),
        ]),
    ]);
    if (is_wp_error($resp)) {
        return ['ok' => false, 'message' => 'The writing service did not respond. Try again in a moment.'];
    }
    $code    = wp_remote_retrieve_response_code($resp);
    $payload = json_decode(wp_remote_retrieve_body($resp), true);
    if ($code === 402 && is_array($payload) && !empty($payload['limit_reached'])) {
        return [
            'ok'             => false,
            'limit_reached'  => true,
            'message'        => $payload['message'] ?? 'Daily limit reached. Upgrade to keep writing.',
            'upgrade_url'    => $payload['upgrade_url'] ?? ($payload['pricing_url'] ?? ''),
            'inline_upgrade' => $payload['inline_upgrade'] ?? null,
        ];
    }
    if ($code >= 400 || empty($payload['ok']) || empty($payload['gutenberg_content'])) {
        $msg = is_array($payload) && !empty($payload['message']) ? $payload['message'] : 'Could not generate the draft. Try a different topic.';
        return ['ok' => false, 'message' => $msg];
    }

    $title       = isset($payload['title']) ? sanitize_text_field((string) $payload['title']) : $topic;
    $content     = (string) $payload['gutenberg_content'];
    $excerpt     = isset($payload['excerpt']) ? sanitize_textarea_field((string) $payload['excerpt']) : '';
    $meta_desc   = isset($payload['meta_description']) ? sanitize_textarea_field((string) $payload['meta_description']) : '';
    $img_prompt  = isset($payload['featured_image_prompt']) ? trim((string) $payload['featured_image_prompt']) : '';

    // Write into the post. wp_update_post expects SLASHED data (it
    // internally wp_unslash's before saving), so we wp_slash() up front.
    // Without this, content containing literal " or ' becomes mangled
    // and KSES filters silently strip Gutenberg block comments under
    // some configurations.
    error_log('[swcp blog-draft] PRE-UPDATE target=' . $target_post_id . ' title_len=' . strlen($title) . ' content_len=' . strlen($content));
    $update = wp_update_post(wp_slash([
        'ID'           => $target_post_id,
        'post_title'   => $title,
        'post_content' => $content,
        'post_excerpt' => $excerpt,
        'post_status'  => 'draft', // promote auto-draft → draft so it shows in lists
    ]), true);
    error_log('[swcp blog-draft] POST-UPDATE result=' . (is_wp_error($update) ? 'ERR:' . $update->get_error_message() : (string) $update));
    if (is_wp_error($update)) {
        return ['ok' => false, 'message' => 'Generated the draft but could not save it: ' . $update->get_error_message()];
    }
    // Verify the write actually landed — wp_update_post can return non-error
    // even when filters silently dropped the content (kses, multisite).
    $check = get_post($target_post_id);
    if (!$check || trim((string) $check->post_title) === '' || trim((string) $check->post_content) === '') {
        error_log('[swcp blog-draft] VERIFY-FAIL post_title="' . ($check ? $check->post_title : 'NO_POST') . '" content_len=' . ($check ? strlen($check->post_content) : 0));
        return ['ok' => false, 'message' => 'Generated the draft but the save did not stick. Most likely cause: your role cannot save HTML comments. Check that you are an admin/editor.'];
    }

    // SEO meta — write to whichever plugin is present. Both Yoast and
    // Rank Math expose meta_description via well-known post-meta keys.
    if ($include_seo && $meta_desc !== '') {
        update_post_meta($target_post_id, '_yoast_wpseo_metadesc', $meta_desc);
        update_post_meta($target_post_id, 'rank_math_description', $meta_desc);
    }

    // Featured image — chain through generate_image so it uses the same
    // brand-aware pipeline + media-library plumbing.
    $image_url = '';
    $image_id  = 0;
    if ($include_image && $img_prompt !== '' && function_exists('swcp_tool_generate_image')) {
        $img_result = swcp_tool_generate_image([
            'prompt'       => $img_prompt,
            'aspect_ratio' => '16:9',
            'intent'       => 'hero',
            'alt'          => $title,
        ], $ctx);
        if (is_array($img_result) && !empty($img_result['ok']) && !empty($img_result['attachment_id'])) {
            $image_id = (int) $img_result['attachment_id'];
            set_post_thumbnail($target_post_id, $image_id);
            $image_url = (string) ($img_result['url'] ?? '');
        }
    }

    // Build user-facing message: short, action-led, names what we did.
    // Mention WHERE the draft lives so Claude can echo this cleanly:
    // - created_new=true → we are about to redirect the tab, so say "opening it now"
    // - in-place        → editor will auto-refresh, so say "refreshing your editor"
    $extras = [];
    if ($image_url) $extras[] = 'with a featured image';
    if ($include_seo && $meta_desc) $extras[] = 'and SEO meta';
    $extra_clause = $extras ? ' ' . implode(' ', $extras) : '';
    if ($created_new) {
        $human = 'Created a new draft "' . $title . '"' . $extra_clause . '. Opening it now.';
    } else {
        $human = 'Drafted into your post "' . $title . '"' . $extra_clause . '. Refreshing your editor.';
    }

    // get_edit_post_link returns null when there is no current user (the
    // license-key REST path). Build the canonical wp-admin URL ourselves
    // so the rail's redirect_to actually points somewhere.
    $edit_url = get_edit_post_link($target_post_id, 'raw');
    if (!$edit_url) {
        $edit_url = admin_url('post.php?post=' . $target_post_id . '&action=edit');
    }

    $result = [
        'ok'             => true,
        'message'        => $human,
        'post_id'        => $target_post_id,
        'title'          => $title,
        'edit_url'       => $edit_url,
        'preview_url'    => get_preview_post_link($target_post_id),
        'created_new'    => $created_new,
        'has_image'      => (bool) $image_url,
        'image_url'      => $image_url,
        'image_id'       => $image_id,
        'wrote_seo_meta' => (bool) ($include_seo && $meta_desc),
        // v0.25.4: raw Gutenberg + excerpt so the rail can inject it live
        // into the currently-open editor via wp.data — no reload, the
        // article appears under the user's cursor.
        'gutenberg_content' => $content,
        'excerpt'           => $excerpt,
        'meta_description'  => $meta_desc,
    ];
    // New draft → take the user there. Existing post → just reload the
    // editor in place so the draft surfaces without a manual F5. v0.25.1
    // (Joost 2026-05-17): the original v0.25.0 said "refresh the page"
    // but on /wp-admin/post-new.php that just gives another blank form.
    if ($created_new) {
        $result['redirect_to']      = $edit_url;
        $result['requires_refresh'] = false;
    } else {
        $result['requires_refresh'] = true;
    }
    return $result;
}
