<?php
/**
 * Copyright since 2025 InPost S.A.
 *
 * For the full license information, please view the LICENSE file bundled with the module.
 *
 * @author InPost S.A.
 * @copyright since 2025 InPost S.A.
 * @license MIT
 */

declare(strict_types=1);

namespace InPost\International\Controller\Admin;

use InPost\International\Carrier\Exception\CarrierException;
use InPost\International\Carrier\Form\CreateCarrierType;
use InPost\International\Carrier\Form\EditCarrierType;
use InPost\International\Carrier\Grid\CarrierFilters;
use InPost\International\Carrier\Message\CreateCarrierCommand;
use InPost\International\Carrier\Message\DeleteCarrierCommand;
use InPost\International\Carrier\Message\EditCarrierCommand;
use InPost\International\Entity\Carrier;
use PrestaShop\PrestaShop\Core\Grid\Definition\Factory\FilterableGridDefinitionFactoryInterface;
use PrestaShop\PrestaShop\Core\Grid\GridFactoryInterface;
use PrestaShop\PrestaShop\Core\Grid\Presenter\GridPresenterInterface;
use PrestaShopBundle\Security\Annotation\AdminSecurity;
use PrestaShopBundle\Security\Voter\PageVoter;
use PrestaShopBundle\Service\Grid\ResponseBuilder;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

if (!defined('_PS_VERSION_')) {
    exit;
}

/**
 * @Route(path="config/carriers", name="admin_inpost_intl_carriers_", defaults={"_legacy_controller"=ConfigurationController::TAB_NAME, "_inpost_intl_carriers_page"=true})
 */
final class CarrierController extends AbstractConfigurationController
{
    public const CARRIERS_TAB_NAME = 'AdminCarriers';

    /**
     * @Route(name="index", methods={"GET"})
     *
     * @AdminSecurity("is_granted('read', request.get('_legacy_controller'))", redirectRoute="admin_module_manage")
     */
    public function index(CarrierFilters $filters, GridFactoryInterface $gridFactory, GridPresenterInterface $gridPresenter): Response
    {
        $grid = $gridFactory->getGrid($filters);

        return $this->render('@Modules/inpostinternational/views/templates/admin/carrier/index.html.twig', [
            'grid' => $gridPresenter->present($grid),
            'layoutTitle' => $this->trans('Services', [], 'Modules.Inpostinternational.Carrier'),
            'headerTabContent' => $this->getNavBar(),
            'layoutHeaderToolbarBtn' => $this->getToolbarButtons(),
        ]);
    }

    /**
     * @Route(name="filter", methods={"POST"})
     *
     * @AdminSecurity("is_granted('read', request.get('_legacy_controller'))", redirectRoute="admin_module_manage")
     */
    public function filter(Request $request, FilterableGridDefinitionFactoryInterface $gridDefinitionFactory, ResponseBuilder $responseBuilder): Response
    {
        return $responseBuilder
            ->buildSearchResponse(
                $gridDefinitionFactory,
                $request,
                $gridDefinitionFactory->getFilterId(),
                'admin_inpost_intl_carriers_index'
            )
            ->setStatusCode(Response::HTTP_SEE_OTHER);
    }

    /**
     * @Route("/create", name="create", methods={"GET", "POST"})
     *
     * @AdminSecurity("is_granted('create', 'AdminCarriers')", redirectRoute="admin_inpost_intl_carriers_index")
     */
    public function create(Request $request): Response
    {
        $form = $this->createForm(CreateCarrierType::class, new CreateCarrierCommand());
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            try {
                $this->handle($form->getData());
                $this->addFlash('success', $this->trans('Successful creation', [], 'Admin.Notifications.Success'));

                return $this->redirectToRoute('admin_inpost_intl_carriers_index', [], Response::HTTP_SEE_OTHER);
            } catch (\Throwable $e) {
                $this->handleException($e);
            }
        }

        return $this->render('@Modules/inpostinternational/views/templates/admin/carrier/create.html.twig', [
            'form' => $form->createView(),
            'layoutTitle' => $this->trans('New service', [], 'Modules.Inpostinternational.Carrier'),
            'headerTabContent' => $this->getNavBar(),
        ], $this->createResponseForForm($form));
    }

    /**
     * @Route("/{id}/edit", name="edit", methods={"GET", "POST"}, requirements={"id"="\d+"})
     *
     * @AdminSecurity("is_granted('update', 'AdminCarriers')", redirectRoute="admin_inpost_intl_carriers_index")
     */
    public function edit(Carrier $carrier, Request $request): Response
    {
        $form = $this->createForm(EditCarrierType::class, EditCarrierCommand::for($carrier), [
            'carrier_type' => $carrier->getType(),
        ]);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            try {
                $this->handle($form->getData());
                $this->addFlash('success', $this->trans('Successful update.', [], 'Admin.Notifications.Success'));

                return $this->redirectToRoute('admin_inpost_intl_carriers_index', [], Response::HTTP_SEE_OTHER);
            } catch (\Throwable $e) {
                $this->handleException($e);
            }
        }

        return $this->render('@Modules/inpostinternational/views/templates/admin/carrier/edit.html.twig', [
            'form' => $form->createView(),
            'layoutTitle' => $this->trans('Edit service #{carrierId}', [
                '{carrierId}' => $carrier->getReferenceId(),
            ], 'Modules.Inpostinternational.Carrier'),
            'headerTabContent' => $this->getNavBar(),
        ], $this->createResponseForForm($form));
    }

    /**
     * @Route("/{id}", name="delete", methods={"DELETE"}, requirements={"id"="\d+"})
     *
     * @AdminSecurity("is_granted('delete', 'AdminCarriers')", redirectRoute="admin_inpost_intl_carriers_index")
     */
    public function delete(int $id): Response
    {
        try {
            $this->handle(new DeleteCarrierCommand($id));
            $this->addFlash('success', $this->trans('Successful deletion', [], 'Admin.Notifications.Success'));
        } catch (\Throwable $e) {
            $this->handleException($e);
        }

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

    private function getToolbarButtons(): array
    {
        if (!$this->isGranted(PageVoter::CREATE, self::CARRIERS_TAB_NAME)) {
            return [];
        }

        return [
            'new_carrier' => [
                'href' => $this->generateUrl('admin_inpost_intl_carriers_create'),
                'desc' => $this->trans('New service', [], 'Modules.Inpostinternational.Carrier'),
                'icon' => 'add_circle_outline',
            ],
        ];
    }

    private function handleException(\Throwable $e): void
    {
        if ($e instanceof CarrierException) {
            $this->addFlash('error', $e->getMessage());

            return;
        }

        $this->getLogger()->critical('An error occurred while updating carriers data: {exception}', [
            'exception' => $e,
        ]);

        if ($this->debug) {
            throw $e;
        }

        $this->addFlash('error', $this->trans('An unexpected error occurred.', [], 'Modules.Inpostinternational.Errors'));
    }
}
