<?php

namespace Opencart\Admin\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\AbstractOrderDetailsShippingAddressEntity;
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 AlsendoOrderDetailsShippingAddress extends Model
{
    public function __construct(Registry $registry)
    {
        parent::__construct($registry);
    }

    public function populate(): void
    {
        $this->db->query("
            CREATE TABLE IF NOT EXISTS `" . DB_PREFIX . "alsendo_order_details_shipping_address` (
                `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
                `order_details_id` INT(11) UNSIGNED DEFAULT NULL,
                `full_name` VARCHAR(255) NULL DEFAULT NULL,
                `company_name` VARCHAR(255) NULL DEFAULT NULL,
                `address_type` VARCHAR(255) NULL DEFAULT NULL,
                `phone_number` VARCHAR(255) NULL DEFAULT NULL,
                `email` VARCHAR(255) NULL DEFAULT NULL,
                `country` VARCHAR(255) NULL DEFAULT NULL,
                `city` VARCHAR(255) NULL DEFAULT NULL,
                `postal_code` VARCHAR(255) NULL DEFAULT NULL,
                `street` VARCHAR(255) NULL DEFAULT NULL,
                `house_number` VARCHAR(255) NULL DEFAULT NULL,
                `block` VARCHAR(255) NULL DEFAULT NULL,
                `entrance` VARCHAR(255) NULL DEFAULT NULL,
                `floor` VARCHAR(255) NULL DEFAULT NULL,
                `apartment_number` VARCHAR(255) NULL DEFAULT NULL,
                `delivery_point` JSON NULL DEFAULT NULL,
                PRIMARY KEY (`id`),
                CONSTRAINT `fk_alsendo_order_details_shipping_address_order_details`
                    FOREIGN KEY (`order_details_id`)
                    REFERENCES `" . DB_PREFIX . "alsendo_order_details` (`id`)
                    ON DELETE CASCADE
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
        ");
    }

    public function getShippingAddressByOrderId(int $orderId, ?OrderDetailsEntityFactoryInterface $factory = null): ?AbstractOrderDetailsShippingAddressEntity
    {
        $query = $this->db->query("
            SELECT a.*
            FROM `" . DB_PREFIX . "alsendo_order_details_shipping_address` a
            LEFT JOIN `" . DB_PREFIX . "alsendo_order_details` d ON d.id = a.order_details_id
            WHERE d.order_id = '" . (int)$orderId . "'
            LIMIT 1
        ");

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

        $factory = $factory ?? new ApaczkaOrderDetailsEntityFactory();
        return $factory->createShippingAddressFromArray($query->row);
    }

    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 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 updateShippingAddress(int $shippingAddressId, array $data): void
    {
        $updates = [];

        if (array_key_exists('full_name', $data)) {
            $updates[] = $data['full_name'] === null ? "`full_name` = NULL" : "`full_name` = '" . $this->db->escape($data['full_name']) . "'";
        }

        if (array_key_exists('company_name', $data)) {
            $updates[] = $data['company_name'] === null ? "`company_name` = NULL" : "`company_name` = '" . $this->db->escape($data['company_name']) . "'";
        }

        if (array_key_exists('address_type', $data)) {
            $updates[] = $data['address_type'] === null ? "`address_type` = NULL" : "`address_type` = '" . $this->db->escape($data['address_type']) . "'";
        }

        if (array_key_exists('phone_number', $data)) {
            $updates[] = $data['phone_number'] === null ? "`phone_number` = NULL" : "`phone_number` = '" . $this->db->escape($data['phone_number']) . "'";
        }

        if (array_key_exists('email', $data)) {
            $updates[] = $data['email'] === null ? "`email` = NULL" : "`email` = '" . $this->db->escape($data['email']) . "'";
        }

        if (array_key_exists('country', $data)) {
            $updates[] = $data['country'] === null ? "`country` = NULL" : "`country` = '" . $this->db->escape($data['country']) . "'";
        }

        if (array_key_exists('city', $data)) {
            $updates[] = $data['city'] === null ? "`city` = NULL" : "`city` = '" . $this->db->escape($data['city']) . "'";
        }

        if (array_key_exists('postal_code', $data)) {
            $updates[] = $data['postal_code'] === null ? "`postal_code` = NULL" : "`postal_code` = '" . $this->db->escape($data['postal_code']) . "'";
        }

        if (array_key_exists('street', $data)) {
            $updates[] = $data['street'] === null ? "`street` = NULL" : "`street` = '" . $this->db->escape($data['street']) . "'";
        }

        if (array_key_exists('house_number', $data)) {
            $updates[] = $data['house_number'] === null ? "`house_number` = NULL" : "`house_number` = '" . $this->db->escape($data['house_number']) . "'";
        }

        if (array_key_exists('block', $data)) {
            $updates[] = $data['block'] === null ? "`block` = NULL" : "`block` = '" . $this->db->escape($data['block']) . "'";
        }

        if (array_key_exists('entrance', $data)) {
            $updates[] = $data['entrance'] === null ? "`entrance` = NULL" : "`entrance` = '" . $this->db->escape($data['entrance']) . "'";
        }

        if (array_key_exists('floor', $data)) {
            $updates[] = $data['floor'] === null ? "`floor` = NULL" : "`floor` = '" . $this->db->escape($data['floor']) . "'";
        }

        if (array_key_exists('apartment_number', $data)) {
            $updates[] = $data['apartment_number'] === null ? "`apartment_number` = NULL" : "`apartment_number` = '" . $this->db->escape($data['apartment_number']) . "'";
        }

        if (array_key_exists('delivery_point', $data)) {
            $deliveryPoint = $data['delivery_point'] === null ? null : (is_array($data['delivery_point']) ? json_encode($data['delivery_point'], JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT) : $data['delivery_point']);
            $updates[] = "`delivery_point` = " . ($deliveryPoint !== null && $deliveryPoint !== '' ? "'" . $this->db->escape($deliveryPoint) . "'" : "NULL");
        }

        if (!empty($updates)) {
            $this->db->query("
                UPDATE `" . DB_PREFIX . "alsendo_order_details_shipping_address`
                SET " . implode(", ", $updates) . "
                WHERE `id` = '" . (int)$shippingAddressId . "'
            ");
        }
    }
}
