<?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\Api\Request\DateUnit\GetCalendarRequest;
use BookiFlex\Core\Api\Request\DateUnit\SyncDateUnitsRequest;
use BookiFlex\Core\Api\Request\DateUnit\UpdateDateUnitsRequest;
use BookiFlex\Core\Api\Transformer\CalendarTransformer;
use BookiFlex\Core\Contract\RoleCapabilitiesInterface;
use BookiFlex\Core\Service\ConfigurationService;
use BookiFlex\Core\Service\DateUnit\GetCalendar;
use BookiFlex\Core\Service\DateUnit\DateUnitSynchronization;
use BookiFlex\Core\Service\DateUnit\DateUnitManager;
use Throwable;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;

defined( 'ABSPATH' ) || exit;

class DateUnitController extends AbstractController
{
    public const API_ENDPOINT_NAME = 'dateUnits';

    public function __construct(
        private readonly GetCalendar $calendarService,
        private readonly DateUnitSynchronization $syncService,
        private readonly DateUnitManager $updateService,
        private readonly ConfigurationService $configurationService,
        string $namespace = 'bflex/v1'
    ) {
        parent::__construct($namespace);
    }

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

        register_rest_route($this->namespace, '/' . self::API_ENDPOINT_NAME . '/sync', [
            [
                'methods' => 'POST',
                'callback' => [$this, 'syncWithParent'],
                'permission_callback' => [$this, 'hasAccess'],
                'args' => SyncDateUnitsRequest::getValidationRules()
            ]
        ]);

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

    /**
     * Get calendar data
     */
    public function getCalendar(WP_REST_Request $request): WP_REST_Response|WP_Error
    {
        try {
            $calendarRequest = GetCalendarRequest::fromWpRestRequest($request);

            $calendarData = $this->calendarService->getCalendar(
                $calendarRequest->getDateFrom(),
                $calendarRequest->getDateTo(),
                $calendarRequest->getRatePlanId()
            );

            $result = CalendarTransformer::transform(
                $calendarData,
                $this->configurationService->getDefaultCurrency(),
                $this->configurationService->isChildrenSupportEnabled()
            );

            return $this->success([
                'status' => 'success',
                'result' => $result
            ]);
        } catch (Throwable $e) {
            return $this->handleError(
                $e,
                'date_unit_load_calendar_failed',
                __('Failed to load calendar.', 'bookiflex')
            );
        }
    }

    /**
     * Update date units
     */
    public function update(WP_REST_Request $request): WP_REST_Response|WP_Error
    {
        try {
            $updateRequest = UpdateDateUnitsRequest::fromWpRestRequest($request);

            $this->updateService->handle($updateRequest->toDomainRequest());

            return $this->success([
                'status' => 'success',
                'result' => 'ok'
            ]);
        } catch (Throwable $e) {
            return $this->handleError(
                $e,
                'date_unit_update_failed',
                __('Failed to update date units.', 'bookiflex')
            );
        }
    }

    /**
     * Sync date units with parent rate plan
     */
    public function syncWithParent(WP_REST_Request $request): WP_REST_Response|WP_Error
    {
        try {
            $syncRequest = SyncDateUnitsRequest::fromWpRestRequest($request);

            $this->syncService->sync(
                $syncRequest->getRatePlanId(),
                $syncRequest->getAccommodationTypeId()
            );

            return $this->success([
                'status' => 'success',
                'result' => 'ok'
            ]);
        } catch (Throwable $e) {
            return $this->handleError(
                $e,
                'date_unit_sync_failed',
                __('Failed to sync date units.', 'bookiflex')
            );
        }
    }

    /**
     * Check if current user has access to the endpoint
     */
    public function hasAccess(): bool|WP_Error
    {
        if (!current_user_can(RoleCapabilitiesInterface::MANAGE_CONFIGURATION)) {
            return $this->error(
                'bookiflex_forbidden',
                __('You are not allowed to manage configuration.', 'bookiflex'),
                401
            );
        }

        return true;
    }
}
