<?php

declare(strict_types=1);

namespace Macopedia\OrlenShipping\Controller\Adminhtml\Shipment;

use Exception;
use Macopedia\OrlenShipping\Model\Carrier\OrlenShipping;
use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection;
use Magento\Sales\Controller\Adminhtml\Order\AbstractMassAction;
use Magento\Ui\Component\MassAction\Filter;
use Magento\Backend\App\Action\Context;
use Magento\Framework\Controller\ResultInterface;
use Macopedia\OrlenShipping\Model\Api\OrderCourier;
use Macopedia\OrlenShipping\Model\CourierOrderFactory;
use Macopedia\OrlenShipping\Model\ResourceModel\CourierOrder as CourierOrderResource;
use Magento\Sales\Model\ResourceModel\Order\Shipment\CollectionFactory;
use DateTime;
use DateTimeZone;

class MassOrderCourier extends AbstractMassAction
{
    /**
     * Authorization level of a basic admin session
     *
     * @see _isAllowed()
     */
    public const ADMIN_RESOURCE = 'Magento_Sales::shipment';

    /**
     * @param Context $context
     * @param Filter $filter
     * @param CollectionFactory $collectionFactory
     * @param OrderCourier $orderCourier
     * @param CourierOrderFactory $courierOrderFactory
     * @param CourierOrderResource $courierOrderResource
     */
    public function __construct(
        Context $context,
        Filter $filter,
        CollectionFactory $collectionFactory,
        private readonly OrderCourier $orderCourier,
        private readonly CourierOrderFactory $courierOrderFactory,
        private readonly CourierOrderResource $courierOrderResource
    ) {
        $this->collectionFactory = $collectionFactory;
        parent::__construct($context, $filter);
    }

    /**
     * Batch generate shipping protocols
     *
     * @param AbstractCollection $collection
     * @return ResultInterface
     */
    protected function massAction(AbstractCollection $collection): ResultInterface
    {
        try {
            $request = $this->_request->getParams();
            $date = $request['pickup_date'];
            $time = $request['pickup_time'];

            $dates = $this->prepareDates($date, $time);
            $readyDate = $dates['ready_date'];
            $pickupDate = $dates['pickup_date'];
            $shippingNumbers = [];
            $notOrlenShippingNumbers = [];

            foreach ($collection as $shipment) {
                if (!str_contains($shipment->getOrder()->getShippingMethod(), OrlenShipping::CODE)) {
                    $notOrlenShippingNumbers[] = $shipment->getIncrementId();
                    continue;
                }
                $shippingNumbers[] = $shipment->getIncrementId();
            }

            if (!empty($notOrlenShippingNumbers)) {
                $this->messageManager->addError(
                    __('There are no ORLEN shipments corresponding to the following numbers: ')
                    . implode(',', $notOrlenShippingNumbers)
                );
                return $this->resultRedirectFactory->create()->setPath('sales/shipment/');
            }

            $callPickupResponse = $this->orderCourier->callPickup($shippingNumbers, $readyDate, $pickupDate);
            $courierOrder = $this->courierOrderFactory->create();
            $courierOrder->setData(
                [
                    'order_number' => $callPickupResponse->CourierOrderNumber,
                    'ready_date' => $readyDate,
                    'pickup_date' => $pickupDate,
                ]
            );
            $this->courierOrderResource->save($courierOrder);

            $this->messageManager->addSuccessMessage(__('Courier has been ordered.'));
        } catch (Exception $e) {
            $this->messageManager->addErrorMessage(__('Failed to order a courier: ') . $e->getMessage());
        }

        return $this->resultRedirectFactory->create()->setPath('sales/shipment/');
    }

    /**
     * Prepare ready date and pickup date params
     *
     * @param string $date
     * @param string $time
     * @return array
     * @throws Exception
     */
    private function prepareDates(string $date, string $time): array
    {
        list($startTime, $endTime) = explode('-', $time);

        $timezone = new DateTimeZone('Europe/Warsaw');

        $readyDate = new DateTime($date . ' ' . $startTime, $timezone);
        $pickupDate = new DateTime($date . ' ' . $endTime, $timezone);

        // Format to ISO 8601 with timezone
        return [
            'ready_date' => $readyDate->format('Y-m-d\TH:i:sP'),
            'pickup_date' => $pickupDate->format('Y-m-d\TH:i:sP')
        ];
    }
}
