<?php

namespace Velis\Mvc\Controller\Listeners;

use Phalcon\Http\Message\ResponseStatusCodeInterface;
use ReflectionException;
use Velis\Api\HttpExceptionHandler\HttpException;
use Velis\Dto\Exceptions\ValidationException;
use Velis\Mvc\Controller\Exception\BadRequestException;
use Velis\Mvc\Controller\Listeners\Concrete\AbstractListener;
use Velis\Mvc\Controller\Utils\DtoRequestTransformer;

class ValidateDtoRequestListener extends AbstractListener
{
    public const ERROR_FORMAT_STRING = 'string';
    public const ERROR_FORMAT_ARRAY = 'array';

    /**
     * @throws BadRequestException
     * @throws ReflectionException
     * @throws HttpException
     */
    public function handle(): void
    {
        $request = $this->request;
        $errorFormat = $this->config['error_format'] ?: self::ERROR_FORMAT_ARRAY;

        $requestTransformer = new DtoRequestTransformer($request);
        try {
            $requestTransformer->transformRequest($this->dispatcher);
        } catch (ValidationException $e) {
            match ($errorFormat) {
                self::ERROR_FORMAT_STRING => $this->reportString($e),
                self::ERROR_FORMAT_ARRAY => $this->reportArray($e),
            };
        };
    }

    /**
     * @throws BadRequestException
     */
    public function reportString(ValidationException $e)
    {
        $messages = implode('. ', array_map(fn ($error) => $error['message'], $e->getErrors()));
        throw new BadRequestException('Validation Error. ' . $messages);
    }

    /**
     * @throws HttpException
     */
    public function reportArray(ValidationException $e)
    {
        throw new HttpException(
            message: $e->getMessage(),
            details: $e->getErrors(),
            httpCode: ResponseStatusCodeInterface::STATUS_BAD_REQUEST
        );
    }
}
