<?php
/**
 * SailWP Co-pilot — tool dispatcher.
 *
 * Single REST route /sailwp-copilot/v1/execute receives:
 *   { tool: <name>, input: <object>, page_id: <optional int> }
 * Dispatches to swcp_tool_<name>($input, $ctx) and returns the result.
 *
 * Tool implementations live in includes/tools/<tool>.php. Each must:
 *   - return ['ok' => bool, 'message' => string, ...optional details]
 *   - accept ($input, $ctx) where $ctx has at least post_id (current page).
 */
if (!defined('ABSPATH')) exit;

require_once SAILWP_COPILOT_DIR . 'includes/tools/helpers.php';
require_once SAILWP_COPILOT_DIR . 'includes/tools/redesign-page.php';
require_once SAILWP_COPILOT_DIR . 'includes/tools/design-page-preview.php';
require_once SAILWP_COPILOT_DIR . 'includes/tools/iterate-page-design.php';
require_once SAILWP_COPILOT_DIR . 'includes/tools/apply-page-design.php';
require_once SAILWP_COPILOT_DIR . 'includes/tools/convert-testimonials-to-carousel.php';
require_once SAILWP_COPILOT_DIR . 'includes/tools/fix-duplicate-titles.php';
require_once SAILWP_COPILOT_DIR . 'includes/tools/normalize-headings.php';
require_once SAILWP_COPILOT_DIR . 'includes/tools/wire-contact-form-to-email.php';
require_once SAILWP_COPILOT_DIR . 'includes/tools/swap-or-add-image.php';
require_once SAILWP_COPILOT_DIR . 'includes/tools/insert-image-block.php';
require_once SAILWP_COPILOT_DIR . 'includes/tools/generate-image.php';
require_once SAILWP_COPILOT_DIR . 'includes/tools/generate-video.php';
require_once SAILWP_COPILOT_DIR . 'includes/tools/generate-music.php';
require_once SAILWP_COPILOT_DIR . 'includes/tools/restore-page-version.php';
require_once SAILWP_COPILOT_DIR . 'includes/tools/update-page-text.php';
require_once SAILWP_COPILOT_DIR . 'includes/tools/block-locator.php';
require_once SAILWP_COPILOT_DIR . 'includes/tools/swap-image-in-block.php';
require_once SAILWP_COPILOT_DIR . 'includes/tools/update-block-attrs.php';
require_once SAILWP_COPILOT_DIR . 'includes/tools/delete-block.php';
require_once SAILWP_COPILOT_DIR . 'includes/tools/insert-block.php';
require_once SAILWP_COPILOT_DIR . 'includes/tools/navigate-to.php';
require_once SAILWP_COPILOT_DIR . 'includes/tools/write-blog-draft.php';

class SailWP_Copilot_Tools {
    const TOOL_HANDLERS = [
        'redesign_page'                    => 'swcp_tool_redesign_page',
        'design_page_preview'              => 'swcp_tool_design_page_preview',
        'iterate_page_design'              => 'swcp_tool_iterate_page_design',
        'apply_page_design'                => 'swcp_tool_apply_page_design',
        'update_page_text'                 => 'swcp_tool_update_page_text',
        'swap_image_in_block'              => 'swcp_tool_swap_image_in_block',
        'update_block_attrs'               => 'swcp_tool_update_block_attrs',
        'delete_block'                     => 'swcp_tool_delete_block',
        'insert_block'                     => 'swcp_tool_insert_block',
        'convert_testimonials_to_carousel' => 'swcp_tool_convert_testimonials_to_carousel',
        'fix_duplicate_titles'             => 'swcp_tool_fix_duplicate_titles',
        'normalize_headings'               => 'swcp_tool_normalize_headings',
        'wire_contact_form_to_email'       => 'swcp_tool_wire_contact_form_to_email',
        'swap_or_add_image'                => 'swcp_tool_swap_or_add_image',
        'insert_image_block'               => 'swcp_tool_insert_image_block',
        'generate_image'                   => 'swcp_tool_generate_image',
        'generate_video'                   => 'swcp_tool_generate_video',
        'generate_music'                   => 'swcp_tool_generate_music',
        'restore_page_version'             => 'swcp_tool_restore_page_version',
        'navigate_to'                      => 'swcp_tool_navigate_to',
        'write_blog_draft'                 => 'swcp_tool_write_blog_draft',
    ];

    public function __construct() {
        add_action('rest_api_init',         [$this, 'register_routes']);
        add_action('admin_enqueue_scripts', [$this, 'enqueue_styles']);
        add_action('wp_enqueue_scripts',    [$this, 'enqueue_styles']);
    }

    public function register_routes() {
        // Permission helper: accept WP cookie auth (logged-in editor) OR a
        // valid X-License-Key header that matches this site's stored
        // copilot license. The license-key path lets the cloud dashboard
        // at ai.sailwp.com/app dispatch tool calls across sites without
        // a per-site WP session.
        $cookie_or_license = function (WP_REST_Request $request) {
            if (current_user_can('edit_posts')) return true;
            $key = $request->get_header('x-license-key');
            if (!$key) return false;
            $stored = SailWP_Copilot_Plugin::get_license_key();
            if (!$stored) return false;
            return hash_equals($stored, (string) $key);
        };

        register_rest_route(SailWP_Copilot_REST::NAMESPACE_V1, '/execute', [
            'methods'             => 'POST',
            'callback'            => [$this, 'handle_execute'],
            'permission_callback' => $cookie_or_license,
        ]);

        register_rest_route(SailWP_Copilot_REST::NAMESPACE_V1, '/chat-with-tools', [
            'methods'             => 'POST',
            'callback'            => [$this, 'handle_chat_with_tools'],
            'permission_callback' => $cookie_or_license,
        ]);

        register_rest_route(SailWP_Copilot_REST::NAMESPACE_V1, '/extract-text', [
            'methods'             => 'POST',
            'callback'            => [$this, 'handle_extract_text'],
            'permission_callback' => function () {
                return current_user_can('edit_posts');
            },
        ]);

        register_rest_route(SailWP_Copilot_REST::NAMESPACE_V1, '/upload-image', [
            'methods'             => 'POST',
            'callback'            => [$this, 'handle_upload_image'],
            'permission_callback' => function () {
                return current_user_can('upload_files');
            },
        ]);

        register_rest_route(SailWP_Copilot_REST::NAMESPACE_V1, '/discard-preview', [
            'methods'             => 'POST',
            'callback'            => [$this, 'handle_discard_preview'],
            'permission_callback' => function () {
                return current_user_can('edit_posts');
            },
        ]);

        register_rest_route(SailWP_Copilot_REST::NAMESPACE_V1, '/self-test', [
            'methods'             => 'GET',
            'callback'            => [$this, 'handle_self_test'],
            'permission_callback' => function () {
                return current_user_can('manage_options');
            },
        ]);
    }

    /**
     * Runtime smoke test. Returns ok=true only if every TOOL_HANDLERS
     * entry resolves to a defined function. Used by deploy.sh to verify
     * a fresh upload actually loads cleanly before declaring victory.
     * No writes, no AI calls — pure introspection.
     */
    public function handle_self_test(WP_REST_Request $request) {
        $missing = [];
        foreach (self::TOOL_HANDLERS as $tool => $handler) {
            if (!function_exists($handler)) {
                $missing[] = ['tool' => $tool, 'handler' => $handler];
            }
        }
        return rest_ensure_response([
            'ok'             => empty($missing),
            'version'        => defined('SAILWP_COPILOT_VERSION') ? SAILWP_COPILOT_VERSION : 'unknown',
            'tools_total'    => count(self::TOOL_HANDLERS),
            'tools_healthy'  => count(self::TOOL_HANDLERS) - count($missing),
            'missing'        => $missing,
            'php_version'    => PHP_VERSION,
        ]);
    }

    /**
     * Hard-delete a preview draft. Called when the user hits Discard so
     * we do not leave orphan drafts piling up in the trash.
     */
    public function handle_discard_preview(WP_REST_Request $request) {
        $preview_id = (int) $request->get_param('preview_id');
        if (!$preview_id) return new WP_Error('preview_id_required', 'preview_id is required', ['status' => 400]);
        $post = get_post($preview_id);
        if (!$post || $post->post_type !== 'page') {
            return rest_ensure_response(['ok' => true, 'note' => 'already gone']);
        }
        if (!get_post_meta($preview_id, '_swcp_is_preview', true)) {
            return new WP_Error('not_a_preview', 'That page is not a co-pilot preview', ['status' => 400]);
        }
        wp_delete_post($preview_id, true); // force delete (skip trash)
        if (function_exists('swcp_log_remote_event')) {
            swcp_log_remote_event('preview_discarded', ['preview_id' => $preview_id]);
        }
        return rest_ensure_response(['ok' => true, 'preview_id' => $preview_id]);
    }

    /**
     * Save a base64-encoded image straight from the rail into the WP
     * media library. Returns the attachment URL so the design tool can
     * reference it like any other library image.
     */
    public function handle_upload_image(WP_REST_Request $request) {
        $name    = (string) $request->get_param('name');
        $dataUrl = (string) $request->get_param('dataUrl');

        if (!preg_match('/^data:([^;]+);base64,(.+)$/', $dataUrl, $m)) {
            return new WP_Error('invalid_dataurl', 'Invalid image data URL', ['status' => 400]);
        }
        $mime = $m[1];
        $allowed = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
        if (!in_array($mime, $allowed, true)) {
            return new WP_Error('unsupported_type', 'Unsupported image type: ' . $mime, ['status' => 400]);
        }
        $body = base64_decode($m[2], true);
        if ($body === false) {
            return new WP_Error('decode_failed', 'Could not decode image data', ['status' => 400]);
        }
        if (strlen($body) > 10 * 1024 * 1024) {
            return new WP_Error('too_large', 'Image is larger than 10 MB', ['status' => 413]);
        }

        // Sanitize filename + ensure the right extension for the mime type.
        $name = sanitize_file_name($name ?: 'sailwp-upload.jpg');
        $ext_map = [
            'image/jpeg' => 'jpg', 'image/png' => 'png',
            'image/gif'  => 'gif', 'image/webp' => 'webp',
        ];
        $expected_ext = $ext_map[$mime];
        if (!preg_match('/\.' . $expected_ext . '$/i', $name) && !preg_match('/\.jpeg$/i', $name)) {
            $name = preg_replace('/\.[^.]+$/', '', $name) . '.' . $expected_ext;
        }

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

        $upload = wp_upload_bits($name, null, $body);
        if (!empty($upload['error'])) {
            return new WP_Error('upload_failed', $upload['error'], ['status' => 500]);
        }

        $attachment = [
            'guid'           => $upload['url'],
            'post_mime_type' => $mime,
            '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']);
            return new WP_Error('attach_failed', 'Could not register attachment', ['status' => 500]);
        }
        $attach_data = wp_generate_attachment_metadata($attach_id, $upload['file']);
        wp_update_attachment_metadata($attach_id, $attach_data);
        update_post_meta($attach_id, '_swcp_uploaded_via_copilot', 1);

        return rest_ensure_response([
            'ok'   => true,
            'id'   => (int) $attach_id,
            'url'  => wp_get_attachment_url($attach_id),
            'name' => $name,
            'mime' => $mime,
        ]);
    }

    /**
     * Forward a document upload to the AI proxy for text extraction.
     * Body: { dataUrl, name, kind }
     */
    public function handle_extract_text(WP_REST_Request $request) {
        $dataUrl = (string) $request->get_param('dataUrl');
        $name    = (string) $request->get_param('name');
        $kind    = (string) $request->get_param('kind');
        if (!$dataUrl) {
            return new WP_Error('dataurl_required', 'dataUrl is required', ['status' => 400]);
        }

        $url = SailWP_Copilot_Plugin::get_ai_proxy_url() . '/copilot/extract-text';
        $response = wp_remote_post($url, [
            'timeout' => 60,
            '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([
                'dataUrl' => $dataUrl,
                'name'    => $name,
                'kind'    => $kind,
            ]),
        ]);
        if (is_wp_error($response)) return $response;
        $payload = json_decode(wp_remote_retrieve_body($response), true);
        return rest_ensure_response(is_array($payload) ? $payload : ['ok' => false, 'message' => 'Empty response']);
    }

    public function handle_execute(WP_REST_Request $request) {
        $tool  = (string) $request->get_param('tool');
        $input = $request->get_param('input');
        if (!is_array($input)) $input = [];

        if (!isset(self::TOOL_HANDLERS[$tool])) {
            return new WP_Error('unknown_tool', 'Unknown tool: ' . $tool, ['status' => 400]);
        }
        $handler = self::TOOL_HANDLERS[$tool];
        if (!function_exists($handler)) {
            return new WP_Error('handler_missing', 'Handler not loaded: ' . $handler, ['status' => 500]);
        }

        $ctx = [
            'post_id' => (int) $request->get_param('page_id'),
            'user_id' => get_current_user_id(),
        ];

        $result = call_user_func($handler, $input, $ctx);
        if (!is_array($result)) {
            $result = ['ok' => false, 'message' => 'Tool returned no result.'];
        }
        $result['tool'] = $tool;
        return rest_ensure_response($result);
    }

    /**
     * Forward chat-with-tools requests through to the AI proxy. Plugin-side
     * proxy keeps the user's nonce/auth on WP and the API key on the proxy.
     */
    public function handle_chat_with_tools(WP_REST_Request $request) {
        $messages = $request->get_param('messages');
        if (!is_array($messages) || empty($messages)) {
            return new WP_Error('invalid_messages', 'messages must be a non-empty array', ['status' => 400]);
        }
        $context = $request->get_param('context');
        $locale  = $request->get_param('locale');

        $url = SailWP_Copilot_Plugin::get_ai_proxy_url() . '/copilot/chat-with-tools';
        $body = [
            'messages' => $messages,
            'context'  => is_array($context) ? $context : [],
            'site'     => home_url(),
        ];
        if ($locale) $body['locale'] = $locale;

        $response = wp_remote_post($url, [
            'timeout' => 60,
            '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($body),
        ]);

        if (is_wp_error($response)) return $response;
        $code    = wp_remote_retrieve_response_code($response);
        $payload = json_decode(wp_remote_retrieve_body($response), true);
        if ($code >= 400) {
            $msg = is_array($payload) && isset($payload['message']) ? $payload['message'] : 'AI proxy error';
            return new WP_Error('ai_proxy_error', $msg, ['status' => $code]);
        }
        // Proxy now returns a `quota` block on chat-with-tools. Cache it so
        // the rail can render the heavy-action counter without an extra
        // round-trip on the next page load.
        if (is_array($payload) && isset($payload['quota']) && is_array($payload['quota'])) {
            SailWP_Copilot_Plugin::cache_quota_from_response($payload['quota']);
        }
        return rest_ensure_response($payload);
    }

    public function enqueue_styles() {
        wp_register_style(
            'sailwp-copilot-tool-styles',
            SAILWP_COPILOT_URL . 'assets/css/tool-styles.css',
            [],
            SAILWP_COPILOT_VERSION
        );
        wp_enqueue_style('sailwp-copilot-tool-styles');
    }
}
