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

declare(strict_types=1);

namespace BookiFlex\Extensions\NotificationLog\Api\Controller;

use BookiFlex\Core\Api\Controller\AbstractController;
use BookiFlex\Core\Contract\RoleCapabilitiesInterface;
use BookiFlex\Extensions\Notification\Api\Transformer\NotificationTransformer;
use BookiFlex\Extensions\Notification\Model\Notification;
use BookiFlex\Extensions\Notification\Repository\NotificationRepository;
use BookiFlex\Extensions\Notification\Service\NotificationRenderer;
use BookiFlex\Extensions\NotificationLog\Api\Request\ResendNotificationRequest;
use Cycle\ORM\EntityManagerInterface;
use Symfony\Component\Uid\Uuid;
use Throwable;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;

defined('ABSPATH') || exit;

class NotificationLogController extends AbstractController
{
    public const API_ENDPOINT_NAME = 'notification-log';

    public function __construct(
        private readonly NotificationRepository $notificationRepository,
        private readonly EntityManagerInterface $entityManager,
        private readonly NotificationRenderer $renderer,
        string $namespace = 'bflex/v1'
    ) {
        parent::__construct($namespace);
    }

    public function registerRoutes(): void
    {
        register_rest_route($this->namespace, '/' . self::API_ENDPOINT_NAME . '/(?P<sid>[a-f0-9\-]+)/preview', [
            [
                'methods'             => 'GET',
                'callback'            => [$this, 'previewNotification'],
                'permission_callback' => [$this, 'hasAccess'],
                'args'                => [
                    'sid' => ['required' => true, 'type' => 'string'],
                ],
            ],
        ]);

        register_rest_route($this->namespace, '/' . self::API_ENDPOINT_NAME . '/(?P<sid>[a-f0-9\-]+)/resend', [
            [
                'methods'             => 'POST',
                'callback'            => [$this, 'resendNotification'],
                'permission_callback' => [$this, 'hasAccess'],
                'args'                => ResendNotificationRequest::getValidationRules(),
            ],
        ]);
    }

    /**
     * GET /notification-log/{sid}/preview
     */
    public function previewNotification(WP_REST_Request $request): string|WP_Error
    {
        try {
            $sid = $request->get_param('sid');

            $notification = $this->notificationRepository->findBySid($sid);
            if (!$notification) {
                return $this->error(
                    'notification_not_found',
                    __('Notification not found.', 'bookiflex'),
                    404
                );
            }

            if (!$notification->hasSnapshot()) {
                return $this->error(
                    'notification_no_snapshot',
                    __('This notification has no saved snapshot and cannot be previewed.', 'bookiflex'),
                    422
                );
            }

            $snapshot = $notification->getSnapshot();
            $this->renderer->renderSnapshotResponse($snapshot);
        } catch (Throwable $e) {
            return $this->handleError(
                $e,
                'notification_preview_failed',
                __('Failed to preview notification.', 'bookiflex')
            );
        }
    }

    /**
     * POST /notification-log/{sid}/resend
     */
    public function resendNotification(WP_REST_Request $request): WP_REST_Response|WP_Error
    {
        try {
            $req = ResendNotificationRequest::fromWpRestRequest($request);

            /** @var Notification|null $original */
            $original = $this->notificationRepository->findBySid($req->getSid());
            if (!$original) {
                return $this->error(
                    'notification_not_found',
                    __('Notification not found.', 'bookiflex'),
                    404
                );
            }

            if (!$original->hasSnapshot()) {
                return $this->error(
                    'notification_no_snapshot',
                    __('This notification has no saved snapshot and cannot be resent.', 'bookiflex'),
                    422
                );
            }

            $notification = new Notification(
                (string) Uuid::v4(),
                $original->getEvent(),
                $original->getStakeholder(),
                $original->getSendTo(),
                $original->getTransport(),
                new \DateTimeImmutable(),
                $original->getReservation(),
            );
            $notification->setDetails($original->getDetails());

            $this->entityManager->persist($notification);
            $this->entityManager->run();

            $transformer = new NotificationTransformer();

            return $this->success([
                'status' => 'success',
                'result' => $transformer->transform($notification),
            ], 201);
        } catch (Throwable $e) {
            return $this->handleError(
                $e,
                'notification_resend_failed',
                __('Failed to resend notification.', 'bookiflex')
            );
        }
    }

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

        return true;
    }
}
