<?php

namespace Opencart\Catalog\Model\Extension\Alsendo\Module;

require_once(DIR_EXTENSION . 'alsendo/src/DTO/Entity/OrderDetailsEntityFactoryInterface.php');
require_once(DIR_EXTENSION . 'alsendo/src/DTO/Entity/Apaczka/ApaczkaOrderDetailsEntityFactory.php');

use Opencart\Extension\Alsendo\DTO\Entity\AbstractOrderDetailsShipmentEntity;
use Opencart\Extension\Alsendo\DTO\Entity\OrderDetailsEntityFactoryInterface;
use Opencart\Extension\Alsendo\DTO\Entity\Apaczka\ApaczkaOrderDetailsEntityFactory;
use Opencart\System\Engine\Model;
use Opencart\System\Engine\Registry;

class AlsendoOrderDetailsShipment extends Model
{
    public function __construct(Registry $registry)
    {
        parent::__construct($registry);
    }

    public function insertShipment(int $orderDetailsId, array $data): void
    {
        $shipmentPickupPoint = null;
        if (!empty($data['shipment_pickup_point'])) {
            $shipmentPickupPoint = $data['shipment_pickup_point'];

            if (is_string($shipmentPickupPoint)) {
                $shipmentPickupPoint = json_decode(html_entity_decode($shipmentPickupPoint), true);
            }

            if (isset($shipmentPickupPoint['raw'])) {
                unset($shipmentPickupPoint['raw']);
            }

            $shipmentPickupPoint = json_encode(
                $shipmentPickupPoint,
                JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT
            );
        }

        $strSql = function($key) use ($data) {
            return array_key_exists($key, $data) ? ($data[$key] === null ? "NULL" : "'" . $this->db->escape(htmlspecialchars($data[$key], ENT_QUOTES, 'UTF-8')) . "'") : "NULL";
        };
        $intSql = function($key) use ($data) {
            return (array_key_exists($key, $data) && $data[$key] !== null && $data[$key] !== '') ? "'" . (int)$data[$key] . "'" : "NULL";
        };
        $this->db->query("
        INSERT INTO `" . DB_PREFIX . "alsendo_order_details_shipment`
        SET `order_details_id` = '" . (int)$orderDetailsId . "',
            `shipping_method_id` = " . $intSql('shipping_method_id') . ",
            `shipping_method_name` = " . $strSql('shipping_method_name') . ",
            `service_id` = " . $intSql('service_id') . ",
            `external_service_id` = " . $strSql('external_service_id') . ",
            `shipping_service_name` = " . $strSql('shipping_service_name') . ",
            `map_operator` = " . $strSql('map_operator') . ",
            `preferred_pickup_date` = " . (array_key_exists('preferred_pickup_date', $data) && $data['preferred_pickup_date'] !== null && $data['preferred_pickup_date'] !== '' ? "'" . $this->db->escape($data['preferred_pickup_date']) . "'" : "NULL") . ",
            `preferred_pickup_hour_from` = " . $strSql('preferred_pickup_hour_from') . ",
            `preferred_pickup_hour_to` = " . $strSql('preferred_pickup_hour_to') . ",
            `shipment_pickup_point` = " . ($shipmentPickupPoint !== null && $shipmentPickupPoint !== '' ? "'" . $this->db->escape($shipmentPickupPoint) . "'" : "NULL") . ",
            `shipment_pickup_point_display` = " . $strSql('shipment_pickup_point_display') . "
        ");
    }

    public function getShipmentByOrderDetailsId(int $orderDetailsId, ?OrderDetailsEntityFactoryInterface $factory = null): ?AbstractOrderDetailsShipmentEntity
    {
        $query = $this->db->query("
            SELECT *
            FROM `" . DB_PREFIX . "alsendo_order_details_shipment`
            WHERE order_details_id = '" . (int)$orderDetailsId . "'
            LIMIT 1
        ");
        if (!$query->num_rows) {
            return null;
        }
        $factory = $factory ?? new ApaczkaOrderDetailsEntityFactory();
        return $factory->createShipmentFromArray($query->row);
    }

    public function updatePickupPointByOrderId(int $orderId, array $pickupPointData): void
    {
        $query = $this->db->query("
            SELECT s.shipping_method_id
            FROM `" . DB_PREFIX . "alsendo_order_details_shipment` s
            LEFT JOIN `" . DB_PREFIX . "alsendo_order_details` d ON d.id = s.order_details_id
            WHERE d.order_id = '$orderId'
            LIMIT 1
        ");

        if (!$query->num_rows) {
            return;
        }

        $shippingMethodId = $query->row['shipping_method_id'] ?? 0;

        $methodQuery = $this->db->query("
            SELECT has_map
            FROM `" . DB_PREFIX . "alsendo_shipping_methods`
            WHERE id = '$shippingMethodId'
            LIMIT 1
        ");

        $hasMap = $methodQuery->num_rows ? (int)$methodQuery->row['has_map'] : 0;

        if ($hasMap === 0) {
            $this->deletePickupPointByOrderId($orderId);

            return;
        }


        $shipmentPickupPoint = json_encode(
            $pickupPointData,
            JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT
        );

        $display = isset($pickupPointData['name'])
            ? "'" . $this->db->escape(sprintf('%s - %s', $pickupPointData['code'], htmlspecialchars($pickupPointData['name'], ENT_QUOTES, 'UTF-8'))) . "'"
            : "NULL";

        $this->db->query("
            UPDATE `" . DB_PREFIX . "alsendo_order_details_shipment` s
            LEFT JOIN `" . DB_PREFIX . "alsendo_order_details` d ON d.id = s.order_details_id
            SET
                s.shipment_pickup_point = '" . $this->db->escape($shipmentPickupPoint) . "',
                s.shipment_pickup_point_display = {$display}
            WHERE d.order_id = '$orderId'
        ");
    }

    public function deletePickupPointByOrderId(int $orderId): void
    {
        $this->db->query("
            UPDATE `" . DB_PREFIX . "alsendo_order_details_shipment` s
            LEFT JOIN `" . DB_PREFIX . "alsendo_order_details` d ON d.id = s.order_details_id
            SET
                s.shipment_pickup_point = NULL,
                s.shipment_pickup_point_display = NULL
            WHERE d.order_id = '" . $orderId . "'
        ");
    }
}
