<?php

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Chill\DocGeneratorBundle\GeneratorDriver;

use Chill\DocGeneratorBundle\GeneratorDriver\Exception\TemplateException;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Mime\Part\DataPart;
use Symfony\Component\Mime\Part\Multipart\FormDataPart;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;

final readonly class RelatorioDriver implements DriverInterface
{
    private string $url;

    public function __construct(
        private HttpClientInterface $client,
        ParameterBagInterface $parameterBag,
        private LoggerInterface $logger,
    ) {
        $this->url = $parameterBag->get('chill_doc_generator')['driver']['relatorio']['url'];
    }

    public function generateFromString(string $template, string $resourceType, array $data, ?string $templateName = null): string
    {
        $form = new FormDataPart(
            [
                'variables' => json_encode($data, JSON_THROW_ON_ERROR),
                'template' => new DataPart($template, $templateName ?? uniqid('template_'), $resourceType),
            ]
        );

        try {
            $response = $this->client->request('POST', $this->url, [
                'headers' => $form->getPreparedHeaders()->toArray(),
                'body' => $form->bodyToIterable(),
                'timeout' => '300',
            ]);

            return $response->getContent();
        } catch (ClientExceptionInterface $e) {
            $content = $e->getResponse()->getContent(false);

            if (400 === $e->getResponse()->getStatusCode()) {
                $content = json_decode($content, true, 512, JSON_THROW_ON_ERROR);
                $this->logger->error('relatorio: template error', [
                    'error' => $content['message'] ?? '_not defined',
                ]);

                throw new TemplateException([$content['message']]);
            }

            $this->logger->error('relatorio: error while generating document', [
                'msg' => $e->getMessage(),
                'response' => $e->getResponse()->getStatusCode(),
                'content' => $content,
            ]);

            throw $e;
        } catch (TransportExceptionInterface $e) {
            $this->logger->error('relatorio: transport exception', [
                'msg' => $e->getMessage(),
                'e' => $e->getTraceAsString(),
            ]);

            throw $e;
        } catch (DecodingExceptionInterface $e) {
            $this->logger->error('relatorio: could not decode response', [
                'msg' => $e->getMessage(),
                'e' => $e->getTraceAsString(),
            ]);

            throw $e;
        } catch (\Throwable $exception) {
            $this
                ->logger
                ->error(
                    'relatorio: Unable to get content from response.',
                    [
                        'msg' => $exception->getMessage(),
                        'e' => $exception->getTraceAsString(),
                    ]
                );

            throw $exception;
        }
    }
}
