<?php

namespace Drupal\Tests\acquia_contenthub\Kernel\EventSubscriber\HandleWebhook;

use Drupal\acquia_contenthub\EventSubscriber\HandleWebhook\RegisterWebhook;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\KernelTests\KernelTestBase;
use Drupal\Tests\acquia_contenthub\Kernel\EventSubscriber\HandleWebhook\Traits\HandleWebhookEventTestTrait;
use Drupal\Tests\acquia_contenthub\Unit\Helpers\LoggerMock;

/**
 * @coversDefaultClass \Drupal\acquia_contenthub\EventSubscriber\HandleWebhook\RegisterWebhook
 *
 * @group acquia_contenthub
 *
 * @requires module depcalc
 */
class RegisterWebhookTest extends KernelTestBase {

  use HandleWebhookEventTestTrait;

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'acquia_contenthub',
    'depcalc',
    'user',
  ];

  /**
   * A mocked logger to examine recorded logs.
   *
   * @var \Psr\Log\LoggerInterface
   */
  protected $logger;

  /**
   * {@inheritdoc}
   */
  protected function setUp(): void {
    parent::setUp();

    $this->installEntitySchema('user');
    $this->logger = new LoggerMock();
  }

  /**
   * Tests subscriber when the payload crud is pending.
   *
   * The response is not signed if X-Server-Authorization-HMAC-SHA256 is not
   * present.
   */
  public function testPayloadStatusIsNotPending(): void {
    $event = $this->newHandleWebhookEvent([
      'status' => 'update',
    ]);

    $subscriber = $this->newRegisterWebhook();
    $subscriber->onHandleWebhook($event);

    $resp = $event->getResponse();
    $this->assertFalse($resp->headers->has('X-Server-Authorization-HMAC-SHA256'));
  }

  /**
   * Tests negative cases.
   *
   * Public Keys don't match and uuid is missing from payload.
   */
  public function testPayloadWhenPublicKeysDontMatchAndUuidMissing(): void {
    $payload = [
      'status' => 'pending',
      'publickey' => $this->randomString(),
      'uuid' => $this->generateUuid(),
    ];
    $event = $this->newHandleWebhookEvent($payload);
    $subscriber = $this->newRegisterWebhook();
    $subscriber->onHandleWebhook($event);

    /** @var \GuzzleHttp\Psr7\Response $resp */
    $resp = $event->getResponse();
    $this->assertFalse($resp->hasHeader('X-Server-Authorization-HMAC-SHA256'));
    $this->assertStringContainsString(
      'rejected (initiator and/or publickey do not match local settings):',
      $this->logger->getDebugMessages()[0],
    );

    $event = $this->newHandleWebhookEvent([
      'status' => 'pending',
      // Ensure matching public key.
      'publickey' => $this->getChAdminSettings()['api_key'],
    ]);

    $subscriber = $this->newRegisterWebhook();
    $subscriber->onHandleWebhook($event);

    $resp = $event->getResponse();
    $this->assertFalse($resp->hasHeader('X-Server-Authorization-HMAC-SHA256'));
    $this->assertStringContainsString(
      'rejected (initiator and/or publickey do not match local settings):',
      $this->logger->getDebugMessages()[0],
    );
  }

  /**
   * Tests a successful case.
   *
   * On pending it returns a signed response to plexus.
   */
  public function testWithSuccessfulSignedRequest(): void {
    $event = $this->newHandleWebhookEvent([
      'status' => 'pending',
      'publickey' => $this->getChAdminSettings()['api_key'],
      'uuid' => $this->generateUuid(),
    ]);

    $subscriber = $this->newRegisterWebhook();
    $subscriber->onHandleWebhook($event);

    /** @var \GuzzleHttp\Psr7\Response $resp */
    $resp = $event->getResponse();
    $this->assertTrue($resp->hasHeader('X-Server-Authorization-HMAC-SHA256'));
  }

  /**
   * Returns a new RegisterWebhook object.
   *
   * @return \Drupal\acquia_contenthub\EventSubscriber\HandleWebhook\RegisterWebhook
   *   The object.
   */
  protected function newRegisterWebhook(): RegisterWebhook {
    $logger_factory = $this->prophesize(LoggerChannelFactoryInterface::class);
    $logger_factory->get('acquia_contenthub')->willReturn($this->logger);
    return new RegisterWebhook($logger_factory->reveal());
  }

}
