<?php

namespace PortalPeople\virtualstock\services;

use PortalPeople\virtualstock\components\VirtualStockClient;
use PortalPeople\virtualstock\models\Product;
use PortalPeople\virtualstock\models\StockLevel;
use yii\base\Component;

/**
 * REST service for VirtualStock product and stock operations.
 */
class ProductService extends Component
{
    public VirtualStockClient $client;

    /**
     * List products, optionally filtered.
     *
     * @param array<string, mixed> $filters  e.g. ['supplier_code' => 'TSL', 'limit' => 50]
     * @return Product[]
     */
    public function listProducts(array $filters = []): array
    {
        $data = $this->client->listProducts($filters);
        $products = [];

        $items = $data['products'] ?? $data['results'] ?? $data;

        if (is_array($items)) {
            foreach ($items as $item) {
                if (is_array($item)) {
                    $products[] = Product::fromArray($item);
                }
            }
        }

        return $products;
    }

    /**
     * Retrieve a single product by its supplier SKU / product number.
     */
    public function getProduct(string $supplierSku): Product
    {
        $data = $this->client->getProduct($supplierSku);
        return Product::fromArray($data);
    }

    /**
     * Retrieve stock level for a product by its supplier SKU / product number.
     */
    public function getStockLevel(string $supplierSku): StockLevel
    {
        $data = $this->client->getProductStock($supplierSku);
        return StockLevel::fromArray($data);
    }

    /**
     * Update stock level for a product on VirtualStock.
     * Accepts either a StockLevel instance or an associative array payload.
     * Returns the updated StockLevel as returned by the API.
     *
     * @param string $supplierSku
     * @param StockLevel|array $stock
     * @return StockLevel
     */
    public function updateStockLevel(string $supplierSku, $stock): StockLevel
    {
        $payload = [];
        if ($stock instanceof StockLevel) {
            $payload = $stock->toArray();
        } elseif (is_array($stock)) {
            $payload = $stock;
        } else {
            throw new \InvalidArgumentException('Stock must be a StockLevel or array.');
        }

        $data = $this->client->updateProductStock($supplierSku, $payload);
        return StockLevel::fromArray($data);
    }

    /**
     * Search products by keyword.
     *
     * @param array<string, mixed> $extra  Additional filter parameters
     * @return Product[]
     */
    public function searchProducts(string $keyword, array $extra = []): array
    {
        return $this->listProducts(array_merge(['search' => $keyword], $extra));
    }

    /**
     * Inspect a raw search response and attempt to extract a REST id for the product.
     * Returns string id or null when not found.
     *
     * @param mixed $searchRes
     * @return string|null
     */
    public function findRestIdFromSearchResponse($searchRes): ?string
    {
        // Normalize string responses
        if (is_string($searchRes) && trim($searchRes) !== '') {
            $decoded = json_decode($searchRes, true);
            if (json_last_error() === JSON_ERROR_NONE) {
                $searchRes = $decoded;
            }
        }

        $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;
            }
        }

        $found = null;
        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];
                }
            }
        }

        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; }
            }
        }

        return $found !== null ? (string)$found : null;
    }
}
