<?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');
require_once(DIR_EXTENSION . 'alsendo/src/Services/MapWidgetService.php');

use Opencart\Extension\Alsendo\DTO\Entity\AbstractOrderDetailsShippingAddressEntity;
use Opencart\Extension\Alsendo\DTO\Entity\OrderDetailsEntityFactoryInterface;
use Opencart\Extension\Alsendo\DTO\Entity\Apaczka\ApaczkaOrderDetailsEntityFactory;
use Opencart\Extension\Alsendo\Services\MapWidgetService;
use Opencart\System\Engine\Model;
use Opencart\System\Engine\Registry;

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

    public function insertShippingAddress(int $orderDetailsId, array $data): void
    {
        $deliveryPoint = array_key_exists('delivery_point', $data) ? (is_array($data['delivery_point']) ? json_encode($data['delivery_point']) : $data['delivery_point']) : null;
        $sqlVal = function($key) use ($data) {
            return array_key_exists($key, $data) ? ($data[$key] === null ? "NULL" : "'" . $this->db->escape($data[$key]) . "'") : "NULL";
        };
        $this->db->query("
            INSERT INTO `" . DB_PREFIX . "alsendo_order_details_shipping_address`
            SET `order_details_id` = '" . (int)$orderDetailsId . "',
                `full_name` = " . $sqlVal('full_name') . ",
                `company_name` = " . $sqlVal('company_name') . ",
                `address_type` = " . $sqlVal('address_type') . ",
                `phone_number` = " . $sqlVal('phone_number') . ",
                `email` = " . $sqlVal('email') . ",
                `country` = " . $sqlVal('country') . ",
                `city` = " . $sqlVal('city') . ",
                `postal_code` = " . $sqlVal('postal_code') . ",
                `street` = " . $sqlVal('street') . ",
                `house_number` = " . $sqlVal('house_number') . ",
                `block` = " . $sqlVal('block') . ",
                `entrance` = " . $sqlVal('entrance') . ",
                `floor` = " . $sqlVal('floor') . ",
                `apartment_number` = " . $sqlVal('apartment_number') . ",
                `delivery_point` = " . ($deliveryPoint !== null ? "'" . $this->db->escape($deliveryPoint) . "'" : "NULL") . "
        ");
    }

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

    public function updatePickupPointByOrderId($orderId, ?array $pickupPointToSaveArray): 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;
        }

        if (empty($pickupPointToSaveArray)) {
            $orderQuery = $this->db->query("
                SELECT date_added
                FROM `" . DB_PREFIX . "order`
                WHERE order_id = '" . (int) $orderId . "'
                LIMIT 1
            ");
            if (!$orderQuery->num_rows) {
                return;
            }
            $orderDate = $orderQuery->row['date_added'] ?? null;
            if (!$orderDate) {
                return;
            }
            $this->registry->get('load')->model('extension/alsendo/module/alsendo_order_selected_pickup_points');
            $selectedPickupModel = $this->registry->get('model_extension_alsendo_module_alsendo_order_selected_pickup_points');
            $fallback = $selectedPickupModel->findLatestWithoutOrderCreatedAround($orderDate, 2);
            if (!$fallback || empty($fallback['pickup_point'])) {
                return;
            }
            $pickupPointToSaveArray = json_decode($fallback['pickup_point'], true);
            if (!is_array($pickupPointToSaveArray)) {
                return;
            }
            $selectedPickupModel->assignOrderId((int) $fallback['id'], (int) $orderId);
        }

        $deliveryPickupPoint = json_encode(
            $pickupPointToSaveArray,
            JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT
        );

        $this->db->query("
            UPDATE `" . DB_PREFIX . "alsendo_order_details_shipping_address` s
            LEFT JOIN `" . DB_PREFIX . "alsendo_order_details` d ON d.id = s.order_details_id
            SET
                s.delivery_point = '" . $this->db->escape($deliveryPickupPoint) . "'
            WHERE d.order_id = '" . (int) $orderId . "'
        ");

        $shipmentRow = $this->db->query("
            SELECT s.shipment_pickup_point, s.shipment_pickup_point_display
            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 = '" . (int) $orderId . "'
            LIMIT 1
        ");
        if ($shipmentRow->num_rows) {
            $sp = $shipmentRow->row['shipment_pickup_point'] ?? null;
            $spDisplay = $shipmentRow->row['shipment_pickup_point_display'] ?? null;
            $shipmentEmpty = ($sp === null || $sp === '') && ($spDisplay === null || $spDisplay === '');
            if ($shipmentEmpty) {
                $operator = $pickupPointToSaveArray['operator'] ?? null;
                if ($operator !== null && $operator !== '') {
                    $key = MapWidgetService::getOperatorKeyFromValue($operator);
                    if ($key !== null) {
                        $column = $key . '_default_point';
                        $allowedColumns = [
                            'inpost_default_point', 'dhl_default_point', 'orlen_default_point',
                            'poczta_polska_default_point', 'dpd_default_point', 'ups_default_point',
                            'balikovna_default_point', 'gls_default_point', 'ppl_default_point',
                            'zasilkovna_default_point', 'sameday_default_point', 'fan_courier_default_point',
                            'cargus_default_point'
                        ];
                        if (in_array($column, $allowedColumns, true)) {
                            $defaultQuery = $this->db->query("
                                SELECT `" . $column . "` AS val
                                FROM `" . DB_PREFIX . "alsendo_additional_settings`
                                LIMIT 1
                            ");
                            if ($defaultQuery->num_rows && !empty($defaultQuery->row['val'])) {
                                $defaultPoint = json_decode($defaultQuery->row['val'], true);
                                if (is_array($defaultPoint)) {
                                    $shipmentPickupPoint = json_encode(
                                        $defaultPoint,
                                        JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT
                                    );
                                    $display = isset($defaultPoint['code'], $defaultPoint['name'])
                                        ? ($defaultPoint['code'] . ' - ' . $defaultPoint['name'])
                                        : '';
                                    $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 = '" . $this->db->escape($display) . "'
                                        WHERE d.order_id = '" . (int) $orderId . "'
                                    ");
                                }
                            }
                        }
                    }
                }
            }
        }
    }

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