<?php

namespace PortalPeople\magento\models;

use Yii;
use backend\models\Cartsbe;
use PortalPeople\magento\components\FieldMapper;
use PortalPeople\magento\Module;

class Cart extends Cartsbe
{
    public static function newMagentoOrder(array $rawOrder): array
    {
        $module = Yii::$app->getModule('magento');
        if (!$module instanceof Module || !$module->isConfigured()) {
            throw new \RuntimeException('Magento module is not configured.');
        }

        $normalized = FieldMapper::normalizeOrder($rawOrder);
        return self::upsertFromMagento($normalized, $module);
    }

    public static function upsertFromMagento(array $order, Module $module): array
    {
        $orderNo = (string) ($order['orderNo'] ?? '');
        if ($orderNo === '') {
            throw new \InvalidArgumentException('Magento order payload is missing an order number.');
        }

        return Yii::$app->db->transaction(function () use ($order, $orderNo, $module) {
            $cart = self::findExistingCart($orderNo);
            if ($cart === null) {
                $cart = new self();
                $cart->id = $cart::tempId();
                $cart->status = 'Paid';
            }

            $cart->ordernumber = $cart->ordernumber ?: $orderNo;
            $cart->porderref = $cart->porderref ?: $orderNo;
            $cart->email = $cart->email ?: ($order['customerEmail'] ?? '');
            $cart->contact = $cart->contact ?: ($order['customerName'] ?? '');
            $cart->telephone = $cart->telephone ?: ($order['telephone'] ?? '');
            $cart->sourceurl = 'magento';
            $cart->dateordered = $cart->dateordered ?: strtotime((string) ($order['orderDate'] ?? 'now'));
            $delivery = $order['deliveryAddress'] ?? [];
            $cart->fulladdress = trim((string) (
                ($delivery['line1'] ?? '') . ' ' .
                ($delivery['city'] ?? '') . ' ' .
                ($delivery['postcode'] ?? '')
            ));
            $cart->fulladdresses = [
                'billing' => $order['billingAddress'] ?? [],
                'shipping' => $order['deliveryAddress'] ?? [],
            ];
            $cart->data = json_encode(array_merge(is_array($cart->data) ? $cart->data : [], [
                'magento' => [
                    'order_id' => $order['orderId'] ?? null,
                    'order_no' => $orderNo,
                    'status' => $order['status'] ?? null,
                    'payment_method' => $order['paymentMethod'] ?? null,
                    'raw' => $order['_raw'] ?? null,
                ],
            ]), JSON_UNESCAPED_SLASHES);

            if (!$cart->save()) {
                throw new \RuntimeException('Failed to save Magento cart: ' . json_encode($cart->errors));
            }

            self::upsertMagentoLines($cart, $order['orderLines'] ?? []);

            return [
                'created' => $cart->getIsNewRecord(),
                'orderNo' => $orderNo,
                'cartId' => $cart->id,
            ];
        });
    }

    public static function updateMagentoPayment(array $payment): array
    {
        $orderNo = (string) ($payment['orderNo'] ?? '');
        if ($orderNo === '') {
            throw new \InvalidArgumentException('Magento payment snapshot is missing an order number.');
        }

        return Yii::$app->db->transaction(function () use ($payment, $orderNo) {
            $cart = self::findExistingCart($orderNo);
            if ($cart === null) {
                return [
                    'updated' => false,
                    'reason' => 'cart-not-found',
                    'orderNo' => $orderNo,
                ];
            }

            $data = is_array($cart->data) ? $cart->data : [];
            $magento = $data['magento'] ?? [];
            $magento['order_no'] = $magento['order_no'] ?? $orderNo;
            $magento['payment_method'] = (string) ($payment['method'] ?? ($magento['payment_method'] ?? ''));
            $magento['payment'] = [
                'order_id' => $payment['orderId'] ?? null,
                'order_no' => $orderNo,
                'status' => $payment['status'] ?? null,
                'created_at' => $payment['createdAt'] ?? null,
                'method' => $payment['method'] ?? null,
                'amount' => $payment['amount'] ?? null,
                'currency' => $payment['currency'] ?? null,
                'customer_email' => $payment['customerEmail'] ?? null,
                'raw' => $payment['raw'] ?? null,
            ];
            $data['magento'] = $magento;
            $cart->data = $data;

            if (!$cart->save()) {
                throw new \RuntimeException('Failed to save Magento payment data: ' . json_encode($cart->errors));
            }

            return [
                'updated' => true,
                'orderNo' => $orderNo,
                'cartId' => $cart->id,
            ];
        });
    }

    private static function findExistingCart(string $orderNo)
    {
        $json = new \yii\db\Expression("json_value(`data`, '$.magento.order_no')");
        return self::find()->where(['=', $json, $orderNo])->one();
    }

    private static function upsertMagentoLines($cart, array $lines): void
    {
        $lineClass = '\backend\models\Cartlines';
        $seen = [];

        foreach ($lines as $index => $line) {
            if (!is_array($line)) {
                continue;
            }

            $sequence = (int) ($line['lineNo'] ?? $index + 1);
            $seen[] = $sequence;
            $model = $lineClass::find()->where(['basketid' => $cart->id, 'sequence' => $sequence])->one();

            if ($model === null) {
                $model = new $lineClass(['basketid' => $cart->id, 'sequence' => $sequence]);
            }

            $model->qty = (int) ($line['quantity'] ?? 0);
            $model->price = (float) ($line['unitPrice'] ?? 0);
            $model->product_name = (string) ($line['productName'] ?? '');
            $model->product_description = (string) ($line['description'] ?? '');
            $model->status = 'Active';
            $model->requested_date = date('Y-m-d');

            if (!$model->save()) {
                throw new \RuntimeException('Failed to save Magento cart line: ' . json_encode($model->errors));
            }
        }

        $lineClass::updateAll(['status' => 'Deleted'], ['basketid' => $cart->id, 'and', ['not in', 'sequence', $seen]]);
    }
}
