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

declare(strict_types=1);

namespace BookiFlex\Extensions\Onboarding\Api\Controller;

use BookiFlex\Core\Api\Controller\AbstractController;
use BookiFlex\Extensions\Onboarding\Service\OnboardingInitService;
use BookiFlex\Extensions\Onboarding\Service\OnboardingService;
use BookiFlex\Extensions\Onboarding\Api\Request\OnboardingInitRequest;
use BookiFlex\Extensions\Onboarding\Api\Request\OnboardingCompleteRequest;
use BookiFlex\Extensions\Onboarding\Api\Transformer\InitResponseTransformer;
use BookiFlex\Extensions\Onboarding\Api\Transformer\CompleteResponseTransformer;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;

defined( 'ABSPATH' ) || exit;

/**
 * Onboarding Controller
 *
 * REST API controller for onboarding wizard endpoints.
 *
 * Routes:
 * - POST /bflex/v1/onboarding/init - Get initialization data
 * - POST /bflex/v1/onboarding/complete - Complete onboarding
 *
 * @package BookiFlex\Extensions\Onboarding\Api\Controller
 * @since   1.0.0
 */
class OnboardingController extends AbstractController
{
    public const API_ENDPOINT_NAME = 'onboarding';

    /**
     * OnboardingController constructor
     *
     * @param OnboardingInitService $initService       Initialization service
     * @param OnboardingService     $onboardingService Onboarding service
     * @param string                $namespace         API namespace
     */
    public function __construct(
        private readonly OnboardingInitService $initService,
        private readonly OnboardingService $onboardingService,
        string $namespace = 'bflex/v1'
    ) {
        parent::__construct($namespace);
    }

    /**
     * Register REST API routes
     *
     * @return void
     */
    public function registerRoutes(): void
    {
        // POST /onboarding/init
        register_rest_route(
            $this->namespace,
            '/' . self::API_ENDPOINT_NAME . '/init',
            [
                [
                    'methods' => 'POST',
                    'callback' => [$this, 'init'],
                    'permission_callback' => [$this, 'hasAccess'],
                    'args' => OnboardingInitRequest::getValidationRules(),
                ],
            ]
        );

        // POST /onboarding/complete
        register_rest_route(
            $this->namespace,
            '/' . self::API_ENDPOINT_NAME . '/complete',
            [
                [
                    'methods' => 'POST',
                    'callback' => [$this, 'complete'],
                    'permission_callback' => [$this, 'hasAccess'],
                    'args' => OnboardingCompleteRequest::getValidationRules(),
                ],
            ]
        );
    }

    /**
     * Check if user has permission to access onboarding endpoints
     *
     * @return bool|WP_Error True if user can manage options
     */
    public function hasAccess(): bool|WP_Error
    {
        if (!current_user_can('manage_options')) {
            return $this->error(
                'bookiflex_forbidden',
                __('You are not allowed to access onboarding.', 'bookiflex'),
                401
            );
        }

        return true;
    }

    /**
     * POST /onboarding/init
     *
     * Initialize onboarding wizard with:
     * - Available currencies
     * - Existing or created cancellation policies (domain objects)
     * - Existing or created payment types (domain objects)
     *
     * If no cancellation policies or payment types exist in the database,
     * they will be automatically created from plugin-specific presets.
     *
     * @param  WP_REST_Request $request Request object
     * @return WP_REST_Response|WP_Error Response or error
     */
    public function init(WP_REST_Request $request): WP_REST_Response|WP_Error
    {
        try {
            // Create request object (no parameters needed)
            OnboardingInitRequest::fromWpRestRequest($request);

            // Initialize onboarding data (creates presets if needed, returns domain objects)
            $data = $this->initService->initialize();

            // Transform domain objects to API response format
            $transformer = new InitResponseTransformer();
            $transformedData = $transformer->transform(
                $data['currencies'],
                $data['cancellationPolicies'],
                $data['paymentTypes'],
                $data['bookingPresets'],
                $data['accommodationTypes']
            );

            return $this->success(
                [
                'status' => 'success',
                'result' => $transformedData,
                ]
            );
        } catch (\Throwable $e) {
            return $this->handleError(
                $e,
                'onboarding_init_failed',
                __('Failed to initialize onboarding', 'bookiflex')
            );
        }
    }

    /**
     * POST /onboarding/complete
     *
     * Complete onboarding with user configuration.
     * Request validation is handled by WordPress REST API.
     *
     * @param  WP_REST_Request $request Request object
     * @return WP_REST_Response|WP_Error Response or error
     */
    public function complete(WP_REST_Request $request): WP_REST_Response|WP_Error
    {
        try {
            // Create and validate request object (validation already done by WP REST API)
            $completeRequest = OnboardingCompleteRequest::fromWpRestRequest($request);

            // Transform to configuration
            $config = $completeRequest->toConfiguration();

            // Execute onboarding
            $result = $this->onboardingService->execute($config);

            // Transform and return result
            $transformer = new CompleteResponseTransformer();
            $transformedData = $transformer->transform($result);

            return $this->success(
                [
                'status' => 'success',
                'result' => $transformedData,
                ]
            );
        } catch (\Throwable $e) {
            return $this->handleError(
                $e,
                'onboarding_complete_failed',
                __('Failed to complete onboarding', 'bookiflex')
            );
        }
    }
}
