<?php

declare(strict_types=1);

namespace ProRank\SEO\Core\RestApi;

use ProRank\SEO\Core\Performance\ObjectCacheHealth;
use ProRank\SEO\Core\Performance\ObjectCache\ObjectCacheDropinManager;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * Always-registered, read-only object-cache health endpoint.
 *
 * This controller is registered at the plugin level (not inside the optional
 * object_cache performance module), so the Database & Server panel can always
 * reach GET /prorank/v1/object-cache/health regardless of which performance
 * child modules are enabled.
 *
 * The route is intentionally registered under the `prorank/v1` namespace
 * (not the BaseController default `prorank-seo/v1`) so it matches the path the
 * UI already calls and the previous module route.
 */
class ObjectCacheHealthController extends BaseController {

    /** Explicit namespace so the public path stays /prorank/v1/object-cache/health. */
    private const ROUTE_NAMESPACE = 'prorank/v1';

    public function register_routes(): void {
        register_rest_route(
            self::ROUTE_NAMESPACE,
            '/object-cache/health',
            [
                [
                    'methods'             => WP_REST_Server::READABLE,
                    'callback'            => [$this, 'get_health'],
                    'permission_callback' => function () {
                        return current_user_can('manage_options');
                    },
                ],
            ]
        );

        register_rest_route(
            self::ROUTE_NAMESPACE,
            '/object-cache/dropin/install',
            [
                [
                    'methods'             => WP_REST_Server::CREATABLE,
                    'callback'            => [$this, 'install_dropin'],
                    'permission_callback' => [$this, 'can_manage'],
                    'args'                => [
                        'confirm' => [
                            'type'    => 'boolean',
                            'default' => false,
                        ],
                    ],
                ],
            ]
        );

        register_rest_route(
            self::ROUTE_NAMESPACE,
            '/object-cache/dropin/remove',
            [
                [
                    'methods'             => WP_REST_Server::CREATABLE,
                    'callback'            => [$this, 'remove_dropin'],
                    'permission_callback' => [$this, 'can_manage'],
                    'args'                => [
                        'confirm' => [
                            'type'    => 'boolean',
                            'default' => false,
                        ],
                    ],
                ],
            ]
        );

        register_rest_route(
            self::ROUTE_NAMESPACE,
            '/object-cache/test',
            [
                [
                    'methods'             => WP_REST_Server::CREATABLE,
                    'callback'            => [$this, 'test_connection'],
                    'permission_callback' => [$this, 'can_manage'],
                ],
            ]
        );

        register_rest_route(
            self::ROUTE_NAMESPACE,
            '/object-cache/flush',
            [
                [
                    'methods'             => WP_REST_Server::CREATABLE,
                    'callback'            => [$this, 'flush_cache'],
                    'permission_callback' => [$this, 'can_manage'],
                    'args'                => [
                        'confirm' => [
                            'type'    => 'boolean',
                            'default' => false,
                        ],
                    ],
                ],
            ]
        );

        register_rest_route(
            self::ROUTE_NAMESPACE,
            '/object-cache/flush-group',
            [
                [
                    'methods'             => WP_REST_Server::CREATABLE,
                    'callback'            => [$this, 'flush_group'],
                    'permission_callback' => [$this, 'can_manage'],
                    'args'                => [
                        'group' => [
                            'type'     => 'string',
                            'required' => true,
                        ],
                        'confirm' => [
                            'type'    => 'boolean',
                            'default' => false,
                        ],
                    ],
                ],
            ]
        );
    }

    public function can_manage(): bool {
        return current_user_can('manage_options');
    }

    public function get_health(): WP_REST_Response {
        if (!class_exists('\\ProRank\\SEO\\Core\\Performance\\ObjectCacheHealth')) {
            $file = defined('PRORANK_PREMIUM_PLUGIN_DIR')
                ? PRORANK_PREMIUM_PLUGIN_DIR . 'includes/Core/Performance/ObjectCacheHealth.php'
                : __DIR__ . '/../Performance/ObjectCacheHealth.php';
            if (is_readable($file)) {
                require_once $file;
            }
        }

        if (!class_exists('\\ProRank\\SEO\\Core\\Performance\\ObjectCacheHealth')) {
            return new WP_REST_Response([
                'success' => false,
                'message' => __('Object cache diagnostic is unavailable.', 'prorank-seo'),
            ], 500);
        }

        try {
            $health = (new ObjectCacheHealth())->report();
        } catch (\Throwable $e) {
            return new WP_REST_Response([
                'success' => false,
                'message' => $e->getMessage(),
            ], 500);
        }

        return new WP_REST_Response([
            'success' => true,
            'health'  => $health,
        ]);
    }

    private function manager(): ObjectCacheDropinManager {
        return new ObjectCacheDropinManager();
    }

    private function require_confirm(WP_REST_Request $request, string $action): ?WP_REST_Response {
        if ((bool) $request->get_param('confirm')) {
            return null;
        }

        return new WP_REST_Response([
            'success' => false,
            'code'    => 'confirmation_required',
            'message' => sprintf(
                /* translators: %s: object cache action name */
                __('Confirm this object-cache %s action before running it.', 'prorank-seo'),
                $action
            ),
        ], 400);
    }

    public function install_dropin(WP_REST_Request $request): WP_REST_Response {
        $confirm = $this->require_confirm($request, 'install');
        if ($confirm instanceof WP_REST_Response) {
            return $confirm;
        }

        $health_before = (new ObjectCacheHealth())->report();
        $connection    = $health_before['connection'] ?? [];
        if (empty($connection['tested']) || empty($connection['connected'])) {
            return new WP_REST_Response([
                'success' => false,
                'code'    => 'backend_not_ready',
                'message' => __('A persistent object-cache backend was not verified as reachable. Fix Redis/Memcached first, then install the ProRank drop-in.', 'prorank-seo'),
                'health'  => $health_before,
            ], 409);
        }

        $result        = $this->manager()->install();
        $status        = !empty($result['success']) ? 200 : 409;

        return new WP_REST_Response([
            'success'       => !empty($result['success']),
            'result'        => $result,
            'health_before' => $health_before,
            'health'        => (new ObjectCacheHealth())->report(),
        ], $status);
    }

    public function remove_dropin(WP_REST_Request $request): WP_REST_Response {
        $confirm = $this->require_confirm($request, 'remove');
        if ($confirm instanceof WP_REST_Response) {
            return $confirm;
        }

        $result = $this->manager()->remove();

        return new WP_REST_Response([
            'success' => !empty($result['success']),
            'result'  => $result,
            'health'  => (new ObjectCacheHealth())->report(),
        ], !empty($result['success']) ? 200 : 409);
    }

    public function test_connection(): WP_REST_Response {
        $health = new ObjectCacheHealth();
        return new WP_REST_Response([
            'success'    => true,
            'connection' => $health->probe_connection(),
            'health'     => $health->report(),
        ]);
    }

    public function flush_cache(WP_REST_Request $request): WP_REST_Response {
        $confirm = $this->require_confirm($request, 'flush');
        if ($confirm instanceof WP_REST_Response) {
            return $confirm;
        }

        $ok = function_exists('wp_cache_flush') ? (bool) wp_cache_flush() : false;

        return new WP_REST_Response([
            'success' => $ok,
            'message' => $ok
                ? __('Object cache flushed.', 'prorank-seo')
                : __('Object cache flush failed or is unsupported by the current backend.', 'prorank-seo'),
            'health'  => (new ObjectCacheHealth())->report(),
        ], $ok ? 200 : 500);
    }

    public function flush_group(WP_REST_Request $request): WP_REST_Response {
        $confirm = $this->require_confirm($request, 'flush-group');
        if ($confirm instanceof WP_REST_Response) {
            return $confirm;
        }

        $group = sanitize_key((string) $request->get_param('group'));
        if ($group === '') {
            return new WP_REST_Response([
                'success' => false,
                'code'    => 'missing_group',
                'message' => __('Cache group is required.', 'prorank-seo'),
            ], 400);
        }

        if (!function_exists('wp_cache_flush_group')) {
            return new WP_REST_Response([
                'success' => false,
                'code'    => 'unsupported',
                'message' => __('The active object-cache backend does not support group flushing.', 'prorank-seo'),
            ], 501);
        }

        $ok = (bool) wp_cache_flush_group($group);

        return new WP_REST_Response([
            'success' => $ok,
            'group'   => $group,
            'message' => $ok
                ? sprintf(
                    /* translators: %s: object-cache group */
                    __('Object cache group "%s" flushed.', 'prorank-seo'),
                    $group
                )
                : __('Object cache group flush failed.', 'prorank-seo'),
            'health'  => (new ObjectCacheHealth())->report(),
        ], $ok ? 200 : 500);
    }
}
