<?php

declare(strict_types=1);

namespace Autogedal\RemoveSubscriber\Model\TheMarketer;

use Autogedal\Extend\Model\TheMarketer\SyncContext;
use Autogedal\RemoveSubscriber\Api\TheMarketerUnsubscribeWebhookInterface;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\Exception\InputException;
use Magento\Framework\Webapi\Exception as WebapiException;
use Magento\Framework\Webapi\Rest\Request as RestRequest;
use Magento\Newsletter\Model\Subscriber;
use Magento\Newsletter\Model\SubscriberFactory;
use Magento\Newsletter\Model\SubscriptionManagerInterface;
use Magento\Store\Model\StoreManagerInterface;

class UnsubscribeWebhook implements TheMarketerUnsubscribeWebhookInterface
{
    private const CONFIG_WEBHOOK_TOKEN = 'mktr_tracker/autogedal_newsletter_sync/webhook_token';

    public function __construct(
        private readonly SubscriptionManagerInterface $subscriptionManager,
        private readonly StoreManagerInterface $storeManager,
        private readonly SyncContext $syncContext,
        private readonly RestRequest $request,
        private readonly ScopeConfigInterface $scopeConfig,
        private readonly SubscriberFactory $subscriberFactory
    ) {
    }

    public function receive(string $email): bool
    {
        $this->validateToken();

        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            throw new InputException(__('Invalid email address.'));
        }

        $websiteId = (int) $this->storeManager->getStore()->getWebsiteId();

        /** @var Subscriber $subscriber */
        $subscriber = $this->subscriberFactory->create()->loadBySubscriberEmail($email, $websiteId);

        if (!$subscriber->getId() || (int) $subscriber->getStatus() !== Subscriber::STATUS_SUBSCRIBED) {
            return true;
        }

        $storeId = (int) $this->storeManager->getStore()->getId();

        $this->syncContext->setIsWebhookRequest(true);
        $this->subscriptionManager->unsubscribe($email, $storeId, (string) $subscriber->getSubscriberConfirmCode());

        return true;
    }

    private function validateToken(): void
    {
        $expectedToken = $this->scopeConfig->getValue(self::CONFIG_WEBHOOK_TOKEN);
        if (!$expectedToken) {
            throw new WebapiException(__('Webhook token not configured.'), 0, WebapiException::HTTP_UNAUTHORIZED);
        }

        // Apache mod_rewrite moves Authorization to REDIRECT_HTTP_AUTHORIZATION
        $authHeader = $this->request->getHeader('Authorization')
            ?: $this->request->getServer('REDIRECT_HTTP_AUTHORIZATION');

        if (!$authHeader) {
            throw new WebapiException(__('Authorization header missing.'), 0, WebapiException::HTTP_UNAUTHORIZED);
        }

        $pieces = explode(' ', (string) $authHeader);
        if (count($pieces) !== 2 || strtolower($pieces[0]) !== 'bearer') {
            throw new WebapiException(__('Invalid Authorization header.'), 0, WebapiException::HTTP_UNAUTHORIZED);
        }

        if (!hash_equals($expectedToken, $pieces[1])) {
            throw new WebapiException(__('Invalid webhook token.'), 0, WebapiException::HTTP_UNAUTHORIZED);
        }
    }
}
