<?php

namespace PortalPeople\magento\controllers;

use yii\data\ArrayDataProvider;
use yii\filters\AccessControl;
use yii\filters\VerbFilter;
use yii\web\BadRequestHttpException;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use Yii;
use PortalPeople\magento\services\MagentoClient;
use PortalPeople\magento\models\Cart;

class DefaultController extends Controller
{
    public function behaviors(): array
    {
        return [
            'access' => [
                'class' => AccessControl::class,
                'rules' => [
                    ['allow' => true, 'roles' => ['@']],
                ],
            ],
            'verbs' => [
                'class' => VerbFilter::class,
                'actions' => [
                    'download-order' => ['GET'],
                    'download-orders' => ['POST'],
                    'import-order' => ['POST'],
                    'import-orders' => ['POST'],
                    'download-payments' => ['POST'],
                    'import-payments' => ['POST'],
                ],
            ],
        ];
    }

    public function actionIndex()
    {
        return $this->renderContent('Magento module is ready.');
    }

    public function actionOrders()
    {
        $module = Yii::$app->getModule('magento');
        if (!$module instanceof \PortalPeople\magento\Module || !$module->isConfigured()) {
            Yii::$app->session->setFlash('error', 'Magento integration is not configured.');

            return $this->render('/orders/index', [
                'dataProvider' => new ArrayDataProvider([
                    'allModels' => [],
                    'pagination' => false,
                ]),
                'totalCount' => 0,
                'paymentCount' => 0,
                'isCached' => false,
            ]);
        }

        $orders = $this->loadOrdersSnapshot($module, Yii::$app->request->get('refresh', '0') === '1');
        $payments = $this->loadPaymentSnapshots($module, $orders);

        $items = $orders['items'] ?? [];

        $dataProvider = new ArrayDataProvider([
            'allModels' => is_array($items) ? $items : [],
            'pagination' => [
                'pageSize' => 25,
            ],
        ]);

        return $this->render('/orders/index', [
            'dataProvider' => $dataProvider,
            'totalCount' => (int) ($orders['total_count'] ?? count($items)),
            'paymentCount' => count($payments),
            'isCached' => Yii::$app->has('cache', true),
        ]);
    }

    public function actionDownloadOrder(int $id)
    {
        $module = $this->getConfiguredModule();
        if ($module === null) {
            return $this->redirect(['orders']);
        }

        $orders = $this->loadOrdersSnapshot($module, false);
        $order = $this->findOrderSnapshot($orders['items'] ?? [], $id);

        if ($order === null) {
            throw new NotFoundHttpException('Magento order not found.');
        }

        $incrementId = (string) ($order['increment_id'] ?? $id);
        $payload = json_encode($order, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);

        if ($payload === false) {
            throw new BadRequestHttpException('Failed to encode Magento order payload.');
        }

        return Yii::$app->response->sendContentAsFile(
            $payload,
            'magento-order-' . $incrementId . '.json',
            ['mimeType' => 'application/json']
        );
    }

    public function actionImportOrder(int $id)
    {
        $module = $this->getConfiguredModule();
        if ($module === null) {
            return $this->redirect(['orders']);
        }

        $orders = $this->loadOrdersSnapshot($module, false);
        $order = $this->findOrderSnapshot($orders['items'] ?? [], $id);

        if ($order === null) {
            throw new NotFoundHttpException('Magento order not found.');
        }

        try {
            Cart::newMagentoOrder($order);
            Yii::$app->session->setFlash(
                'success',
                'Imported Magento order ' . (string) ($order['increment_id'] ?? $id) . '.'
            );
        } catch (\Throwable $e) {
            Yii::$app->session->setFlash(
                'error',
                'Failed to import Magento order ' . (string) ($order['increment_id'] ?? $id) . ': ' . $e->getMessage()
            );
        }

        return $this->redirect(['orders']);
    }

    public function actionDownloadOrders()
    {
        $module = $this->getConfiguredModule();
        if ($module === null) {
            return $this->redirect(['orders']);
        }

        $orders = $this->loadOrdersSnapshot($module, true);
        Yii::$app->session->setFlash('success', 'Downloaded ' . count($orders['items'] ?? []) . ' Magento order(s).');

        return $this->redirect(['orders']);
    }

    public function actionImportOrders()
    {
        $module = $this->getConfiguredModule();
        if ($module === null) {
            return $this->redirect(['orders']);
        }

        $orders = $this->loadOrdersSnapshot($module, false);
        $imported = 0;
        $failed = 0;

        foreach (($orders['items'] ?? []) as $item) {
            if (!is_array($item)) {
                continue;
            }

            try {
                Cart::newMagentoOrder($item);
                $imported++;
            } catch (\Throwable $e) {
                $failed++;
                Yii::error('Magento order import failed: ' . $e->getMessage(), 'magento');
            }
        }

        Yii::$app->session->setFlash('success', 'Imported ' . $imported . ' Magento order(s); failed ' . $failed . '.');

        return $this->redirect(['orders']);
    }

    public function actionDownloadPayments()
    {
        $module = $this->getConfiguredModule();
        if ($module === null) {
            return $this->redirect(['orders']);
        }

        $orders = $this->loadOrdersSnapshot($module, false);
        $payments = $this->extractPaymentSnapshots($orders['items'] ?? []);

        if (Yii::$app->has('cache', true)) {
            Yii::$app->cache->set($this->getPaymentsCacheKey($module), $payments, 300);
        }

        Yii::$app->session->setFlash('success', 'Downloaded ' . count($payments) . ' Magento payment snapshot(s).');

        return $this->redirect(['orders']);
    }

    public function actionImportPayments()
    {
        $module = $this->getConfiguredModule();
        if ($module === null) {
            return $this->redirect(['orders']);
        }

        $payments = $this->loadPaymentSnapshots($module);
        $updated = 0;
        $skipped = 0;

        foreach ($payments as $payment) {
            if (!is_array($payment)) {
                continue;
            }

            try {
                $result = Cart::updateMagentoPayment($payment);
                if (($result['updated'] ?? false) === true) {
                    $updated++;
                } else {
                    $skipped++;
                }
            } catch (\Throwable $e) {
                $skipped++;
                Yii::error('Magento payment import failed: ' . $e->getMessage(), 'magento');
            }
        }

        Yii::$app->session->setFlash(
            'success',
            'Imported ' . $updated . ' Magento payment snapshot(s); skipped ' . $skipped . '.'
        );

        return $this->redirect(['orders']);
    }

    private function getConfiguredModule(): ?\PortalPeople\magento\Module
    {
        $module = Yii::$app->getModule('magento');
        if (!$module instanceof \PortalPeople\magento\Module || !$module->isConfigured()) {
            Yii::$app->session->setFlash('error', 'Magento integration is not configured.');
            return null;
        }

        return $module;
    }

    private function loadOrdersSnapshot(\PortalPeople\magento\Module $module, bool $refresh = false): array
    {
        $cacheKey = $this->getOrdersCacheKey($module);
        $cacheTtl = 300;
        $orders = null;

        if (!$refresh && Yii::$app->has('cache', true)) {
            $orders = Yii::$app->cache->get($cacheKey);
        }

        if (!is_array($orders)) {
            $client = new MagentoClient((string) $module->apiUrl, (string) $module->accessToken);
            $orders = $this->downloadAllOrders($client);

            if (Yii::$app->has('cache', true)) {
                Yii::$app->cache->set($cacheKey, $orders, $cacheTtl);
            }
        }

        return $orders;
    }

    private function loadPaymentSnapshots(\PortalPeople\magento\Module $module, ?array $orders = null): array
    {
        $cacheKey = $this->getPaymentsCacheKey($module);

        if ($orders === null) {
            $orders = $this->loadOrdersSnapshot($module, false);
        }

        $payments = Yii::$app->has('cache', true) ? Yii::$app->cache->get($cacheKey) : null;
        if (!is_array($payments)) {
            $payments = $this->extractPaymentSnapshots($orders['items'] ?? []);

            if (Yii::$app->has('cache', true)) {
                Yii::$app->cache->set($cacheKey, $payments, 300);
            }
        }

        return $payments;
    }

    private function downloadAllOrders(MagentoClient $client): array
    {
        $pageSize = 100;
        $currentPage = 1;
        $allItems = [];
        $totalCount = 0;

        do {
            $response = $client->getOrders([
                'searchCriteria[pageSize]' => $pageSize,
                'searchCriteria[currentPage]' => $currentPage,
            ]);

            $items = $response['items'] ?? [];
            $totalCount = (int) ($response['total_count'] ?? $totalCount);

            if (is_array($items) && $items !== []) {
                $allItems = array_merge($allItems, $items);
            }

            $fetchedCount = is_array($items) ? count($items) : 0;
            $currentPage++;
        } while ($fetchedCount === $pageSize && ($totalCount === 0 || count($allItems) < $totalCount));

        return [
            'items' => $allItems,
            'total_count' => $totalCount > 0 ? $totalCount : count($allItems),
        ];
    }

    private function getOrdersCacheKey(\PortalPeople\magento\Module $module): string
    {
        return 'magento.orders.' . sha1(implode('|', [
            (string) $module->apiUrl,
            (string) $module->accessToken,
            (string) $module->storeCode,
        ]));
    }

    private function getPaymentsCacheKey(\PortalPeople\magento\Module $module): string
    {
        return 'magento.payments.' . sha1(implode('|', [
            (string) $module->apiUrl,
            (string) $module->accessToken,
            (string) $module->storeCode,
        ]));
    }

    private function extractPaymentSnapshots(array $orders): array
    {
        $payments = [];

        foreach ($orders as $order) {
            if (!is_array($order)) {
                continue;
            }

            $payment = $order['payment'] ?? [];
            $payments[] = [
                'orderId' => $order['entity_id'] ?? null,
                'orderNo' => $order['increment_id'] ?? null,
                'status' => $order['status'] ?? null,
                'createdAt' => $order['created_at'] ?? null,
                'method' => is_array($payment) ? ($payment['method'] ?? '') : '',
                'amount' => $order['base_grand_total'] ?? $order['grand_total'] ?? null,
                'currency' => $order['base_currency_code'] ?? $order['order_currency_code'] ?? null,
                'customerEmail' => $order['customer_email'] ?? null,
                'raw' => $payment,
            ];
        }

        return $payments;
    }

    private function findOrderSnapshot(array $orders, int $id): ?array
    {
        foreach ($orders as $order) {
            if (!is_array($order)) {
                continue;
            }

            if ((int) ($order['entity_id'] ?? 0) === $id) {
                return $order;
            }
        }

        return null;
    }
}
