<?php

namespace Mautic\PluginBundle\EventListener;

use Mautic\PluginBundle\Event\PluginIntegrationRequestEvent;
use Mautic\PluginBundle\Helper\oAuthHelper;
use Mautic\PluginBundle\PluginEvents;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * This class can provide useful debugging information for API requests and responses.
 * The information is displayed when a command is executed from the console and the -vv flag is passed to it.
 */
class IntegrationSubscriber implements EventSubscriberInterface
{
    public function __construct(
        private LoggerInterface $logger,
    ) {
    }

    public static function getSubscribedEvents(): array
    {
        return [
            PluginEvents::PLUGIN_ON_INTEGRATION_RESPONSE => ['onResponse', 0],
            PluginEvents::PLUGIN_ON_INTEGRATION_REQUEST  => ['onRequest', 0],
        ];
    }

    /*
     * Request event
     */
    public function onRequest(PluginIntegrationRequestEvent $event): void
    {
        $name     = strtoupper($event->getIntegrationName());
        $headers  = var_export($event->getHeaders(), true);
        $params   = var_export($event->getParameters(), true);
        $settings = var_export($event->getSettings(), true);

        if (defined('IN_MAUTIC_CONSOLE') && defined('MAUTIC_CONSOLE_VERBOSITY')
            && MAUTIC_CONSOLE_VERBOSITY >= ConsoleOutput::VERBOSITY_VERY_VERBOSE) {
            $output = new ConsoleOutput();
            $output->writeln('<fg=magenta>REQUEST:</>');
            $output->writeln('<fg=white>'.$event->getMethod().' '.$event->getUrl().'</>');
            $output->writeln('<fg=cyan>'.$headers.'</>');
            $output->writeln('');
            $output->writeln('<fg=cyan>'.$params.'</>');
            $output->writeln('');
            $output->writeln('<fg=cyan>'.$settings.'</>');
        } else {
            $this->logger->debug("$name REQUEST URL: ".$event->getMethod().' '.$event->getUrl());
            if ('' !== $headers) {
                $hashedHeaders  = oAuthHelper::sanitizeHeaderData($event->getHeaders());
                $headers        = var_export($hashedHeaders, true);
                $this->logger->debug("$name REQUEST HEADERS: \n".$headers.PHP_EOL);
            }
            if ('' !== $params) {
                $this->logger->debug("$name REQUEST PARAMS: \n".$params.PHP_EOL);
            }
            if ('' !== $settings) {
                $this->logger->debug("$name REQUEST SETTINGS: \n".$settings.PHP_EOL);
            }
        }
    }

    /*
     * Response event
     */
    public function onResponse(PluginIntegrationRequestEvent $event): void
    {
        $response = $event->getResponse();
        $headers  = var_export($response->getHeaders(), true);
        $name     = strtoupper($event->getIntegrationName());
        $isJson   = isset($response->getHeaders()['Content-Type']) && preg_grep('/application\/json/', $response->getHeaders()['Content-Type']);
        $json     = $isJson ? str_replace('    ', '  ', json_encode(json_decode($response->getBody()), JSON_PRETTY_PRINT)) : '';
        $xml      = '';
        $isXml    = isset($response->getHeaders()['Content-Type']) && preg_grep('/text\/xml/', $response->getHeaders()['Content-Type']);
        if ($isXml) {
            $doc                     = new \DOMDocument('1.0');
            $doc->preserveWhiteSpace = false;
            $doc->formatOutput       = true;
            $doc->loadXML($response->getBody());
            $xml = $doc->saveXML();
        }

        if (defined('IN_MAUTIC_CONSOLE') && defined('MAUTIC_CONSOLE_VERBOSITY')
            && MAUTIC_CONSOLE_VERBOSITY >= ConsoleOutput::VERBOSITY_VERY_VERBOSE) {
            $output = new ConsoleOutput();
            $output->writeln(sprintf('<fg=magenta>RESPONSE: %d</>', $response->getStatusCode()));
            $output->writeln('<fg=cyan>'.$headers.'</>');
            $output->writeln('');

            if ($isJson) {
                $output->writeln('<fg=cyan>'.$json.'</>');
            } elseif ($isXml) {
                $output->writeln('<fg=cyan>'.$xml.'</>');
            } else {
                $output->writeln('<fg=cyan>'.$response->getBody().'</>');
            }
        } else {
            $this->logger->debug("$name RESPONSE CODE: {$response->getStatusCode()}");
            if ('' !== $headers) {
                $this->logger->debug("$name RESPONSE HEADERS: \n".$headers.PHP_EOL);
            }
            if ('' !== $json || '' !== $xml || '' !== $response->getBody()) {
                $body = "$name RESPONSE BODY: ";
                if ($isJson) {
                    $body .= $json;
                } elseif ($isXml) {
                    $body .= $xml;
                } else {
                    $body = $response->getBody();
                }

                $this->logger->debug($body);
            }
        }
    }
}
