<?php

namespace PortalPeople\OrderWebhook\Model;

use Magento\Sales\Api\Data\OrderInterface;
use Magento\Sales\Api\Data\OrderItemInterface;
use Magento\Store\Model\StoreManagerInterface;

/**
 * Order data builder for webhook payload
 */
class OrderDataBuilder
{
    /**
     * @var StoreManagerInterface
     */
    private $storeManager;

    /**
     * @param StoreManagerInterface $storeManager
     */
    public function __construct(
        StoreManagerInterface $storeManager
    ) {
        $this->storeManager = $storeManager;
    }

    /**
     * Build order data array for webhook
     *
     * @param OrderInterface $order
     * @param string $eventType
     * @return array
     */
    public function build(OrderInterface $order, string $eventType): array
    {
        $store = $this->storeManager->getStore($order->getStoreId());
        $storeUrl = $store->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_WEB);

        $orderData = [
            'event_type' => $eventType,
            'timestamp' => date('c'),
            'order_source' => rtrim($storeUrl, '/'),
            'order' => [
                'id' => $order->getId(),
                'increment_id' => $order->getIncrementId(),
                'status' => $order->getStatus(),
                'state' => $order->getState(),
                'store_id' => $order->getStoreId(),
                'created_at' => $order->getCreatedAt(),
                'updated_at' => $order->getUpdatedAt(),
                'currency_code' => $order->getOrderCurrencyCode(),
                'grand_total' => $order->getGrandTotal(),
                'subtotal' => $order->getSubtotal(),
                'tax_amount' => $order->getTaxAmount(),
                'shipping_amount' => $order->getShippingAmount(),
                'discount_amount' => $order->getDiscountAmount(),
                'total_qty_ordered' => $order->getTotalQtyOrdered(),
                'weight' => $order->getWeight(),
                'coupon_code' => $order->getCouponCode(),
            ],
            'customer' => $this->buildCustomerData($order),
            'billing_address' => $this->buildAddressData($order->getBillingAddress()),
            'shipping_address' => $this->buildAddressData($order->getShippingAddress()),
            'payment' => $this->buildPaymentData($order),
            'items' => $this->buildItemsData($order->getAllVisibleItems()),
            'shipping_method' => [
                'method' => $order->getShippingMethod(),
                'description' => $order->getShippingDescription(),
            ],
            'shipping_fields' => [
                'shipping_date' => $order->getData('shipping_date'),
                'shipping_message' => $order->getData('shipping_message'),
            ]
        ];

        return $orderData;
    }

    /**
     * Build customer data
     *
     * @param OrderInterface $order
     * @return array
     */
    private function buildCustomerData(OrderInterface $order): array
    {
        return [
            'id' => $order->getCustomerId(),
            'email' => $order->getCustomerEmail(),
            'firstname' => $order->getCustomerFirstname(),
            'lastname' => $order->getCustomerLastname(),
            'middlename' => $order->getCustomerMiddlename(),
            'prefix' => $order->getCustomerPrefix(),
            'suffix' => $order->getCustomerSuffix(),
            'group_id' => $order->getCustomerGroupId(),
            'is_guest' => $order->getCustomerIsGuest(),
            'dob' => $order->getCustomerDob(),
            'gender' => $order->getCustomerGender(),
        ];
    }

    /**
     * Build address data
     *
     * @param \Magento\Sales\Api\Data\OrderAddressInterface|null $address
     * @return array|null
     */
    private function buildAddressData($address): ?array
    {
        if (!$address) {
            return null;
        }

        return [
            'firstname' => $address->getFirstname(),
            'lastname' => $address->getLastname(),
            'company' => $address->getCompany(),
            'street' => implode(',', $address->getStreet()),
            'city' => $address->getCity(),
            'region' => $address->getRegion(),
            'region_code' => $address->getRegionCode(),
            'postcode' => $address->getPostcode(),
            'country_id' => $address->getCountryId(),
            'telephone' => $address->getTelephone(),
            'fax' => $address->getFax(),
        ];
    }

    /**
     * Build payment data
     *
     * @param OrderInterface $order
     * @return array
     */
    private function buildPaymentData(OrderInterface $order): array
    {
        $payment = $order->getPayment();
        if (!$payment) {
            return [];
        }

        return [
            'method' => $payment->getMethod(),
            'additional_information' => $payment->getAdditionalInformation(),
            'cc_last4' => $payment->getCcLast4(),
            'cc_type' => $payment->getCcType(),
            'cc_exp_month' => $payment->getCcExpMonth(),
            'cc_exp_year' => $payment->getCcExpYear(),
        ];
    }

    /**
     * Build items data
     *
     * @param OrderItemInterface[] $items
     * @return array
     */
    private function buildItemsData(array $items): array
    {
        $itemsData = [];

        foreach ($items as $item) {
            // Skip simple child items of configurable products (price is 0; price lives on the parent)
            if ($item->getProductType() === 'simple' && (float)$item->getPrice() == 0) {
                continue;
            }

            $itemsData[] = [
                'item_id' => $item->getItemId(),
                'product_id' => $item->getProductId(),
                'sku' => $item->getSku(),
                'name' => $item->getName(),
                'description' => $item->getDescription(),
                'weight' => $item->getWeight(),
                'qty_ordered' => $item->getQtyOrdered(),
                'price' => $item->getPrice(),
                'row_total' => $item->getRowTotal(),
                'row_total_incl_tax' => $item->getRowTotalInclTax(),
                'tax_amount' => $item->getTaxAmount(),
                'discount_amount' => $item->getDiscountAmount(),
                'product_type' => $item->getProductType(),
                'product_options' => $item->getProductOptions(),
            ];
        }

        return $itemsData;
    }
}
