<?php

declare(strict_types=1);

namespace Gls\GlsPoland\Controller\Admin;

use Gls\GlsPoland\AdePlus\Fault\AdePlusFault;
use Gls\GlsPoland\Entity\Consignment;
use Gls\GlsPoland\Form\Type\CreateConsignmentType;
use Gls\GlsPoland\Message\BulkCreateConsignmentsCommand;
use Gls\GlsPoland\MessageHandler\Consignment\CreateConsignmentsResult;
use Gls\GlsPoland\PrestaShop\Order\CreateConsignmentCommandFactoryInterface;
use Gls\GlsPoland\Translation\TranslatorAwareTrait;
use PrestaShop\PrestaShop\Adapter\Admin\UrlGenerator;
use PrestaShop\PrestaShop\Core\CommandBus\CommandBusInterface;
use PrestaShopBundle\Security\Voter\PageVoter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;

/**
 * @Route(path="orders", name="admin_gls_poland_orders_")
 */
final class OrderController extends AbstractController
{
    use TranslatorAwareTrait;

    /**
     * @Route(path="/{id}/new-consignment", name="create_consignment", methods={"GET", "POST"}, requirements={"id"="\d+"})
     */
    public function createConsignment(int $id, Request $request, CommandBusInterface $bus, CreateConsignmentCommandFactoryInterface $commandFactory): Response
    {
        $this->denyAccessUnlessGranted(PageVoter::CREATE, ConsignmentController::TAB_NAME);

        $lightDisplay = $request->query->getBoolean('liteDisplaying');

        $options = [
            'action' => $this->generateUrl('admin_gls_poland_orders_create_consignment', [
                'id' => $id,
                'liteDisplaying' => $lightDisplay,
            ]),
        ];

        if ($partialSubmit = $request->query->has('partial_submit')) {
            $options['validation_groups'] = false;
        }

        $form = $this
            ->createForm(CreateConsignmentType::class, $commandFactory->create($id), $options)
            ->handleRequest($request);

        if (!$partialSubmit && $form->isSubmitted() && $form->isValid()) {
            try {
                /** @var Consignment $consignment */
                $consignment = $bus->handle($form->getData());

                $this->addFlash('success', $this->getTranslator()->trans('Successful creation.', [], 'Admin.Notifications.Success'));

                if ($lightDisplay) {
                    return $this->render('@Modules/glspoland/views/templates/admin/consignment/success.html.twig', [
                        'consignment_id' => $consignment->getId(),
                    ]);
                }

                return $this->redirectToRoute('admin_gls_poland_orders_create_consignment', ['id' => $id], Response::HTTP_SEE_OTHER);
            } catch (AdePlusFault $fault) {
                $this->addFlash('error', $fault->getMessage());
            }
        }

        return $this->render('@Modules/glspoland/views/templates/admin/consignment/form.html.twig', [
            'form' => $form->createView(),
            'light_display' => $lightDisplay,
        ]);
    }

    /**
     * @Route(path="/bulk-create-consignments", name="bulk_create_consignments", methods={"POST"})
     */
    public function bulkCreateConsignments(Request $request, CommandBusInterface $bus): Response
    {
        $orderIds = $this->getOrderIdsFromRequest($request);

        /** @var CreateConsignmentsResult $result */
        $result = $bus->handle(new BulkCreateConsignmentsCommand(...$orderIds));

        if ([] === $errors = $result->getErrors()) {
            $this->addFlash('success', $this->getTranslator()->trans('Successful creation.', [], 'Admin.Notifications.Success'));
        } else {
            foreach ($errors as $orderId => $error) {
                $this->addFlash('error', $this->getTranslator()->trans('Order #{orderId}: {error}', ['{orderId}' => $orderId, '{error}' => $error->getMessage()], 'Modules.Glspoland.Errors'));
            }
        }

        return $this->redirectToRoute('admin_orders_index', [], Response::HTTP_SEE_OTHER);
    }

    /**
     * @Route(path="/legacy/bulk-create-consignments", name="legacy_bulk_create_consignments", methods={"POST"})
     *
     * @param UrlGenerator $legacyUrlGenerator
     */
    public function legacyBulkCreateConsignments(Request $request, CommandBusInterface $bus, UrlGeneratorInterface $legacyUrlGenerator): Response
    {
        $orderIds = $this->getOrderIdsFromRequest($request, 'orderBox');

        /** @var CreateConsignmentsResult $result */
        $result = $bus->handle(new BulkCreateConsignmentsCommand(...$orderIds));

        if ([] === $errors = $result->getErrors()) {
            $this->addFlash('glspoland_success', $this->getTranslator()->trans('Successful creation.', [], 'Admin.Notifications.Success'));
        } else {
            foreach ($errors as $orderId => $error) {
                $this->addFlash('glspoland_error', $this->getTranslator()->trans('Order #{orderId}: {error}', ['{orderId}' => $orderId, '{error}' => $error->getMessage()], 'Modules.Glspoland.Errors'));
            }
        }

        $url = $legacyUrlGenerator->generate('AdminOrders');

        return $this->redirect($url, Response::HTTP_SEE_OTHER);
    }

    private function getOrderIdsFromRequest(Request $request, string $key = 'order_orders_bulk'): array
    {
        $orderIds = $request->request->get($key);
        if (!is_array($orderIds) || [] === $orderIds) {
            throw new BadRequestHttpException('Order IDs list is empty.');
        }

        return array_map('intval', $orderIds);
    }
}
