<?php

namespace Opencart\Extension\Alsendo\DTO;

require_once(DIR_EXTENSION . 'alsendo/src/DTO/Entity/OrderDetailsEntity.php');
require_once(DIR_EXTENSION . 'alsendo/src/Models/OrderShipment.php');
require_once(DIR_EXTENSION . 'alsendo/src/Models/OrderPickupPoint.php');
require_once(DIR_EXTENSION . 'alsendo/src/Enums/AddressType.php');
require_once(DIR_EXTENSION . 'alsendo/src/Enums/PickupType.php');
require_once(DIR_EXTENSION . 'alsendo/src/Enums/OrderShipmentStatus.php');
require_once(DIR_EXTENSION . 'alsendo/src/DTO/OrderShipmentCodeDTO.php');

use Opencart\Extension\Alsendo\DTO\Entity\OrderDetailsEntity;
use Opencart\Extension\Alsendo\Enums\AddressType;
use Opencart\Extension\Alsendo\Enums\OrderShipmentStatus;
use Opencart\Extension\Alsendo\Enums\PickupType;
use Opencart\Extension\Alsendo\Models\OrderShipment;
use Opencart\Extension\Alsendo\Models\OrderPickupPoint;

class FullOrderDTO
{
    public array $openCartOrder;
    public ?OrderDetailsEntity $orderDetails;
    /** @var OrderShipment[] */
    public array $orderShipments;
    public ?OrderPickupPoint $orderPickupPoint;

    public function __construct(
        array $openCartOrder = [],
        ?OrderDetailsEntity $orderDetails = null,
        array $orderShipments = [],
        ?OrderPickupPoint $orderPickupPoint = null
    ) {
        $this->openCartOrder = $openCartOrder;
        $this->orderDetails = $orderDetails;
        $this->orderShipments = $orderShipments;
        $this->orderPickupPoint = $orderPickupPoint;
    }

    public function hasNonCancelledShipmentGoingOn(): bool {
        foreach ($this->orderShipments as $orderShipment) {
            if ($orderShipment->getStatus() !== OrderShipmentStatus::CANCELLED) {
                return true;
            }
        }

        return false;
    }

    public function getLastNonCancelledShipment(): ?OrderShipment {
        foreach ($this->orderShipments as $orderShipment) {
            if ($orderShipment->getStatus() !== OrderShipmentStatus::CANCELLED) {
                return $orderShipment;
            }
        }

        return null;
    }

    public function getLastNonCancelledShipmentExternalId(): ?string {
        foreach ($this->orderShipments as $orderShipment) {
            if ($orderShipment->getStatus() !== OrderShipmentStatus::CANCELLED) {
                return $orderShipment->getExternalId();
            }
        }

        return null;
    }

    public function getLastNonCancelledWaybillNumber(): ?string {
        foreach ($this->orderShipments as $orderShipment) {
            if ($orderShipment->getStatus() !== OrderShipmentStatus::CANCELLED) {
                $waybillNumber = $orderShipment->getData()['waybill_number'] ?? null;

                if ($waybillNumber) {
                    return $waybillNumber;
                }

                if (!empty($orderShipment->getData()['waybillNumbers'][0]) !== null) {
                    return $orderShipment->getData()['waybillNumbers'][0];
                }
            }
        }

        return null;
    }

    public function getSenderPackagePickupType(): string
    {
        if (!$this->orderDetails || !$this->orderDetails->packageDetails) {
            return PickupType::NO_PICKUP;
        }

        $pickupType = $this->orderDetails->packageDetails->pickupType ?? null;
        if (!empty($pickupType)) {
            return $pickupType;
        }

        return PickupType::NO_PICKUP;
    }

    public function getSelectedServiceId(): ?int
    {
        $openCartShippingMethod = $this->openCartOrder['shipping_method'] ?? null;

        if ($openCartShippingMethod) {
            $openCartShippingMethod = json_decode(html_entity_decode($openCartShippingMethod), true);

            $openCartShippingMethodCode = $openCartShippingMethod['code'] ?? null;

            try {
                $orderShipmentCodeDTO = new OrderShipmentCodeDTO($openCartShippingMethodCode);
            } catch (\Exception $exception) {
                return null;
            }

            return $orderShipmentCodeDTO->serviceId;
        }

        if (!$this->orderDetails || !$this->orderDetails->shipment) {
            return null;
        }

        $selectedService = $this->orderDetails->shipment->serviceId ?? null;

        if (empty($selectedService)) {
            return null;
        }

        return (int) $selectedService;
    }

    public function getSelectedServiceExternalId(): ?string
    {
        if (!$this->orderDetails || !$this->orderDetails->shipment) {
            return null;
        }

        $selectedExternalServiceId = $this->orderDetails->shipment->externalServiceId ?? null;

        if (empty($selectedExternalServiceId)) {
            return null;
        }

        return (string) $selectedExternalServiceId;
    }

    public function getShippingAddressType(): ?string
    {
        return !empty($this->openCartOrder['shipping_company']) ? AddressType::COMPANY : AddressType::HOME;
    }

    public function getAttribute(string $key, ?string $group = null): mixed
    {
        if (!$this->orderDetails) {
            return null;
        }

        if ($group === 'sender' && $this->orderDetails->sender !== null) {
            $snakeToCamel = ['country' => 'country', 'full_name' => 'fullName', 'company_name' => 'companyName', 'street' => 'street', 'house_number' => 'houseNumber', 'apartment_number' => 'apartmentNumber', 'postal_code' => 'postalCode', 'city' => 'city', 'phone_number' => 'phoneNumber', 'email' => 'email'];
            $prop = $snakeToCamel[$key] ?? lcfirst(str_replace('_', '', ucwords($key, '_')));
            return $this->orderDetails->sender->$prop ?? null;
        }
        if ($group === 'package' && $this->orderDetails->packageDetails !== null) {
            if ($key === 'cod_value') {
                return $this->orderDetails->packageDetails->codValue?->toFloat();
            }
            if ($key === 'declared_value') {
                return $this->orderDetails->packageDetails->declaredValue?->toFloat();
            }
            $snakeToCamel = ['package_content' => 'packageContent', 'pickup_type' => 'pickupType'];
            $prop = $snakeToCamel[$key] ?? lcfirst(str_replace('_', '', ucwords($key, '_')));
            return $this->orderDetails->packageDetails->$prop ?? null;
        }

        return null;
    }

    public function getShippingCountryCode(): string
    {
        return $this->getAttribute('country', 'sender');
    }

    public function getShippingPhoneNumber(): string
    {
        return $this->openCartOrder['telephone'] ?? '';
    }

    public function getShippingPickupPoint(): ?array
    {
        if (!$this->orderPickupPoint) {
            return null;
        }

        return $this->orderPickupPoint->toArray()['pickup_point'] ?? null;
    }

    public function getShipmentPickupPoint(): ?array
    {
        if (!$this->orderDetails || !$this->orderDetails->shipment) {
            return null;
        }

        $shipmentPickupPoint = $this->orderDetails->shipment->shipmentPickupPoint ?? null;
        if (!$shipmentPickupPoint) {
            return null;
        }

        if (is_array($shipmentPickupPoint)) {
            return $shipmentPickupPoint;
        }

        if (is_string($shipmentPickupPoint)) {
            return json_decode(htmlspecialchars_decode($shipmentPickupPoint), true);
        }

        return null;
    }

    public function getCodValueOrNull(): ?float
    {
        if (!$this->orderDetails || !$this->orderDetails->packageDetails || !$this->orderDetails->packageDetails->codValue) {
            return null;
        }

        return $this->orderDetails->packageDetails->codValue->toFloat();
    }

    public function getDeclaredValueOrNull(): ?float
    {
        if (!$this->orderDetails || !$this->orderDetails->packageDetails || !$this->orderDetails->packageDetails->declaredValue) {
            return null;
        }

        return $this->orderDetails->packageDetails->declaredValue->toFloat();
    }

    /**
     * Returns order details in legacy array format for WrapperService compatibility.
     */
    public function getOrderDetailsDataForWrapper(): ?array
    {
        if (!$this->orderDetails) {
            return null;
        }
        $od = $this->orderDetails;
        $sender = $od->sender;
        $shipping = $od->shippingAddress;
        $pkg = $od->packageDetails;
        $shipment = $od->shipment;

        $senderData = null;
        if ($sender) {
            $senderData = [
                'id' => $sender->id,
                'external_id' => $sender->externalId ?? null,
                'address_type' => $sender->addressType ?? 'company',
                'company_name' => $sender->companyName ?? '',
                'full_name' => $sender->fullName ?? '',
                'street' => $sender->street ?? '',
                'house_number' => $sender->houseNumber ?? '',
                'apartment_number' => $sender->apartmentNumber ?? '',
                'block' => $sender->block ?? '',
                'entrance' => $sender->entrance ?? '',
                'floor' => $sender->floor ?? '',
                'country' => $sender->country ?? '',
                'postal_code' => $sender->postalCode ?? '',
                'city' => $sender->city ?? '',
                'phone_number' => $sender->phoneNumber ?? '',
                'email' => $sender->email ?? '',
                'bank_account_number' => $sender->bankAccountNumber ?? '',
                'bank_code' => $sender->bankCode ?? null,
                'additional_bank_account_number' => $sender->additionalBankAccountNumber ?? null,
                'shipping_point' => $sender->shippingPoint ?? null,
            ];
        }

        $shippingData = null;
        if ($shipping) {
            $shippingData = [
                'address_type' => $shipping->addressType ?? 'home',
                'company_name' => $shipping->companyName ?? '',
                'full_name' => $shipping->fullName ?? '',
                'street' => $shipping->street ?? '',
                'house_number' => $shipping->houseNumber ?? '',
                'apartment_number' => $shipping->apartmentNumber ?? '',
                'block' => $shipping->block ?? '',
                'entrance' => $shipping->entrance ?? '',
                'floor' => $shipping->floor ?? '',
                'country' => $shipping->country ?? '',
                'postal_code' => $shipping->postalCode ?? '',
                'city' => $shipping->city ?? '',
                'phone_number' => $shipping->phoneNumber ?? '',
                'email' => $shipping->email ?? '',
            ];
        }

        $packageData = null;
        if ($pkg) {
            $packages = [];
            foreach ($pkg->packages as $p) {
                $packages[] = [
                    'package_template_id' => $p->templateId,
                    'template_name' => $p->templateName,
                    'package_width' => $p->packageWidth,
                    'package_length' => $p->packageLength,
                    'package_height' => $p->packageHeight,
                    'package_weight' => $p->packageWeight,
                    'package_shipment_packaging' => $p->packageShipmentPackaging ?? 'standard',
                    'non_standard' => $p->nonStandard ?? false,
                ];
            }
            $packageData = [
                'package_content' => $pkg->packageContent ?? '',
                'cod_value' => $pkg->codValue?->toFloat(),
                'declared_value' => $pkg->declaredValue?->toFloat(),
                'pickup_type' => $pkg->pickupType ?? 'COURIER',
                'ship_via_pickup_point' => $pkg->shipViaPickupPoint ?? false,
                'pickup_request' => $pkg->pickupRequest ?? false,
                'packages' => $packages,
            ];
        }

        $shipmentData = null;
        if ($shipment) {
            $shipmentData = [
                'shipping_method_id' => $shipment->shippingMethodId,
                'shipping_method_name' => $shipment->shippingMethodName ?? '',
                'shipping_service_name' => $shipment->shippingServiceName ?? '',
                'service_id' => $shipment->serviceId,
                'external_service_id' => $shipment->externalServiceId ?? '',
                'preferred_pickup_date' => $shipment->preferredPickupDate ?? null,
                'preferred_pickup_hour_from' => $shipment->preferredPickupHourFrom ?? null,
                'preferred_pickup_hour_to' => $shipment->preferredPickupHourTo ?? null,
                'shipment_pickup_point' => $shipment->shipmentPickupPoint ?? null,
                'shipment_pickup_point_display' => $shipment->shipmentPickupPointDisplay ?? null,
            ];
        }

        return [
            'sender' => $senderData ?? [],
            'shipping_address' => $shippingData ?? [],
            'package' => $packageData ?? ['packages' => [], 'package_content' => '', 'cod_value' => null, 'declared_value' => null, 'pickup_type' => 'COURIER', 'ship_via_pickup_point' => false, 'pickup_request' => false],
            'shipment' => $shipmentData ?? [],
        ];
    }
}
