<?php
/**
 * BookiFlex Core
 *
 * @package    BookiFlex
 * @subpackage Core
 * @author     BookiFlex
 * @copyright  Copyright (c) 2025 BookiFlex
 * @license    GPL-2.0-or-later
 *
 * @link       https://bookiflex.com
 */

declare(strict_types=1);

namespace BookiFlex\Core\Api\Controller;

use BookiFlex\Core\Util\LocaleUtils;
use Throwable;
use WP_Error;
use WP_REST_Response;

defined( 'ABSPATH' ) || exit;

abstract class AbstractController extends \WP_REST_Controller
{
    protected array $public = [];

    public const API_ENDPOINT_NAME = '';

    public function __construct(string $namespace = 'bflex/v1')
    {
        $this->namespace = $namespace;

        if (static::API_ENDPOINT_NAME) {
            $this->rest_base = static::API_ENDPOINT_NAME;
        }
    }

    public function get_collection_params()
    {
        return [
            'context' => $this->get_context_param(),
            'page'    => [
                'description'       => __('Current page of the collection.', 'bookiflex'),
                'type'              => 'integer',
                'default'           => 1,
                'sanitize_callback' => 'absint',
                'validate_callback' => 'rest_validate_request_arg',
                'minimum'           => 1,
            ],
            'perPage' => [
                'description'       => __('Maximum number of items to be returned in result set.', 'bookiflex'),
                'type'              => 'integer',
                'default'           => 10,
                'minimum'           => 1,
                'maximum'           => 100,
                'sanitize_callback' => 'absint',
                'validate_callback' => 'rest_validate_request_arg',
            ],
            'search' => [
                'description'       => __('Limit results to those matching a string.', 'bookiflex'),
                'type'              => 'string',
                'sanitize_callback' => 'sanitize_text_field',
                'validate_callback' => 'rest_validate_request_arg',
            ],
        ];
    }

    abstract public function registerRoutes(): void;

    public function register_routes(): void
    {
        $this->registerRoutes();
    }

    /**
     * @param mixed|null $data    Response data. Default null.
     * @param int $status  Optional. HTTP status code. Default 200.
     * @param array $headers Optional. HTTP header map. Default empty array.
     *
     * @return WP_REST_Response
     */
    protected function success(mixed $data = null, int $status = 200, array $headers = []): WP_REST_Response
    {
        return new WP_REST_Response($data, $status, $headers);
    }

    /**
     * Returns error message.
     *
     * @param string $code Error code.
     * @param string $message Error message
     * @param int $status
     * @param array|null $additionalData
     * @return WP_Error
     */
    protected function error(
        string $code,
        string $message,
        int $status = 400,
        ?array $additionalData = null
    ): WP_Error {
        $data = ['status' => $status];

        if ($additionalData) {
            $data = array_merge($data, $additionalData);
        }

        return new WP_Error($code, $message, $data);
    }

    /**
     * Returns a RedirectResponse to the given URL.
     *
     * @param string $url
     * @param int $status
     * @return bool
     */
    protected function redirect(string $url, int $status = 302): bool
    {
        return wp_redirect($url, $status);
    }

    public function hasAccess(): bool|WP_Error
    {
        if (!current_user_can('manage_options')) {
            return $this->error(
                'bookiflex_forbidden',
                __('You are not allowed to access this resource.', 'bookiflex'),
                401
            );
        }

        return true;
    }

    /**
     * Execute a callback with a temporarily switched WordPress locale.
     * Guarantees restore_current_locale() even if the callback throws.
     */
    protected function withLocale(string $locale, callable $callback): mixed
    {
        return LocaleUtils::withLocale($locale, $callback);
    }

    /**
     * Handle errors in a consistent way
     */
    protected function handleError(Throwable $e, string $code, string $message): WP_Error
    {
        $data = [
            'code' => $e->getCode(),
            'message' => $e->getMessage()
        ];

        // Add debug information in development environment
        if (defined('WP_DEBUG') && WP_DEBUG) {
            $data['file'] = $e->getFile();
            $data['line'] = $e->getLine();
            $data['trace'] = $e->getTraceAsString();
        }

        return $this->error($code, $message, 500, $data);
    }
}
