<?php

namespace PortalPeople\magento\components;

class FieldMapper
{
    public static function normalizeOrder(array $rawOrder): array
    {
        $rawSource = $rawOrder['_raw'] ?? $rawOrder;
        $billing = $rawOrder['billingAddress'] ?? $rawOrder['billingAddress'] ?? $rawSource['billing_address'] ?? [];
        $shipping = $rawOrder['deliveryAddress'] ?? $rawOrder['deliveryAddress'] ?? $rawOrder['shippingAddress'] ?? $rawSource['shipping_address'] ?? self::extractShippingAddress($rawSource);
        $customer = $rawOrder['customer'] ?? [];
        $payment = $rawOrder['payment'] ?? [];
        $order = $rawOrder['order'] ?? $rawOrder;

        $customerFirstName = (string) ($customer['firstname'] ?? $rawSource['customer_firstname'] ?? '');
        $customerLastName = (string) ($customer['lastname'] ?? $rawSource['customer_lastname'] ?? '');
        $customerEmail = (string) ($customer['email'] ?? $rawSource['customer_email'] ?? '');
        $telephone = (string) ($billing['telephone'] ?? $shipping['telephone'] ?? $rawSource['telephone'] ?? '');

        $billingAddress = self::extractAddress($billing, $rawOrder['billingAddress'] ?? []);
        $shippingAddress = self::extractAddress($shipping, $rawOrder['deliveryAddress'] ?? []);

        return [
            'orderNo' => self::firstNonEmptyString($rawOrder['orderNo'] ?? null, $order['increment_id'] ?? null, $order['entity_id'] ?? null, $rawSource['increment_id'] ?? null, $rawSource['entity_id'] ?? null, $rawOrder['id'] ?? null),
            'orderId' => self::firstNonEmptyString($rawOrder['orderId'] ?? null, $order['entity_id'] ?? null, $rawOrder['id'] ?? null),
            'status' => self::firstNonEmptyString($rawOrder['status'] ?? null, $order['status'] ?? null, 'pending'),
            'orderDate' => self::firstNonEmptyString($rawOrder['orderDate'] ?? null, $order['created_at'] ?? null, $order['updated_at'] ?? null),
            'customerName' => self::firstNonEmptyString($rawOrder['customerName'] ?? null, trim($customerFirstName . ' ' . $customerLastName)),
            'customerEmail' => self::firstNonEmptyString($rawOrder['customerEmail'] ?? null, $customerEmail),
            'telephone' => self::firstNonEmptyString($rawOrder['telephone'] ?? null, $telephone),
            'currency' => self::firstNonEmptyString($rawOrder['currency'] ?? null, $order['base_currency_code'] ?? null, $order['order_currency_code'] ?? null, $rawSource['base_currency_code'] ?? null, $rawSource['order_currency_code'] ?? null),
            'deliveryAddress' => array_merge([
                'address1' => '',
                'address2' => '',
                'city' => '',
                'postcode' => '',
                'country' => '',
            ], $shippingAddress),
            'billingAddress' => array_merge([
                'line1' => '',
                'line2' => '',
                'city' => '',
                'postcode' => '',
                'country' => '',
            ], $billingAddress),
            'paymentMethod' => self::firstNonEmptyString($rawOrder['paymentMethod'] ?? null, $payment['method'] ?? null, $rawSource['payment']['method'] ?? null),
            'orderLines' => self::normalizeLines($rawOrder['orderLines'] ?? $rawSource['items'] ?? []),
            '_raw' => $rawOrder,
        ];
    }

    private static function extractShippingAddress(array $rawSource): array
    {
        $assignments = $rawSource['extension_attributes']['shipping_assignments'] ?? [];
        $firstAssignment = is_array($assignments) && $assignments !== [] ? $assignments[0] : [];
        $address = $firstAssignment['shipping']['address'] ?? [];

        return is_array($address) ? $address : [];
    }

    private static function extractAddress(array $address, array $fallback = []): array
    {
        $street = $address['street'] ?? $fallback['street'] ?? '';
        $line1 = is_array($street) ? self::normalizeStreet($street) : self::normalizeStreet($street);

        return [
            'companyname' => (string) ($address['company'] ?? $fallback['company'] ?? $line1),
            'address1' => $line1,
            'address2' => (string) ($address['line2'] ?? $fallback['line2'] ?? ''),
            'city' => (string) ($address['city'] ?? $fallback['city'] ?? ''),
            'postcode' => (string) ($address['postcode'] ?? $fallback['postcode'] ?? ''),
            'county' => (string) ($address['county'] ?? $fallback['county'] ?? ''),
            'country' => (string) ($address['country_id'] ?? $address['country'] ?? $fallback['country_id'] ?? $fallback['country'] ?? ''),
            'telephone' => (string) ($address['telephone'] ?? $fallback['telephone'] ?? ''),
        ];
    }

    private static function firstNonEmptyString(...$values): string
    {
        foreach ($values as $value) {
            if (is_array($value) || is_object($value)) {
                continue;
            }

            $text = trim((string) $value);
            if ($text !== '') {
                return $text;
            }
        }

        return '';
    }

    private static function normalizeLines(array $items): array
    {
        $lines = [];
        foreach ($items as $index => $item) {
            if (!is_array($item)) {
                continue;
            }

            $lines[] = [
                'lineNo' => $index + 1,
                'sku' => (string) ($item['sku'] ?? ''),
                'productName' => (string) ($item['name'] ?? ''),
                'description' => (string) ($item['description'] ?? ''),
                'quantity' => (int) ($item['qty_ordered'] ?? $item['qty'] ?? 0),
                'unitPrice' => (float) ($item['base_price'] ?? $item['price'] ?? 0),
                'lineTotal' => (float) ($item['base_row_total_incl_tax'] ?? $item['row_total_incl_tax'] ?? 0),
                'data' => $item,
            ];
        }

        return $lines;
    }

    private static function normalizeStreet($street): string
    {
        if (is_array($street)) {
            $parts = [];

            array_walk_recursive($street, static function ($value) use (&$parts): void {
                if ($value === null) {
                    return;
                }

                $text = trim((string) $value);
                if ($text !== '') {
                    $parts[] = $text;
                }
            });

            return trim(implode(' ', $parts));
        }

        return trim((string) $street);
    }
}
