<?php
/**
 * Tool: generate_image
 *
 * Generate a custom image with Google's Nano Banana Pro and save it
 * directly into the user's WordPress media library. Returns the URL
 * so the model can chain it into design_page_preview's
 * additional_image_urls or insert_image_block's image_url.
 */
if (!defined('ABSPATH')) exit;

function swcp_tool_generate_image($input, $ctx) {
    $prompt        = isset($input['prompt']) ? trim((string) $input['prompt']) : '';
    $aspect_ratio  = isset($input['aspect_ratio']) ? (string) $input['aspect_ratio'] : '';
    $alt           = isset($input['alt']) ? sanitize_text_field((string) $input['alt']) : '';
    $filename_hint = isset($input['filename']) ? sanitize_file_name((string) $input['filename']) : '';
    // v0.24.8 (Joost 2026-05-17): proxy enhances the prompt with
    // quality/style keywords + brand-aware tonal hints. We pass through
    // brand_profile + intent ("hero" / "icon" / blank) so Nano Banana
    // Pro produces commercial-grade output instead of generic AI fare.
    $intent        = isset($input['intent']) ? sanitize_text_field((string) $input['intent']) : '';
    $brand_profile = (class_exists('SailWP_Copilot_Brand_Profile'))
        ? SailWP_Copilot_Brand_Profile::for_proxy()
        : null;

    if ($prompt === '') {
        return ['ok' => false, 'message' => 'I need a prompt describing the image.'];
    }

    $url = SailWP_Copilot_Plugin::get_ai_proxy_url() . '/copilot/generate-image';
    $resp = wp_remote_post($url, [
        'timeout' => 60,
        'headers' => array_filter([
            'Content-Type'   => 'application/json',
            'X-License-Key'  => SailWP_Copilot_Plugin::get_license_key() ?: null,
        ]),
        'body' => wp_json_encode([
            'prompt'        => $prompt,
            'aspect_ratio'  => $aspect_ratio,
            'intent'        => $intent,
            'brand_profile' => $brand_profile,
        ]),
    ]);
    if (is_wp_error($resp)) {
        return ['ok' => false, 'message' => 'The image 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'])) {
        $upgrade = !empty($payload['upgrade_url']) ? $payload['upgrade_url'] : $payload['pricing_url'];
        return [
            'ok'             => false,
            'limit_reached'  => true,
            'message'        => $payload['message'],
            'upgrade_url'    => $upgrade,
            'plan'           => $payload['plan'] ?? 'free',
            'inline_upgrade' => $payload['inline_upgrade'] ?? null,
        ];
    }
    if ($code >= 400 || empty($payload['ok']) || empty($payload['image_b64'])) {
        $msg = is_array($payload) && !empty($payload['message']) ? $payload['message'] : 'Could not generate the image. Try again or rephrase the prompt.';
        return ['ok' => false, 'message' => $msg];
    }

    $mime = isset($payload['mime']) ? strtolower((string) $payload['mime']) : 'image/png';
    $name = $filename_hint ?: ('sailwp-' . wp_generate_uuid4());
    $data_url = 'data:' . $mime . ';base64,' . $payload['image_b64'];

    $media = swcp_save_media_from_dataurl($data_url, $name, $mime, $alt);
    if (!$media || empty($media['url'])) {
        $why = is_array($media) && !empty($media['error']) ? ' (' . $media['error'] . ')' : '';
        return ['ok' => false, 'message' => 'Generated the image but could not save it to your media library.' . $why];
    }

    return [
        'ok'           => true,
        'message'      => 'Generated and added to your media library: ' . esc_html($media['url']),
        'attachment_id'=> (int) $media['id'],
        'url'          => $media['url'],
        'view_url'     => $media['url'],
        'mime'         => $mime,
    ];
}

/**
 * Decode a data URL and write it into wp-uploads as a real attachment.
 * Returns ['id' => int, 'url' => string] on success, or ['error' => string]
 * with a human-readable reason on failure so the caller can surface it.
 */
function swcp_save_media_from_dataurl($data_url, $name, $mime, $alt = '') {
    if (!preg_match('/^data:([^;]+);base64,(.*)$/s', (string) $data_url, $m)) {
        return ['error' => 'invalid data URL'];
    }
    // Some upstream services line-wrap base64; strip whitespace before strict decode.
    $body = base64_decode(preg_replace('/\s+/', '', $m[2]), true);
    if ($body === false || strlen($body) < 100) {
        return ['error' => 'base64 decode produced empty output'];
    }

    require_once ABSPATH . 'wp-admin/includes/file.php';
    require_once ABSPATH . 'wp-admin/includes/image.php';

    // Force the filename extension to match the real MIME type. Without this,
    // a name like "foo.png" with a JPEG body sails into the media library
    // with mismatched metadata, and any name without an extension at all is
    // rejected by wp_check_filetype unless the user has unfiltered_upload.
    $mime_lc = strtolower((string) $mime);
    $ext_for_mime = [
        'image/png'  => 'png',
        'image/jpeg' => 'jpg',
        'image/jpg'  => 'jpg',
        'image/webp' => 'webp',
        'image/gif'  => 'gif',
    ];
    $ext = isset($ext_for_mime[$mime_lc]) ? $ext_for_mime[$mime_lc] : 'png';
    $base = sanitize_file_name(preg_replace('/\.[^.]+$/', '', (string) $name) ?: ('sailwp-' . wp_generate_uuid4()));
    $name = $base . '.' . $ext;

    $upload = wp_upload_bits($name, null, $body);
    if (!empty($upload['error'])) {
        return ['error' => 'wp_upload_bits: ' . $upload['error']];
    }

    $attachment = [
        'guid'           => $upload['url'],
        'post_mime_type' => $mime_lc,
        'post_title'     => sanitize_file_name(pathinfo($name, PATHINFO_FILENAME)),
        'post_content'   => '',
        'post_status'    => 'inherit',
    ];
    $attach_id = wp_insert_attachment($attachment, $upload['file']);
    if (is_wp_error($attach_id) || !$attach_id) {
        @unlink($upload['file']);
        $why = is_wp_error($attach_id) ? $attach_id->get_error_message() : 'no attachment id';
        return ['error' => 'wp_insert_attachment: ' . $why];
    }
    $meta = wp_generate_attachment_metadata($attach_id, $upload['file']);
    wp_update_attachment_metadata($attach_id, $meta);
    if ($alt !== '') update_post_meta($attach_id, '_wp_attachment_image_alt', $alt);
    update_post_meta($attach_id, '_swcp_uploaded_via_copilot', 1);

    $url = wp_get_attachment_url($attach_id);
    if (!$url) {
        return ['error' => 'attachment saved but URL missing'];
    }
    return ['id' => (int) $attach_id, 'url' => $url];
}
