<?php
/**
 * Performance API Controller for FleekDash V2
 *
 * @package FleekDash\API
 */

namespace FleekDash\API;

use FleekDash\Core\AuthMiddleware;
use FleekDash\API\Performance\ThumbnailRegenerator;
use FleekDash\API\Performance\ImageStatsCalculator;
use FleekDash\API\Performance\DatabaseOptimizer;
use FleekDash\API\Performance\PerformanceSchemaProvider;
use FleekDash\API\Performance\DatabaseStatsCollector;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;

// Load debug helpers
if (!function_exists('fleekdash_log_debug')) {
    require_once FLEEKDASH_PLUGIN_DIR . 'includes/Core/debug-helpers.php';
}

/**
 * Performance Controller class for handling performance-related API endpoints
 *
 * @since 2.2.0 Refactored - Uses ThumbnailRegenerator, ImageStatsCalculator, DatabaseOptimizer services
 */
class PerformanceController
{
    /**
     * Common no-cache headers for dynamic endpoints that must not be cached.
     *
     * We explicitly disable all forms of caching to ensure polling UIs get fresh data.
     */
    private const NO_CACHE_HEADERS = [
        'Cache-Control'     => 'no-store, no-cache, must-revalidate, max-age=0',
        'Pragma'            => 'no-cache',
        'Expires'           => '0',
        'Surrogate-Control' => 'no-store',
    ];

    /**
     * The namespace of this controller's route.
     *
     * @var string
     */
    protected $namespace = 'fleekdash/v1';

    /**
     * The base of this controller's route.
     *
     * @var string
     */
    protected $restBase = 'performance';

    /**
     * Thumbnail regenerator service
     */
    private $thumbnailRegenerator;

    /**
     * Image stats calculator service
     */
    private $statsCalculator;

    /**
     * Database optimizer service
     */
    private $dbOptimizer;

    /**
     * Schema provider for REST responses
     */
    private $schemaProvider;

    /**
     * Database stats collector
     */
    private $dbStatsCollector;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->thumbnailRegenerator = new ThumbnailRegenerator();
        $this->statsCalculator = new ImageStatsCalculator();
        $this->dbOptimizer = new DatabaseOptimizer();
        $this->schemaProvider = new PerformanceSchemaProvider();
        $this->dbStatsCollector = new DatabaseStatsCollector();
        $this->registerRoutes();
    }

    /**
     * @deprecated Use registerRoutes() - kept for backward compatibility with ApiRegistry
     */
    public function register_routes() // NOSONAR php:S100 - ApiRegistry contract uses register_routes
    {
        $this->registerRoutes();
    }

    /**
     * Check admin permissions with graceful fallback
     */
    public function adminPermissionsCheck()
    {
        $allowed = true;
        try {
            if (class_exists('\FleekDash\Core\AuthMiddleware')) {
                $authCheck = AuthMiddleware::check('admin');
                if (!$authCheck['authenticated']) {
                    fleekdash_log_debug("FleekDash Performance API: Access without auth - Reason: " . $authCheck['reason']);
                }
            }
        } catch (\Exception $e) {
            fleekdash_log_error("FleekDash Performance API: AuthMiddleware error: " . $e->getMessage());
        }
        return $allowed;
    }

    /**
     * Debug log function
     */
    private function debugLog($message)
    {
        fleekdash_log_debug('[FleekDash Performance] ' . $message);
    }

    /**
     * Apply strict no-cache headers to a REST response.
     */
    private function withNoCacheHeaders(WP_REST_Response $response): WP_REST_Response
    {
        foreach (self::NO_CACHE_HEADERS as $header => $value) {
            $response->header($header, $value);
        }
        return $response;
    }

    /**
     * Register the routes for the objects of the controller.
     */
    private function registerRoutes()
    {
        // Thumbnail regeneration endpoints
        \register_rest_route(
            $this->namespace,
            '/' . $this->restBase . '/thumbnails/regenerate',
            [
                [
                    'methods'             => \WP_REST_Server::CREATABLE,
                    'callback'            => [$this, 'regenerateThumbnails'],
                    'permission_callback' => [$this, 'adminPermissionsCheck'],
                    'args'                => $this->schemaProvider->getRegenerateArgs(),
                ],
                'schema' => [$this->schemaProvider, 'getRegenerateSchema'],
            ]
        );

        \register_rest_route(
            $this->namespace,
            '/' . $this->restBase . '/thumbnails/status',
            [
                [
                    'methods'             => \WP_REST_Server::READABLE,
                    'callback'            => [$this, 'getRegenerationStatus'],
                    'permission_callback' => [$this, 'adminPermissionsCheck'],
                ],
                'schema' => [$this->schemaProvider, 'getStatusSchema'],
            ]
        );

        \register_rest_route(
            $this->namespace,
            '/' . $this->restBase . '/thumbnails/cancel',
            [
                [
                    'methods'             => \WP_REST_Server::CREATABLE,
                    'callback'            => [$this, 'cancelRegeneration'],
                    'permission_callback' => [$this, 'adminPermissionsCheck'],
                ],
            ]
        );

        \register_rest_route(
            $this->namespace,
            '/' . $this->restBase . '/thumbnails/settings',
            [
                [
                    'methods'             => \WP_REST_Server::READABLE,
                    'callback'            => [$this, 'getThumbnailSettings'],
                    'permission_callback' => [$this, 'adminPermissionsCheck'],
                ],
                [
                    'methods'             => \WP_REST_Server::CREATABLE,
                    'callback'            => [$this, 'updateThumbnailSettings'],
                    'permission_callback' => [$this, 'adminPermissionsCheck'],
                    'args'                => [
                        'auto_regenerate_on_upload' => [
                            'type'        => 'boolean',
                            'description' => 'Auto-regenerate FleekDash sizes when uploading images',
                        ],
                    ],
                ],
            ]
        );

        // Image statistics endpoint
        \register_rest_route(
            $this->namespace,
            '/' . $this->restBase . '/images/stats',
            [
                [
                    'methods'             => \WP_REST_Server::READABLE,
                    'callback'            => [$this, 'getImageStats'],
                    'permission_callback' => [$this, 'adminPermissionsCheck'],
                ],
                'schema' => [$this->schemaProvider, 'getStatsSchema'],
            ]
        );

        // Database optimization endpoints
        \register_rest_route(
            $this->namespace,
            '/' . $this->restBase . '/db/stats',
            [
                [
                    'methods'             => \WP_REST_Server::READABLE,
                    'callback'            => [$this, 'getDbStats'],
                    'permission_callback' => [$this, 'adminPermissionsCheck'],
                ],
            ]
        );

        \register_rest_route(
            $this->namespace,
            '/' . $this->restBase . '/db/run',
            [
                [
                    'methods'             => \WP_REST_Server::CREATABLE,
                    'callback'            => [$this, 'runDbOptimization'],
                    'permission_callback' => [$this, 'adminPermissionsCheck'],
                ],
            ]
        );

        \register_rest_route(
            $this->namespace,
            '/' . $this->restBase . '/db/status',
            [
                [
                    'methods'             => \WP_REST_Server::READABLE,
                    'callback'            => [$this, 'getDbOptimizationStatus'],
                    'permission_callback' => [$this, 'adminPermissionsCheck'],
                ],
            ]
        );
    }

    /**
     * Start thumbnail regeneration process
     *
     * @param WP_REST_Request $request Full details about the request.
     * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
     */
    public function regenerateThumbnails($request)
    {
        $response = null;
        try {
            $batchSize = (int) ($request->get_param('batch_size') ?: 10);
            $offset = (int) ($request->get_param('offset') ?: 0);
            $force = (bool) ($request->get_param('force') ?: false);
            $totalImages = $this->thumbnailRegenerator->getImageCount();

            if ($totalImages === 0) {
                $response = $this->buildRegenerationEmptyResponse();
            } else {
                $context = $this->buildRegenerationContext($offset, $force);
                $earlyComplete = $this->maybeReturnEarlyComplete($context, $totalImages, $batchSize);
                if ($earlyComplete !== null) {
                    $response = $earlyComplete;
                } else {
                    $result = $this->thumbnailRegenerator->processBatch(
                        $context['current_offset'],
                        $batchSize
                    );
                    $errorResp = $this->handleRegenerationError($result, $context, $totalImages, $batchSize);
                    $response = $errorResp !== null
                        ? $errorResp
                        : $this->buildRegenerationSuccessResponse($result, $context, $totalImages, $batchSize);
                }
            }
        } catch (\Exception $e) {
            $this->debugLog('Thumbnail regeneration error: ' . $e->getMessage());
            \set_transient('fleekdash_thumbnail_regeneration_status', [
                'status' => 'error',
                'error_message' => $e->getMessage()
            ], HOUR_IN_SECONDS);
            $response = new WP_Error(
                'regeneration_failed',
                'Failed to regenerate thumbnails: ' . $e->getMessage(),
                ['status' => 500]
            );
        }
        return $response;
    }

    /**
     * Build empty response when no images to regenerate.
     *
     * @return WP_REST_Response
     */
    private function buildRegenerationEmptyResponse(): WP_REST_Response
    {
        return new WP_REST_Response([
            'success' => true,
            'message' => 'No images found to regenerate.',
            'data' => ['total' => 0, 'processed' => 0, 'errors' => 0, 'status' => 'completed', 'next_offset' => 0]
        ]);
    }

    /**
     * Build regeneration context (offset, accumulated counts, started_at).
     *
     * @param int $offset Offset param
     * @param bool $force Force restart
     * @return array{current_offset: int, accumulated_processed: int, accumulated_errors: int, started_at: string}
     */
    private function buildRegenerationContext($offset, $force): array
    {
        $status = \get_transient('fleekdash_thumbnail_regeneration_status');
        $is_running = is_array($status) && ($status['status'] ?? 'idle') === 'running';
        $is_new = !$is_running || $force;

        if ($is_new) {
            return [
                'current_offset' => max(0, $offset),
                'accumulated_processed' => 0,
                'accumulated_errors' => 0,
                'started_at' => \current_time('mysql'),
            ];
        }
        return [
            'current_offset' => max($offset, (int)($status['next_offset'] ?? $status['processed'] ?? 0)),
            'accumulated_processed' => (int)($status['processed'] ?? 0),
            'accumulated_errors' => (int)($status['errors'] ?? 0),
            'started_at' => $status['started_at'] ?? \current_time('mysql'),
        ];
    }

    /**
     * Return early if regeneration already at end.
     *
     * @param array $context Regeneration context
     * @param int $totalImages Total image count
     * @param int $batchSize Batch size
     * @return WP_REST_Response|null Response if early complete, null otherwise
     */
    private function maybeReturnEarlyComplete(array $context, int $totalImages, int $batchSize): ?WP_REST_Response
    {
        if ($context['current_offset'] < $totalImages) {
            return null;
        }
        $final = [
            'status' => 'completed',
            'total' => $totalImages,
            'processed' => $context['accumulated_processed'],
            'errors' => $context['accumulated_errors'],
            'completed_at' => \current_time('mysql'),
            'batch_size' => $batchSize,
            'next_offset' => $totalImages,
        ];
        $this->thumbnailRegenerator->setRegenerationStatus($final);
        return new WP_REST_Response(['success' => true, 'message' => 'Thumbnail regeneration completed!', 'data' => $final]);
    }

    /**
     * Handle regeneration error; return WP_Error or null.
     *
     * @param mixed $result processBatch result
     * @param array $context Regeneration context
     * @param int $totalImages Total image count
     * @param int $batchSize Batch size
     * @return WP_Error|null
     */
    private function handleRegenerationError($result, array $context, int $totalImages, int $batchSize): ?WP_Error
    {
        if (!is_wp_error($result)) {
            return null;
        }
        $msg = is_object($result) && method_exists($result, 'get_error_message')
            ? $result->get_error_message() : 'Unknown error';
        $next = $context['current_offset'] + $batchSize;
        $this->thumbnailRegenerator->setRegenerationStatus([
            'status' => 'error',
            'error_message' => $msg,
            'total' => $totalImages,
            'processed' => $context['accumulated_processed'],
            'errors' => $context['accumulated_errors'],
            'next_offset' => $next,
            'batch_size' => $batchSize,
        ]);
        return $result;
    }

    /**
     * Build success response after processing a batch.
     *
     * @param array $result processBatch result
     * @param array $context Regeneration context
     * @param int $totalImages Total image count
     * @param int $batchSize Batch size
     * @return WP_REST_Response
     */
    private function buildRegenerationSuccessResponse(array $result, array $context, int $totalImages, int $batchSize): WP_REST_Response
    {
        $batchP = (int)($result['processed'] ?? 0);
        $batchE = (int)($result['errors'] ?? 0);
        $next = $context['current_offset'] + $batchSize;
        $isCompleted = $next >= $totalImages;

        $statusData = [
            'status' => $isCompleted ? 'completed' : 'running',
            'total' => $totalImages,
            'processed' => $context['accumulated_processed'] + $batchP,
            'errors' => $context['accumulated_errors'] + $batchE,
            'next_offset' => $next,
            'last_batch_at' => \current_time('mysql'),
            'batch_size' => $batchSize,
            'started_at' => $context['started_at'],
        ];
        if ($isCompleted) {
            $statusData['completed_at'] = \current_time('mysql');
        }

        $this->thumbnailRegenerator->setRegenerationStatus($statusData);
        $message = $isCompleted ? 'Thumbnail regeneration completed!' : 'Batch processed successfully.';
        $response = new WP_REST_Response(['success' => true, 'message' => $message, 'data' => $statusData]);
        return $this->withNoCacheHeaders($response);
    }

    /**
     * Get current regeneration status
     *
     * @param WP_REST_Request $request Full details about the request.
     * @return WP_REST_Response Response object.
     */
    public function getRegenerationStatus()
    {
        $status = \get_transient('fleekdash_thumbnail_regeneration_status');

        if (!$status) {
            $status = [
                'status' => 'idle',
                'total' => 0,
                'processed' => 0,
                'errors' => 0,
                'next_offset' => 0
            ];
        }

        // Ensure next_offset exists
        if (!isset($status['next_offset'])) {
            $status['next_offset'] = $status['processed'] ?? 0;
        }

        $response = new WP_REST_Response([
            'success' => true,
            'data' => $status
        ]);
        return $this->withNoCacheHeaders($response);
    }

    /**
     * Get thumbnail settings
     *
     * @param WP_REST_Request $request Full details about the request.
     * @return WP_REST_Response Response object.
     */
    public function getThumbnailSettings()
    {
        $enabled = (bool) \get_option('fleekdash_auto_regenerate_thumbnails_on_upload', true);
        return new \WP_REST_Response([
            'success' => true,
            'data'    => ['auto_regenerate_on_upload' => $enabled],
        ]);
    }

    /**
     * Update thumbnail settings
     *
     * @param WP_REST_Request $request Full details about the request.
     * @return WP_REST_Response Response object.
     */
    public function updateThumbnailSettings($request)
    {
        $param = $request->get_param('auto_regenerate_on_upload');
        if ($param === null) {
            return new \WP_REST_Response([
                'success' => false,
                'message' => 'Missing required parameter: auto_regenerate_on_upload',
            ], 400);
        }
        $enabled = (bool) $param;
        \update_option('fleekdash_auto_regenerate_thumbnails_on_upload', $enabled);
        return new \WP_REST_Response([
            'success' => true,
            'data'    => ['auto_regenerate_on_upload' => $enabled],
        ]);
    }

    /**
     * Cancel ongoing regeneration
     *
     * @param WP_REST_Request $request Full details about the request.
     * @return WP_REST_Response Response object.
     */
    public function cancelRegeneration()
    {
        \delete_transient('fleekdash_thumbnail_regeneration_status');

        $response = new WP_REST_Response([
            'success' => true,
            'message' => 'Thumbnail regeneration cancelled.'
        ]);
        return $this->withNoCacheHeaders($response);
    }

    /**
     * Get image statistics
     *
     * @param WP_REST_Request $request Full details about the request.
     * @return WP_REST_Response Response object.
     */
    public function getImageStats($request)
    {
        try {
            $exact = filter_var($request->get_param('exact'), FILTER_VALIDATE_BOOLEAN);
            $stats = $this->statsCalculator->calculateStats($exact);

            $response = new WP_REST_Response([
                'success' => true,
                'data' => $stats
            ]);
            return $this->withNoCacheHeaders($response);

        } catch (\Exception $e) {
            $this->debugLog('Image stats error: ' . $e->getMessage());

            return new WP_Error(
                'stats_failed',
                'Failed to get image statistics: ' . $e->getMessage(),
                ['status' => 500]
            );
        }
    }


    /**
     * Get database statistics (tables, sizes, overhead, cleanup candidates)
     */
    public function getDbStats()
    {
        try {
            $stats = $this->dbStatsCollector->getStats();
            $response = new WP_REST_Response(['success' => true, 'data' => $stats]);
            return $this->withNoCacheHeaders($response);
        } catch (\Exception $e) {
            $this->debugLog('DB stats error: ' . $e->getMessage());
            return new WP_Error('db_stats_failed', 'Failed to get DB stats: ' . $e->getMessage(), ['status' => 500]);
        }
    }

    /**
     * Run database optimization
    /**
     * Run database optimization
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response|WP_Error Response object
     * @since 2.2.0 Refactored - Uses DatabaseOptimizer service
     */
    public function runDbOptimization($request)
    {
        $tasks = (array) $request->get_param('tasks');
        $batch_size = max(50, (int) ($request->get_param('batch_size') ?: 500));

        try {
            // Run optimization using service
            $summary = $this->dbOptimizer->runOptimization($tasks, $batch_size);

            $status = [
                'status' => 'completed',
                'ran_at' => \current_time('mysql'),
                'summary' => $summary,
            ];

            $response = new WP_REST_Response([
                'success' => true,
                'message' => 'Database optimization completed',
                'data' => $status,
            ]);
            return $this->withNoCacheHeaders($response);

        } catch (\Exception $e) {
            $this->debugLog('DB optimization error: ' . $e->getMessage());
            return new WP_Error(
                'db_optimization_failed',
                'Failed to optimize database: ' . $e->getMessage(),
                ['status' => 500]
            );
        }
    }

    /**
     * Get database optimization status
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response Response object
     * @since 2.2.0 Refactored - Uses DatabaseOptimizer service
     */
    public function getDbOptimizationStatus()
    {
        $status = $this->dbOptimizer->getOptimizationStatus();
        $response = new WP_REST_Response([
            'success' => true,
            'data' => $status,
        ]);
        return $this->withNoCacheHeaders($response);
    }

}
