<?php

namespace PortalPeople\zupa\services;

use Yii;
use yii\base\BaseObject;
use backend\models\Cartsbe;
use backend\models\Cartlines;
use backend\models\Paymentresponsesbe;
use backend\models\Shipment;
use PortalPeople\zupa\Module;
use PortalPeople\zupa\models\Cart;

class ProcessFilesService extends BaseObject
{
    public string $inboxPath = '';
    public string $processedPath = '';
    public string $failedPath = '';
    public ?Module $module = null;

    public function process(): array
    {
        $result = [
            'success' => false,
            'processed' => 0,
            'created' => 0,
            'failed' => 0,
            'errors' => [],
        ];

        if (!is_dir($this->inboxPath)) {
            return $result;
        }

        $files = glob($this->inboxPath . '/*.xml');
        if (!is_array($files)) {
            $files = [];
        }

        foreach ($files as $filePath) {
            $filename = basename($filePath);

            try {
                $content = file_get_contents($filePath);
                if ($content === false) {
                    throw new \RuntimeException("Cannot read file: {$filename}");
                }

                $orders = $this->parseXml($content);
                $imported = 0;

                foreach ($orders as $orderData) {
                    if ($this->importOrder($orderData)) {
                        $imported++;
                    }
                }

                $result['created'] += $imported;
                $result['processed']++;

                $this->moveToProcessed($filePath);
            } catch (\Throwable $e) {
                Yii::error(
                    "Failed to process {$filename}: " . $e->getMessage(),
                    'zupa.process'
                );
                $result['errors'][] = [
                    'file' => $filename,
                    'error' => $e->getMessage(),
                ];
                $result['failed']++;

                $this->moveToFailed($filePath);
            }
        }

        $result['success'] = $result['failed'] === 0;
        $this->sendSummaryEmail($result);

        return $result;
    }

    /**
     * @throws \RuntimeException
     */
    private function parseXml(string $content): array
    {
        libxml_use_internal_errors(true);
        $xml = @simplexml_load_string($content);
        libxml_use_internal_errors(false);

        if (!$xml) {
            throw new \RuntimeException('Invalid XML format');
        }

        $orders = [];

        foreach ($xml->children() as $orderNode) {
            $order = [];
            $order['ordernumber'] = (string) ($orderNode->order_number ?? $orderNode->ordernumber ?? $orderNode->ref ?? '');
            $order['name'] = (string) ($orderNode->customer_name ?? $orderNode->name ?? '');
            $order['email'] = (string) ($orderNode->customer_email ?? $orderNode->email ?? '');
            $order['contact'] = (string) ($orderNode->contact ?? $order['name']);
            $order['deliveryaddress'] = (string) ($orderNode->delivery_address ?? $orderNode->address ?? '');
            $order['postcode'] = (string) ($orderNode->postcode ?? $orderNode->zip ?? '');
            $order['telephone'] = (string) ($orderNode->telephone ?? $orderNode->phone ?? '');
            $order['account_code'] = (string) ($orderNode->account ?? $this->module?->defaultAccountCode ?? 'ZUPA001');
            $order['status'] = 'Paid';
            $order['paymentmethod'] = 'Zupa';
            $order['shippingmethod'] = (string) ($orderNode->shipping_method ?? 'Standard');
            $order['message'] = (string) ($orderNode->notes ?? '');

            $lines = [];
            if (isset($orderNode->items) || isset($orderNode->lines)) {
                $itemNode = $orderNode->items ?? $orderNode->lines;
                foreach ($itemNode->children() as $item) {
                    $lines[] = [
                        'description' => (string) ($item->description ?? $item->product_name ?? 'Item'),
                        'qty' => (int) ($item->quantity ?? $item->qty ?? 1),
                        'price' => (float) ($item->price ?? $item->unit_price ?? 0),
                    ];
                }
            }
            $order['lines'] = $lines;

            if (!empty($order['ordernumber'])) {
                $orders[] = $order;
            }
        }

        return $orders;
    }

    private function importOrder(array $orderData): bool
    {
        try {
            $cart = new Cart();
            $cart->id = $cart::tempId() ?? Yii::$app->security->generateRandomString(16);
            $cart->ordernumber = $orderData['ordernumber'];
            $cart->name = $orderData['name'];
            $cart->email = $orderData['email'];
            $cart->contact = $orderData['contact'];
            $cart->deliveryaddress = $orderData['deliveryaddress'];
            $cart->postcode = $orderData['postcode'];
            $cart->telephone = $orderData['telephone'];
            $cart->account_code = $orderData['account_code'];
            $cart->status = $orderData['status'];
            $cart->paymentmethod = $orderData['paymentmethod'];
            $cart->shippingmethod = $orderData['shippingmethod'];
            $cart->message = $orderData['message'];
            $cart->sourceurl = 'zupa';
            $cart->dateordered = time();
            $cart->nooflines = count($orderData['lines']);

            if (!$cart->save()) {
                Yii::warning(
                    'Cart save failed: ' . implode('; ', array_map(
                        fn ($msgs) => implode(', ', (array) $msgs),
                        $cart->getErrors()
                    )),
                    'zupa.import'
                );

                return false;
            }

            $lineTotal = 0;
            foreach ($orderData['lines'] as $lineData) {
                $line = new Cartlines();
                $line->basketid = $cart->id;
                $line->product_description = $lineData['description'];
                $line->qty = (int) $lineData['qty'];
                $line->price = (float) $lineData['price'];
                $line->linetotal = $line->qty * $line->price;
                $lineTotal += $line->linetotal;

                if (!$line->save()) {
                    Yii::warning(
                        "Cartline save failed for cart {$cart->id}: " . implode('; ', array_map(
                            fn ($msgs) => implode(', ', (array) $msgs),
                            $line->getErrors()
                        )),
                        'zupa.import'
                    );
                }
            }

            $payment = new Paymentresponsesbe();
            $payment->basketid = $cart->id;
            $payment->source = 'zupa';
            $payment->camount = $lineTotal;
            $payment->amount = $lineTotal;
            $payment->status = 'Paid';
            $payment->paymentmethod = $orderData['paymentmethod'];
            $payment->save();

            $shipment = new Shipment();
            $shipment->cart_id = $cart->id;
            $shipment->shipment_type = 0;
            $shipment->delivery = $orderData['shippingmethod'];
            $shipment->shipment_date = date('Y-m-d');
            $shipment->save();

            Yii::info("Order imported from Zupa: {$cart->id}", 'zupa.import');

            return true;
        } catch (\Throwable $e) {
            Yii::error(
                'Order import exception: ' . $e->getMessage() . ' | Data: ' . json_encode($orderData),
                'zupa.import'
            );

            return false;
        }
    }

    private function moveToProcessed(string $filePath): void
    {
        $filename = basename($filePath);
        $dest = $this->processedPath . DIRECTORY_SEPARATOR . $filename;

        if (!is_dir($this->processedPath)) {
            @mkdir($this->processedPath, 0755, true);
        }

        @rename($filePath, $dest);
    }

    private function moveToFailed(string $filePath): void
    {
        $filename = basename($filePath);
        $dest = $this->failedPath . DIRECTORY_SEPARATOR . $filename;

        if (!is_dir($this->failedPath)) {
            @mkdir($this->failedPath, 0755, true);
        }

        @rename($filePath, $dest);
    }

    private function sendSummaryEmail(array $result): void
    {
        if (!$this->module || !$this->module->summaryEmail) {
            return;
        }

        try {
            $body = "Zupa Import Run Summary\n";
            $body .= str_repeat('=', 40) . "\n\n";
            $body .= "Processed files: {$result['processed']}\n";
            $body .= "Orders created: {$result['created']}\n";
            $body .= "Failed: {$result['failed']}\n\n";

            if (!empty($result['errors'])) {
                $body .= "Errors:\n";
                foreach ($result['errors'] as $err) {
                    $body .= "  - {$err['file']}: {$err['error']}\n";
                }
            }

            $body .= "\nRun at: " . date('Y-m-d H:i:s') . "\n";

            Yii::$app->mailer
                ->compose()
                ->setTo($this->module->summaryEmail)
                ->setFrom(['noreply@example.com' => 'Zupa Import'])
                ->setSubject("[Zupa] Import Summary - " . date('Y-m-d H:i'))
                ->setTextBody($body)
                ->send();
        } catch (\Throwable $e) {
            Yii::error('Failed to send Zupa summary email: ' . $e->getMessage(), 'zupa');
        }
    }
}
