<?php 

namespace PortalPeople\virtualstock\controllers;
use Yii;
use yii\helpers\Json;

class VirtualstockController extends \yii\web\Controller
{
    public function actionOrders()
    {
        $searchModel = new \backend\models\Cartsbesearch();
        $searchModel->account_code = 'SCR001';
        $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
        return $this->render('@backend/views/cart/index', [
            'searchModel' => $searchModel,
            'dataProvider' => $dataProvider,
        ]);
    }

    /**
     * GET: Fetch pending orders from the VirtualStock API and show a preview.
     * Stores the cursor used in session so the approve step re-imports the same batch.
     */
    public function actionOrderImport()
    {
        $module = $this->getConfiguredModule();
        if ($module === null) {
            Yii::$app->session->setFlash('error', 'VirtualStock is not configured. Save valid API settings first.');
            return $this->redirect(['/virtualstock/virtualstock/orders']);
        }

        $limit = (int) Yii::$app->request->get('limit', $module->pollLimit);

        $previewData = null;
        $error       = null;

        try {
            $service     = $module->createOrderImportService();
            $previewData = $service->fetchForPreview(null, $limit);
            Yii::$app->session->set('vs_preview_cursor', $previewData['cursor']);
            Yii::$app->session->set('vs_preview_limit', $limit);
        } catch (\Throwable $e) {
            Yii::error('VirtualStock order preview error: ' . $e->getMessage(), 'virtualstock');
            $error = 'Could not fetch orders: ' . $e->getMessage();
        }

        return $this->render('@vendor/portalpeople/ngauge-virtualstock/src/views/config/order-import', [
            'previewData'  => $previewData,
            'error'        => $error,
            'importResult' => Yii::$app->session->getFlash('vs-import-result'),
            'limit'        => $limit,
            'pollLimit'    => $module->pollLimit,
        ]);
    }

    /**
     * POST: Run the actual import for the previewed batch.
     */
    public function actionApproveOrderImport(): \yii\web\Response
    {
        $module = $this->getConfiguredModule();
        if ($module === null) {
            Yii::$app->session->setFlash('vs-import-result', [
                'success' => false,
                'message' => 'VirtualStock is not configured.',
            ]);
            return $this->redirect(['/virtualstock/virtualstock/order-import']);
        }

        $cursor = Yii::$app->session->get('vs_preview_cursor');
        $limit  = (int) Yii::$app->session->get('vs_preview_limit', $module->pollLimit);

        $rawMap     = Yii::$app->request->post('product_map', []);
        $productMap = [];
        if (is_array($rawMap)) {
            foreach ($rawMap as $orderNo => $lineMap) {
                if (!is_array($lineMap)) {
                    continue;
                }
                $orderNo = (string) $orderNo;
                $productMap[$orderNo] = [];
                foreach ($lineMap as $lineNo => $productId) {
                    $productId = trim((string) $productId);
                    if ($productId !== '') {
                        $productMap[$orderNo][(int) $lineNo] = $productId;
                    }
                }
            }
        }

        try {
            $service = $module->createOrderImportService();
            $stats   = $service->run($cursor, $limit, false, $productMap);

            Yii::$app->session->remove('vs_preview_cursor');
            Yii::$app->session->remove('vs_preview_limit');

            Yii::$app->session->setFlash('vs-import-result', [
                'success' => true,
                'message' => "{$stats['created']} order(s) created, {$stats['updated']} updated, {$stats['failed']} failed.",
                'stats'   => $stats,
            ]);
        } catch (\Throwable $e) {
            Yii::error('VirtualStock approve import error: ' . $e->getMessage(), 'virtualstock');
            Yii::$app->session->setFlash('vs-import-result', [
                'success' => false,
                'message' => 'Import failed: ' . $e->getMessage(),
            ]);
        }

        return $this->redirect(['/virtualstock/virtualstock/order-import']);
    }
    
    public function actionProducts()
    {
        $searchModel = new \backend\models\Productsbesearch();
        $searchModel->virtualstock_enabled = true;
        $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
        return $this->render('@backend/views/products/index', [
            'searchModel' => $searchModel,
            'dataProvider' => $dataProvider,
        ]);
    }

    public function actionRefresh()
    {
        Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;

        $id = Yii::$app->request->post('id') ?? Yii::$app->request->get('id');
        if (empty($id)) {
            return ['success' => false, 'error' => 'Missing cart id'];
        }

        $cart = \PortalPeople\virtualstock\models\Cart::findOne($id);
        if ($cart === null) {
            return ['success' => false, 'error' => 'Cart not found'];
        }

        $module = Yii::$app->getModule('virtualstock');
        if (!($module instanceof \PortalPeople\virtualstock\Module) || !$module->isConfigured()) {
            return ['success' => false, 'error' => 'VirtualStock module not configured'];
        }
        $imported = json_decode($cart->imported_data ?? '{}', true) ?: [];
        $orderNo = $imported['url'] ?? null;
        yii::warning($orderNo, 'virtualstock');
        if (empty($orderNo)) {
            return ['success' => false, 'error' => 'No VirtualStock order identifier on cart'];
        }

        try {
            $client = $module->createClient();
            $data = $client->getOrder($orderNo);
            \PortalPeople\virtualstock\models\Cart::applyVirtualStockOrderData($cart, $data, $orderNo, $module);
            if (!$cart->save(false)) {
                return ['success' => false, 'error' => 'Failed to save cart: ' . json_encode($cart->errors)];
            }
            return ['success' => true];
        } catch (\Throwable $t) {
            Yii::error('VirtualStock refresh failed: ' . $t->getMessage(), 'virtualstock');
            return ['success' => false, 'error' => 'API error: ' . $t->getMessage()];
        }
    }

    /**
     * Generic update endpoint to push changes back to VirtualStock API.
     * Accepts POST with `id` (cart id) and `payload` (associative array) or `status`.
     */
    public function actionUpdate()
    {
        Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;

        $id = Yii::$app->request->post('id') ?? Yii::$app->request->get('id');
        $status = Yii::$app->request->post('status');
        $payload = Yii::$app->request->post('payload');

        // Accept payload as JSON string or associative array. Normalize to array.
        // Delegate payload normalization/validation to OrderService
        try {
            $orderService = Yii::createObject(\PortalPeople\virtualstock\services\OrderService::class);
            $payloadData = $orderService->prepareUpdatePayload($payload);
        } catch (\InvalidArgumentException $e) {
            return ['success' => false, 'error' => $e->getMessage()];
        }

        if (empty($id)) {
            return ['success' => false, 'error' => 'Missing cart id'];
        }

        $cart = \PortalPeople\virtualstock\models\Cart::findOne($id);
        if ($cart === null) {
            return ['success' => false, 'error' => 'Cart not found'];
        }

        $module = Yii::$app->getModule('virtualstock');
        if (!($module instanceof \PortalPeople\virtualstock\Module) || !$module->isConfigured()) {
            return ['success' => false, 'error' => 'VirtualStock module not configured'];
        }

        $orderNo = $cart->ordernumber ?? null;
        if (empty($orderNo)) {
            return ['success' => false, 'error' => 'No VirtualStock order identifier on cart'];
        }

        try {
            $vsService = Yii::createObject(\PortalPeople\virtualstock\services\VirtualStockService::class);
            $vsService->client = $module->createClient();
            $vsService->orderService = Yii::createObject(\PortalPeople\virtualstock\services\OrderService::class);
            $vsService->productService = Yii::createObject(\PortalPeople\virtualstock\services\ProductService::class);

            $resp = $vsService->updateOrderFromCart($cart, $payload, $status);
            return ['success' => true, 'response' => $resp];
        } catch (\InvalidArgumentException $e) {
            return ['success' => false, 'error' => $e->getMessage()];
        } catch (\Throwable $t) {
            Yii::error('VirtualStock update failed: ' . $t->getMessage(), 'virtualstock');
            \PortalPeople\virtualstock\models\Cart::appendVirtualStockApiResponse($cart, ['error' => $t->getMessage()]);
            return ['success' => false, 'error' => 'API error: ' . $t->getMessage()];
        }
    }

    /**
     * Acknowledge the order resource on VirtualStock.
     * POST /virtualstock/virtualstock/acknowledge with `id` (cart id).
     */
    public function actionAcknowledge()
    {
        Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
        // Accept either a posted `order` (order URL or id) or a cart `id` to look up the stored order.
        $orderParam = Yii::$app->request->post('order') ?? Yii::$app->request->get('order');
        $id = Yii::$app->request->post('id') ?? Yii::$app->request->get('id');

        $module = Yii::$app->getModule('virtualstock');
        if (!($module instanceof \PortalPeople\virtualstock\Module) || !$module->isConfigured()) {
            return ['success' => false, 'error' => 'VirtualStock module not configured'];
        }

        $orderNo = null;

        $cart = \PortalPeople\virtualstock\models\Cart::findOne($id);
        try {
            $vsService = Yii::createObject(\PortalPeople\virtualstock\services\VirtualStockService::class);
            $vsService->client = $module->createClient();
            $vsService->orderService = Yii::createObject(\PortalPeople\virtualstock\services\OrderService::class);
            $resp = $vsService->acknowledgeOrderFromCart($cart);
            return ['success' => true, 'response' => $resp];
        } catch (\Throwable $t) {
            Yii::error('VirtualStock acknowledge failed: ' . $t->getMessage(), 'virtualstock');
            if (!empty($id) && isset($cart) && $cart !== null) {
                \PortalPeople\virtualstock\models\Cart::appendVirtualStockApiResponse($cart, ['error' => $t->getMessage()]);
            }
            return ['success' => false, 'error' => 'API error: ' . $t->getMessage()];
        }
    }
    /**
     * Acknowledge the order resource on VirtualStock.
     * POST /virtualstock/virtualstock/acknowledge with `id` (cart id).
     */
    public function actionDispatch()
    {
        Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
        // Accept either a posted `order` (order URL or id) or a cart `id` to look up the stored order.
        $orderParam = Yii::$app->request->post('order') ?? Yii::$app->request->get('order');
        $id = Yii::$app->request->post('id') ?? Yii::$app->request->get('id');

        $module = Yii::$app->getModule('virtualstock');
        if (!($module instanceof \PortalPeople\virtualstock\Module) || !$module->isConfigured()) {
            return ['success' => false, 'error' => 'VirtualStock module not configured'];
        }

        $orderNo = null;

        $cart = \PortalPeople\virtualstock\models\Cart::findOne($id);
        try {
            $vsService = Yii::createObject(\PortalPeople\virtualstock\services\VirtualStockService::class);
            $vsService->client = $module->createClient();
            $vsService->orderService = Yii::createObject(\PortalPeople\virtualstock\services\OrderService::class);
            $resp = $vsService->dispatchOrderFromCart($cart);
            return ['success' => true, 'response' => $resp];
        } catch (\Throwable $t) {
            if (!empty($id) && isset($cart) && $cart !== null) {
                \PortalPeople\virtualstock\models\Cart::appendVirtualStockApiResponse($cart, ['error' => $t->getMessage()]);
            }
            return ['success' => false, 'error' => 'API error: ' . $t->getMessage()];
        }
    }

    /**
     * POST: Update product stock on VirtualStock API.
     * Expects JSON body: { sku: string, quantity: int }
     */
    public function actionUpdateProductStock()
    {
        Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;

        $module = Yii::$app->getModule('virtualstock');
        if (!($module instanceof \PortalPeople\virtualstock\Module) || !$module->isConfigured()) {
            return ['success' => false, 'error' => 'VirtualStock module not configured'];
        }

        $body = Yii::$app->request->getBodyParams();
        $raw = (string) Yii::$app->request->getRawBody();
        if (empty($body)) {
            if ($raw !== '') {
                $decoded = json_decode($raw, true);
                if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
                    $body = $decoded;
                    }
                    }
                    }
                    $raw = (string) Yii::$app->request->getRawBody();
        yii::warning($raw, 'virtualstock');
        $sku = trim((string) ($body['sku'] ?? ''));
        $qty = isset($body['quantity']) ? (int)$body['quantity'] : null;

        if ($sku === '' || $qty === null) {
            return ['success' => false, 'error' => 'sku and quantity are required'];
        }

        try {
            $service = $module->createProductService();
            $stockLevel = $service->updateStockLevel($sku, ['on_hand' => $qty]);
            return ['success' => true, 'stock' => $stockLevel->toArray()];
        } catch (\Throwable $t) {
            Yii::error('VirtualStock update product stock failed: ' . $t->getMessage(), 'virtualstock');
            return ['success' => false, 'error' => $t->getMessage()];
        }
    }

    /**
     * GET: Fetch product stock info from VirtualStock by supplier SKU.
     * Returns JSON suitable for rendering into a card.
     */
    public function actionGetProductStock()
    {
        Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
        $sku = trim((string) (Yii::$app->request->get('part_number') ?? Yii::$app->request->post('part_number') ?? ''));

        if ($sku === '') {
            return ['success' => false, 'error' => 'Missing sku'];
        }

        $module = Yii::$app->getModule('virtualstock');
        if (!($module instanceof \PortalPeople\virtualstock\Module) || !$module->isConfigured()) {
            return ['success' => false, 'error' => 'VirtualStock module not configured'];
        }

        try {
            $client = $module->createClient();
            // Try path-based stock endpoint first
            try {
                $data = $client->getProductStock($sku);
                Yii::warning($data, 'virtualstock');
                if (!empty($data)) {
                    return ['success' => true, 'data' => $data];
                }
            } catch (\Throwable $_) {
                Yii::warning('VirtualStock path-based stock endpoint failed, falling back to products API', 'virtualstock');
                // ignore and try products API base
            }

            // Fallback: if module provides a separate productsApiEndpoint, call
            // the search endpoint using the exact URL required by some providers.
            $productsBase = trim((string) ($module->productsApiEndpoint ?? ''));
            if ($productsBase !== '') {
                $productsBase = rtrim($productsBase, '/');
                $url = $productsBase . '/products/?part_number=' . rawurlencode($sku);
                try {
                    $res = $client->request('GET', $url);
                    
                    return ['success' => true, 'data' => $res];
                } catch (\Throwable $t) {
                    Yii::error('VirtualStock product search failed: ' . $t->getMessage(), 'virtualstock');
                    return ['success' => false, 'error' => $t->getMessage()];
                }
            }

            return ['success' => false, 'error' => 'No product data found'];
        } catch (\Throwable $t) {
            Yii::error('VirtualStock get product stock failed: ' . $t->getMessage(), 'virtualstock');
            return ['success' => false, 'error' => $t->getMessage()];
        }
    }

    /**
     * PATCH: Update product data on the external products API by REST ID.
     * Expects POST body: { rest_id: string, data: { free_stock: int, backorder_date?: string } }
     */
    public function actionPatchProduct()
    {
        Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;

        $module = Yii::$app->getModule('virtualstock');
        if (!($module instanceof \PortalPeople\virtualstock\Module) || !$module->isConfigured()) {
            return ['success' => false, 'error' => 'VirtualStock module not configured'];
        }

        $body = json_decode(Yii::$app->request->getRawBody(), true);

        $restId = trim((string) ($body['rest_id'] ?? ''));
        $partNumber = trim((string) ($body['part_number'] ?? ''));
        $data = $body['data'] ?? [];
        Yii::warning($body, 'virtualstock');

        if (!is_array($data) || !isset($data['free_stock'])) {
            return ['success' => false, 'error' => 'data.free_stock is required'];
        }

        $productsBase = trim((string) ($module->productsApiEndpoint ?? ''));
        if ($productsBase === '') {
            return ['success' => false, 'error' => 'productsApiEndpoint is not configured'];
        }

        $productsBase = rtrim($productsBase, '/');
        // If restId is not provided, allow using part_number to discover the product REST id
        if ($restId === '' && $partNumber !== '') {
            try {
                $client = $module->createClient();
                $searchUrl = $productsBase . '/products/?part_number=' . rawurlencode($partNumber);
                $searchRes = $client->request('GET', $searchUrl);
                Yii::warning(['searchRes' => $searchRes], 'virtualstock');
                $found = null;

                // Normalize string responses
                if (is_string($searchRes) && trim($searchRes) !== '') {
                    $decoded = json_decode($searchRes, true);
                    if (json_last_error() === JSON_ERROR_NONE) {
                        $searchRes = $decoded;
                    }
                }

                // searchRes may be an envelope or a list; check common container keys
                $candidates = [];
                if (is_array($searchRes)) {
                    if (isset($searchRes['results']) && is_array($searchRes['results'])) {
                        $candidates = $searchRes['results'];
                    } elseif (isset($searchRes['data']) && is_array($searchRes['data'])) {
                        $candidates = $searchRes['data'];
                    } elseif (isset($searchRes['products']) && is_array($searchRes['products'])) {
                        $candidates = $searchRes['products'];
                    } elseif (array_is_list($searchRes)) {
                        $candidates = $searchRes;
                    }
                }

                // Inspect first candidate for identifiable id fields or URL
                if (count($candidates) > 0) {
                    $first = $candidates[0];
                    if (is_array($first)) {
                        foreach (['id','rest_id','pk','product_id'] as $k) {
                            if (!empty($first[$k])) { $found = (string)$first[$k]; break; }
                        }
                        if ($found === null && !empty($first['url']) && preg_match('#/products/(\d+)/?#', $first['url'], $m)) {
                            $found = $m[1];
                        }
                    }
                }

                // As a last resort, do a recursive scan for the first numeric id or product URL
                if ($found === null && is_array($searchRes)) {
                    $iterator = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($searchRes));
                    foreach ($iterator as $value) {
                        if (is_string($value) && preg_match('#/products/(\d+)/?#', $value, $m)) { $found = $m[1]; break; }
                        if ((is_int($value) || (is_string($value) && ctype_digit($value))) && (int)$value > 0) { $found = (string)$value; break; }
                    }
                }
                if ($found !== null) {
                    $restId = $found;
                }
            } catch (\Throwable $t) {
                Yii::warning('Products lookup failed: ' . $t->getMessage(), 'virtualstock');
            }
        }

        $url = $productsBase . '/products/' . rawurlencode($restId) . '/?format=json';

        try {
            $client = $module->createClient();
            $resp = $client->request('PATCH', $url, ['data' => $data]);
            return ['success' => true, 'response' => $resp];
        } catch (\Throwable $t) {
            Yii::error('VirtualStock patch product failed: ' . $t->getMessage(), 'virtualstock');
            return ['success' => false, 'error' => $t->getMessage()];
        }
    }

    /**
     * Return the configured VirtualStock module, or null if unavailable.
     *
     * @return \PortalPeople\virtualstock\Module|null
     */
    private function getConfiguredModule(): ?\PortalPeople\virtualstock\Module
    {
        /** @var \PortalPeople\virtualstock\Module|null $module */
        $module = Yii::$app->getModule('virtualstock');
        if (!$module || !$module->isConfigured()) {
            return null;
        }
        return $module;
    }
}