<?php

/**
 * This is a common store component which will be used across all Module-store-controllers
 */

namespace ComponentStoreSpace\Controllers;

use App\Components\Controllers\Component;
use App\Modules\Products\Models\ProductOptions;
use App\Modules\Products\Models\ProductOptionRel;
use App\Modules\Products\Models\ProductVariants;
use App\Modules\Products\Models\ProductVariantRel;
use App\Modules\Products\Models\ProductImage;
use App\Modules\Products\Models\ProductImageSides;
use App\Modules\Products\Models\ProductSetting;
use App\Modules\Products\Models\CatalogProductRel;

class StoreComponent extends Component
{
    public $shopDomain;
    private $token;
    private $apiKey;
    private $secret;
    private $apiVersion;
    private $lastResponseHeaders = null;
    public $thumbSize = "small";
    public $fullSize = "";
    public $colorAttrName = "color";
    public $sizeAttrName = "size";

    function __construct()
    {
        if (!isset($_SESSION)) {
            session_start();
        }
        parent::__construct();
        $this->name = "ShopifyClient";
        $this->shopDomain = SHOPIFY_SHOP . '.myshopify.com';
        $this->token = APIPASS;
        $this->apiKey = APIUSER;
        $this->secret = SECRETKEY;

        $settingDIR = ASSETS_PATH_W . 'settings/stores/1/settings.json';
        $getSettingDetails = file_get_contents($settingDIR);
        $getSettingDetails = json_decode($getSettingDetails, true);

        if (!empty($getSettingDetails['store']['color'])) {
            $this->colorAttrName = strtolower($getSettingDetails['store']['color']);
        }

        if (!empty($getSettingDetails['store']['size'])) {
            $this->sizeAttrName = strtolower($getSettingDetails['store']['size']);
        }

        $versionDir = str_replace('assets/', 'shopify/data/api_version.json', ASSETS_PATH_W);
        if (!file_exists($versionDir)) {
            $this->getLatestApiVersion();
            $installedVersion = json_decode(file_get_contents($versionDir), true);
            $this->apiVersion = $installedVersion[0]['api_version'];
        } else {
            $installedVersion = json_decode(file_get_contents($versionDir), true);
        }

        $this->apiVersion = empty($installedVersion[0]['api_version']) ? "2024-07" : $installedVersion[0]['api_version'];
    }

    /**
     * Get: get Shopify authorization URL
     *
     * @param $scope  Shopify inut parameter
     * @param $redirectURL Shopify returned URL incase of error
     *
     * @author debashisd@riaxe.com
     * @date   02 March 2020
     * @return Shopify rest autorised URL
     */
    public function getAuthorizeUrl($scope, $redirectURL = '')
    {
        $url = "http://{$this->shopDomain}/admin/oauth/authorize?client_id={$this->apiKey}&scope=" . urlencode($scope);
        if ($redirectURL != '') {
            $url .= "&redirect_uri=" . urlencode($redirectURL);
        }
        return $url;
    }

    /**
     * Get: get latest version of api and save it to the config.xml file
     *
     * @author divya@imprintnext.com
     * @date   30 January 2023
     * @return Shopify API version
     */
    public function getLatestApiVersion()
    {

        $currentMonth = date("m");
        $monthDiff = $this->getVersionDifference();
        $previousYear =  date("Y", strtotime("-1 year"));
        if ($monthDiff > 6) {
            if ($currentMonth > 01 && $currentMonth <= 04) {
                $this->apiVersion = date("Y-" . '01');
            } elseif ($currentMonth > 04 && $currentMonth <= 07) {
                $this->apiVersion = date("Y-" . '04');
            } elseif ($currentMonth > 07 && $currentMonth <= 10) {
                $this->apiVersion = date("Y-" . '07');
            } elseif (($currentMonth > 10 && $currentMonth < 12) || $currentMonth == 01) {
                $this->apiVersion = date("Y-" . '10');
            }
        }
        if ($monthDiff <= -6) {
            if ($currentMonth > 01 && $currentMonth <= 04) {
                $this->apiVersion = date("Y-" . '01');
            } elseif ($currentMonth > 04 && $currentMonth <= 07) {
                $this->apiVersion = $previousYear . '-' . '04';
            } elseif ($currentMonth > 07 && $currentMonth <= 10) {
                $this->apiVersion = $previousYear . '-' . '07';
            } elseif (($currentMonth > 10 && $currentMonth < 12) || $currentMonth == 01) {
                $this->apiVersion = $previousYear . '-' . '10';
            }
        }
        $versionJsonPath = str_replace('assets/', 'shopify/data/api_version.json', ASSETS_PATH_W);
        $installedVersion = json_decode(file_get_contents($versionJsonPath), true);
        $installedVersion[0]['api_version'] = $this->apiVersion;
        $jsonData = json_encode($installedVersion);
        file_put_contents($versionJsonPath, $jsonData);

        $baseDIR = getcwd();
        $xmlPath = $baseDIR . '/../../config.xml';
        $dom = new \DomDocument();
        $dom->load($xmlPath);
        $versionFileData = str_replace('assets/', 'shopify/data/api_version.json', ASSETS_PATH_R);
        $versionFileData = json_decode(file_get_contents($versionFileData), true);
        if (isset($dom->getElementsByTagName('apiVersion')->item(0)->nodeValue) && $dom->getElementsByTagName('apiVersion')->item(0)->nodeValue != $this->apiVersion) {
            $dom->getElementsByTagName('apiVersion')->item(0)->nodeValue = $versionFileData[0]['api_version'];
            $dom->save($xmlPath);
        } else {
            $dataElement = $dom->createElement("apiVersion", $versionFileData[0]['api_version']);
            $dom->getElementsByTagName('url_detail')->item(0)->appendChild($dataElement);
            $dom->save($xmlPath);
        }
    }

    /**
     * Get: Get diffrenece between api version month
     *
     * @author divya@imprintnext.com
     * @date   31 January 2023
     * @return year-month combination string
     */
    public function getVersionDifference()
    {
        $versionDir = str_replace('assets/', 'shopify/data', ASSETS_PATH_W);
        $versionJsonPath = str_replace('assets/', 'shopify/data/api_version.json', ASSETS_PATH_W);
        if (!is_file($versionJsonPath)) {
            $baseDIR = getcwd();
            $xmlPath = $baseDIR . '/../../config.xml';
            $dom = new \DomDocument();
            $dom->load($xmlPath);
            $versionValue = $dom->getElementsByTagName('apiVersion')->item(0)->nodeValue;
            $vesionJsonData = [
                ["api_version" => $versionValue]
            ];
            mkdir($versionDir, 0777, true);
            $targetFile = $versionDir . '/api_version.json';
            file_put_contents($targetFile, json_encode($vesionJsonData));
            $installedVersion = json_decode(file_get_contents($versionJsonPath), true);
        } else {
            $installedVersion = json_decode(file_get_contents($versionJsonPath), true);
        }

        $currentdate = date("Y-m");
        $apiVersionMonth = $installedVersion[0]['api_version'];
        $ts1 = strtotime($currentdate);
        $ts2 = strtotime($apiVersionMonth);
        $year1 = date('Y', $ts1);
        $year2 = date('Y', $ts2);
        $month1 = date('m', $ts1);
        $month2 = date('m', $ts2);
        return (($year1 - $year2) * 12) + ($month1 - $month2);
    }

    /**
     * Get: get Shopify Access token
     *
     * @param $code  Shopify Oauth token
     *
     * @author debashisd@riaxe.com
     * @date   02 March 2020
     * @return Shopify rest access token
     */
    public function getAccessToken($code)
    {
        // POST to  POST https://SHOP_NAME.myshopify.com/admin/oauth/access_token
        $url = "https://{$this->shopDomain}/admin/oauth/access_token";
        $payload = "client_id={$this->apiKey}&client_secret={$this->secret}&code=$code";
        $response = $this->curlHttpApiRequest('POST', $url, '', $payload, array());
        $response = json_decode($response, true);
        if (isset($response['access_token'])) {
            return $response['access_token'];
        }
        return '';
    }

    /**
     * Internal function to get API call credit done per second
     *
     * @return string
     */
    private function callsMade()
    {
        return $this->shopApiCallLimitParam(0);
    }

    /**
     * Internal function to get API call credit limit per second
     *
     * @return string
     */
    private function callLimit()
    {
        return $this->shopApiCallLimitParam(1);
    }

    /**
     * Internal function to get API call credit left per second
     *
     * @return string
     */
    private function callsLeft()
    {
        try {
            return $this->callLimit() - $this->callsMade();
        } catch (\Exception $e) {
            return 40;
        }
    }

    /**
     * Shopify REST aPI call helper function
     *
     * @param $method  REST API call method (GET, POST, PUT, DELETE)
     * @param $path  Shopify API end point
     * @param $params  Shopify API parameters if any
     * @param $sessionKey  Session identifying key for pagination.
     *
     * @author debashisd@riaxe.com
     * @date   02 March 2020
     * @return Shopify REST API call response in array
     */
    private function call($method, $path, $params = array(), $sessionKey = "", $fetchRaw = false)
    {
        $APIData = array();
        if ($method == 'GET' && (strpos($path, '/admin/products/') !== false || strpos($path, '/admin/variants/') !== false) && !$fetchRaw) {
            $APIData = $this->getAPIDataFromCache($path);
        }
        if (empty($APIData)) {
            if ($this->callsLeft() < 5) {
                sleep(8);
            }
            //checking difference between current api version and version in config.xml file
            if ($this->getVersionDifference()  > 6 || $this->getVersionDifference() <= -6) {
                $this->getLatestApiVersion();
            }
            $needle   = 'customer_saved_searches';
            $versionString = 'api/' . $this->apiVersion . '/';
            $newPath = (!empty($this->apiVersion) && strpos($path, $this->apiVersion) === false && strpos($path, $needle) === false) ? str_replace("admin/", "admin/" . $versionString, $path) : $path;
            $baseurl = "https://{$this->shopDomain}/";
            $url = $baseurl . ltrim($newPath, '/');
            $query = in_array($method, array('GET', 'DELETE')) ? $params : array();
            $payload = in_array($method, array('POST', 'PUT')) ? stripslashes(str_replace("\u", "\\\\u", json_encode($params))) : array();
            $requestHeaders = in_array($method, array('POST', 'PUT')) ? array("Content-Type: application/json; charset=utf-8", 'Expect:') : array();
            // add auth headers
            $requestHeaders[] = 'X-Shopify-Access-Token: ' . $this->token;
            $response = $this->curlHttpApiRequest($method, $url, $sessionKey, $query, $payload, $requestHeaders);
            $response = json_decode($response, true);
            if (isset($response['errors']) || ($this->lastResponseHeaders['http_status_code'] >= 400)) {
                return array("method" => $method, "path" => $newPath, "params" => $params, "header" => $this->lastResponseHeaders, "response" => $response);
            }
            $APIData = (is_array($response) && (!empty($response))) ? array_shift($response) : $response;
        }
        return $APIData;
    }

    private function getAPIDataFromCache($path)
    {
        $APIContent = array();
        // some places the variant detail is called as:: admin/products/<product_id>/variants/<variant_id>.json
        // added extra conditions for that
        if (strpos($path, 'product') !== false && strpos($path, 'variant') === false) {
            $APIQry = substr($path, strrpos($path, '/') + 1);
            $thisProductID = substr($APIQry, 0, strpos($APIQry, '.'));
            $thisProdCacheDIR = SHOPIFY_CACHE_FOLDER . $thisProductID . ".json";
            if (!empty($thisProductID) && file_exists($thisProdCacheDIR)) {
                $cacheContent = file_get_contents($thisProdCacheDIR);
            }
            $APIContent = $cacheContent;
        }

        // alternative path for variant
        $vUrlPattern = "/\/product\\/[a-z0-9]+\/variant\//i";
        if (strpos($path, 'variant') !== false || preg_match($vUrlPattern, stripslashes($path))) {
            $APIQry = substr($path, strrpos($path, '/') + 1);
            $thisVariantID = substr($APIQry, 0, strpos($APIQry, '.'));
            $thisVarCacheDIR = SHOPIFY_CACHE_FOLDER . "variants/" . $thisVariantID . ".json";
            if (!empty($thisVariantID) && file_exists($thisVarCacheDIR)) {
                $cacheContent = file_get_contents($thisVarCacheDIR);
            }
            $APIContent = $cacheContent;
        }
        $jsonCache = json_decode($APIContent, true);
        if (!empty($jsonCache)) { //nested if is written to avoid syntax error. ignore during sonarqube fix
            if (!array_key_exists('data', $jsonCache)) {
                $APIContent = [];
            }
        }
        return $APIContent;
    }

    /**
     * Shopify REST aPI signature validator
     *
     * @param $query  Shopify API query params
     *
     * @author debashisd@riaxe.com
     * @date   02 March 2020
     * @return Shopify REST API signature
     */
    private function validateSignature($query)
    {
        if (!is_array($query) || empty($query['signature']) || !is_string($query['signature'])) {
            return false;
        }
        foreach ($query as $k => $v) {
            if ($k == 'signature') {
                continue;
            }
            $signature[] = $k . '=' . $v;
        }
        sort($signature);
        $signature = md5($this->secret . implode('', $signature));
        return $query['signature'] == $signature;
    }

    /**
     * Shopify API curl function
     *
     * @param $method  REST API call method (GET, POST, PUT, DELETE)
     * @param $path  Shopify API end point
     * @param $params  Shopify API parameters if any
     * @param $sessionKey  Session identifying key for pagination.
     *
     * @author debashisd@riaxe.com
     * @date   02 March 2020
     * @return Curlresponse
     */
    private function curlHttpApiRequest($method, $url, $sessionKey, $query = '', $payload = '', $requestHeaders = array())
    {
        $url = $this->curlAppendQuery($url, $query);
        $ch = curl_init($url);
        $this->curlSetopts($ch, $method, $payload, $requestHeaders);
        $response = curl_exec($ch);
        $errno = curl_errno($ch);
        $error = curl_error($ch);
        curl_close($ch);
        if ($errno) {
            print_r($errno . ": " . $error);
        }
        list($message_headers, $message_body) = preg_split("/\r\n\r\n|\n\n|\r\r/", $response, 2);
        $this->lastResponseHeaders = $this->curlParseHeaders($message_headers);
        if ($sessionKey != '') {
            $headerLink = $this->lastResponseHeaders['link'];
            if ($this->returnHeaderArray($headerLink) != '') {
                $_SESSION[$sessionKey] = $this->returnHeaderArray($headerLink);
            }
        }
        // var_dump($this->lastResponseHeaders);exit();
        return $message_body;
    }

    /**
     * Shopify API curl header return
     *
     * @param $path  Shopify API header response link
     *
     * @author debashisd@riaxe.com
     * @date   02 March 2020
     * @return pagination links if available
     */
    private function returnHeaderArray($linkHeader)
    {
        $cleanArray = [];
        if (strpos($linkHeader, ',') !== false) {
            //Split into two or more elements by comma
            $linkHeaderArr = explode(',', $linkHeader);
        } else {
            //Create array with one element
            $linkHeaderArr[] = $linkHeader;
        }
        foreach ($linkHeaderArr as $linkHeader) {
            $cleanArray += [
                $this->extractRel($linkHeader) => $this->extractLink($linkHeader)
            ];
        }
        return $cleanArray;
    }

    /**
     * Internal function to get pagination links
     *
     * @return string
     */
    private function extractLink($element)
    {
        if (preg_match('/<(.*?)>/', $element, $match) == 1) {
            return $match[1];
        }
    }

    /**
     * Internal function to get pagination links
     *
     * @return string
     */
    private function extractRel($element)
    {
        if (preg_match('/rel="(.*?)"/', $element, $match) == 1) {
            return $match[1];
        }
    }

    /**
     * Internal function to get pagination links
     *
     * @return string
     */
    private function curlAppendQuery($url, $query)
    {
        if (empty($query)) {
            return $url;
        }
        if (is_array($query)) {
            return "$url?" . http_build_query($query);
        } else {
            return "$url?$query";
        }
    }

    /**
     * Internal function to set curl params
     *
     * @return string
     */
    private function curlSetopts($ch, $method, $payload, $requestHeaders)
    {
        curl_setopt($ch, CURLOPT_HEADER, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
        curl_setopt($ch, CURLOPT_USERAGENT, 'ohShopify-php-api-client');
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 90);
        curl_setopt($ch, CURLOPT_TIMEOUT, 500);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
        if (!empty($requestHeaders)) {
            curl_setopt($ch, CURLOPT_HTTPHEADER, $requestHeaders);
        }
        if ($method != 'GET' && !empty($payload)) {
            if (is_array($payload)) {
                $payload = http_build_query($payload);
            }
            curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
        }
    }

    /**
     * Internal function to get parsed CURL header return
     *
     * @return string
     */
    private function curlParseHeaders($message_headers)
    {
        $headerLines = preg_split("/\r\n|\n|\r/", $message_headers);
        $headers = array();
        list(, $headers['http_status_code'], $headers['http_status_message']) = explode(' ', trim(array_shift($headerLines)), 3);
        foreach ($headerLines as $headerLine) {
            list($name, $value) = explode(':', $headerLine, 2);
            $name = strtolower($name);
            $headers[$name] = trim($value);
        }
        return $headers;
    }

    /**
     * Internal function to get Shopify API call limits left
     *
     * @return string
     */
    private function shopApiCallLimitParam($index)
    {
        if ($this->lastResponseHeaders == null) {
            throw new \Exception('Cannot be called before an API call.');
        }
        $params = explode('/', $this->lastResponseHeaders['http_x_shopify_shop_api_call_limit']);
        return (int) $params[$index];
    }

    /**
     * Internal function to get sanitized API text contents
     *
     * @return string
     */
    public static function shopify_body($body)
    {
        return strip_tags(str_ireplace('"', "''", $body));
    }

    /**
     * Internal function to extract numeric value from a set of string
     */
    public function getNumericData($stringValue)
    {
        $numericValue = preg_replace("/[^0-9]/", '', $stringValue);
        return $numericValue;
    }


    /**
     * Internal function to get Show in designer collection id
     *
     * @return string
     */
    private function getShowInDesignerId()
    {
        $collectionQuery = <<<JSON
                query starts {
                    collectionByHandle(handle: "show-in-designer") {
                            id
                    }
                }
        JSON;
        $collectionData = $this->graphQlRequest($collectionQuery);
        $collectionId = $collectionData['data']['collectionByHandle']['id'];
        return $this->getNumericData($collectionId);
    }

    /**
     * Getting pre-designed-product collection id
     * @param
     * @return integer (pre designed product collection id)
     *
     */
    public function getPreDesignedCollectionId()
    {
        $collectionQuery = <<<JSON
                query starts {
                    collectionByHandle(handle: "pre-designed-product") {
                            id
                    }
                }
        JSON;
        $collectionData = $this->graphQlRequest($collectionQuery); //get predesigned-collection query
        $collectionId =  $this->getNumericData($collectionData['data']['collectionByHandle']['id']);

        if ($collectionId != "") {
            return $collectionId;
        } else {
            $collectionCreateQuery = <<<JSON
            mutation {
                collectionCreate(
                  input: {
                    title: "Pre Designed Product",
                    handle:"pre-designed-product",
                    descriptionHtml: "<strong>The products under this collection are designed in designer tool.</strong>",

                  }
                ) {
                  collection {
                    id
                  }
                }
              }
            JSON;
            $collectionPostData = $this->graphQlRequest($collectionCreateQuery);
            $collectionId = $collectionPostData['data']['collectionCreate']['collection']['id'];
            return $this->getNumericData($collectionId);
        }
    }

    /**
     * Getting catalog-product collection id
     * @param
     * @return integer (pre designed product collection id)
     *
     */
    public function getCatalogueCollectionId()
    {
        $collectionQuery = <<<JSON
                query starts {
                       collectionByHandle(handle: "imprint_catalogue") {
                       id
                  }
              }
        JSON;
        $collectionData = $this->graphQlRequest($collectionQuery); // getting imprint catalogue query
        $collectionId =  $this->getNumericData($collectionData['data']['collectionByHandle']['id']);

        if ($collectionId != "") {
            return $collectionId;
        } else {
            $collectionCreateQuery = <<<JSON
            mutation {
                collectionCreate(
                  input: {
                    title: "imprint catalogue",
                    handle:"imprint_catalogue",
                    descriptionHtml: "<strong>The products under this collection are imported through ImprintNext catalogue.</strong>",
                    ruleSet: {
                      appliedDisjunctively: false,
                      rules: {
                        column: TAG,
                        relation: EQUALS,
                        condition: "catalogue"
                      }
                    }
                  }
                ) {
                  collection {
                    id
                  }
                }
              }
            JSON;
            $collectionPostData = $this->graphQlRequest($collectionCreateQuery);
            $collectionId = $collectionPostData['data']['collectionCreate']['collection']['id'];
            return $this->getNumericData($collectionId);
        }
    }

    /**
     *  to get Customized collection id
     *
     * @return integer
     */
    private function getCustomizedCollectionId()
    {
        $query = <<<JSON
                     query starts {
                        collectionByHandle(handle: "customized") {
                          id
                        }
                    }
                JSON;
        $collectionArr = $this->graphQlRequest($query);
        $collection = $collectionArr['data']['collectionByHandle'];
        if (!empty($collection)) {
            return $collection['id'];
        }
    }

    /**
     * GET: Fetching all available resource option from the store
     *
     * @author divya@imprintnext.com
     * @date 05 August 2024
     * @return Array of all store related information
     */

    public function shopifyStoreResourceLimit()
    {
        $storeDataQuery = <<<JSON
                            query getResourceLimit {
                            shop {
                                resourceLimits {
                                locationLimit
                                maxProductOptions
                                maxProductVariants
                                redirectLimitReached
                                }
                            }
                        }
                      JSON;
        $getStoreLimitDetails = $this->graphQlRequest($storeDataQuery); //getting all avaialble resource limits
        return $getStoreLimitDetails = $getStoreLimitDetails['data']['shop']['resourceLimits'];
    }

    /** ************************* Product Module Start **************************** **/

    /**
     * GET: Fetching all products from store
     *
     * @author inkXE
     * @date 16 Dec 2018
     * @param filter parameters
     * @return Array of all product
     */
    public function getAllProducts($filters, $isCustomize = '')
    {
        $products = [];
        $productArr = [];
        $productParams['limit'] = empty($filters['limit']) ? 250 : $filters['limit'];
        $productParams['order_by'] = empty($filters['orderby']) ? 'CREATED' : 'TITLE';
        $reverseOrder = empty($filters['orderby']) && ($filters['order'] == 'desc') ? 'true' : 'false';
        $order = ($filters['order'] == "desc") ? SORT_DESC : SORT_ASC;
        $productParams['orders'] = $filters['order'];
        $productParams['status'] = 'active';
        $requestedPage = empty($filters['page']) ? 1 : $filters['page'];
        $categoryid = $filters['collection_id'];
        $searchstring = $filters['title'];

        if (!$categoryid && $categoryid == '') {
            $productParams['collection_id'] = $this->getShowInDesignerId();
        }
        if ($categoryid && $categoryid != '') {
            $productParams['collection_id'] = $categoryid;
        }
        if ($searchstring && $searchstring != '') {
            $productParams['title'] = $searchstring;
            $productArr = $this->getSearchProduct($productParams);
            // $query = "status:{$productParams['status']} title:{$productParams['title']} -vendor:imprintNext";
        }
        if ($isCustomize == 1) {
            $productParams['collection_id'] = $this->getPreDesignedCollectionId();
        }
        if ($filters['isCatalogue'] > 0) {
            $productParams['collection_id'] = $this->getCatalogueCollectionId();
        }
        $settingJSON = ASSETS_PATH_W . "settings";
        $saveSessionData = $settingJSON . '/' . "shopify_session.json";
        if (empty($productArr)) {
            $productListQuery = <<<JSON
             query productList {
                    collection(id: "gid://shopify/Collection/{$productParams['collection_id']}") {
                            products(first: {$productParams['limit']}, sortKey: {$productParams['order_by']}, reverse: {$reverseOrder}) {
                            pageInfo {
                                endCursor
                                hasNextPage
                                hasPreviousPage
                                startCursor
                            }
                            edges {
                                node {
                                    id
                                    handle
                                    title
                                    status
                                    templateSuffix
                                    tags
                                    totalInventory
                                    productType
                                    variants(first: 100) {
                                            edges {
                                                node {
                                                    id
                                                    sku
                                                    title
                                                    price
                                                    inventoryPolicy
                                                    inventoryQuantity
                                                }
                                            }
                                        }
                                    images(first: 15) {
                                            edges {
                                                node {
                                                    url
                                                }
                                            }
                                        }
                                    vendor
                                    variantsCount {
                                            count
                                    }
                                }
                                }
                            }
                        }
                    }
             JSON;

            if ($requestedPage == 0) {
                $getSessionData = json_decode(file_get_contents($saveSessionData), true);
                $addBeforeCursor = 'sortKey: ' . $productParams['order_by'] . ', before: "' . $getSessionData['data']['collection']['products']['pageInfo']['startCursor'] . '"';
                $productListQuery = str_replace('sortKey: ' . $productParams['order_by'], $addBeforeCursor, $productListQuery);
            } elseif ($requestedPage > 1) {
                $getSessionData = json_decode(file_get_contents($saveSessionData), true);
                $addNextCursor = 'sortKey: ' . $productParams['order_by'] . ', after: "' . $getSessionData['data']['collection']['products']['pageInfo']['endCursor'] . '"';
                $productListQuery = str_replace('sortKey: ' . $productParams['order_by'], $addNextCursor, $productListQuery);
            }
            $productArr = $this->graphQlRequest($productListQuery);
        }

        if (!empty($productArr['data']['collection']['products']['edges']) && $searchstring == '') {
            file_put_contents($saveSessionData, json_encode($productArr));
        }

        if (!empty($productArr['data']['collection']['products']['edges']) &&  $searchstring == '') {
            foreach ($productArr['data']['collection']['products']['edges'] as $eachProduct) {
                $products[] = $eachProduct;
            }
            $keys = array_column($products, $productParams['order_by']);
            if ($keys) {
                array_multisort($keys, $order, $products);
            }
        } else {
            foreach ($productArr['data']['products']['edges'] as $eachProduct) {
                if ($eachProduct['node']['inCollection'] == 1) {
                    $products[] = $eachProduct;
                }
            }
        }
        return $products;
    }


    /**
     * Save the product and order data in cache file
     *
     * @author sonali@imprintnext.com
     * @modified by pansy@imprintnext.com
     * @date 10 May 2023
     * @param params & type
     * @return product details
     */
    private function checkCacheData($productParams, $type)
    {
        $getCacheData = ASSETS_PATH_W . $type . '/cache/' . $type . '_list.json';
        $getCacheDataArr = file_get_contents($getCacheData);
        $cacheResponseArr = json_decode($getCacheDataArr, true);
        $lastModifiedFileTime = filemtime($getCacheData);
        $lastModifiedTime = new \DateTime(date('Y-m-d H:i:s', $lastModifiedFileTime)); //created time of the .json file
        $currentTime = new \DateTime(date('Y-m-d H:i:s'));
        $interval = $currentTime->diff($lastModifiedTime);
        $interval = $interval->format('%R%a days');
        if (empty($cacheResponseArr) || intval($interval) > 0 || $productParams['cache_delete'] == 1 || $productParams['status'] == "closed") {
            if ($type == "products") {
                $productListQuery = <<<JSON
                                        query productList {
                                            collection(id: "gid://shopify/Collection/{$productParams['collection_id']}") {
                                                products(first: {$productParams['limit']}, sortKey: {$productParams['order_by']}) {
                                                pageInfo {
                                                    endCursor
                                                    hasNextPage
                                                    hasPreviousPage
                                                    startCursor
                                                }
                                                edges {
                                                    node {
                                                        id
                                                        handle
                                                        title
                                                        status
                                                        templateSuffix
                                                        tags
                                                        totalInventory
                                                        productType
                                                        variants(first: 100) {
                                                                edges {
                                                                    node {
                                                                        id
                                                                        sku
                                                                        title
                                                                        price
                                                                        inventoryPolicy
                                                                        inventoryQuantity
                                                                    }
                                                                }
                                                            }
                                                        images(first: 15) {
                                                                edges {
                                                                    node {
                                                                        url
                                                                    }
                                                                }
                                                            }
                                                            vendor
                                                            variantsCount {
                                                                count
                                                            }
                                                    }
                                                }
                                                }
                                            }
                                        }
                                    JSON;
                $cacheResponseArr = $this->graphQlRequest($productListQuery);
            } else {
                $productParams['status'] = "open";
                $cacheResponseArr = $this->call('GET', '/admin/orders.json', $productParams, "orders");
            }
            $cacheDIR = ASSETS_PATH_W . $type . '/cache';
            if (!is_dir($cacheDIR)) {
                mkdir($cacheDIR, 0777, true);
            }
            $thisCacheFile = $cacheDIR . '/' . $type . "_list.json";
            if (file_exists($thisCacheFile)) {
                unlink($thisCacheFile);
            }
            file_put_contents($thisCacheFile, json_encode($cacheResponseArr));
        }
        return $cacheResponseArr;
    }

    /**
     * geting product search details from store
     *
     * @author pansy@imprintnext.com
     * @date 25 Apr 2023
     * @param search name
     * @return product details
     */
    private function getSearchProduct($productParams)
    {
        if ($productParams['order_by'] == 'CREATED') {
            $productParams['order_by'] = 'CREATED_AT';
        }
        $reverseOrder =  $productParams['orders'] == 'desc' ? 'true' : 'false';
        $query = "status:{$productParams['status']} title:{$productParams['title']}* -vendor:imprintNext";
        $productListQuery = <<<JSON
                    query productList {
                        products(first: {$productParams['limit']}, query: "($query)", sortKey: {$productParams['order_by']}, reverse:{$reverseOrder}) {
                            pageInfo {
                                hasNextPage
                                hasPreviousPage
                                endCursor
                                startCursor
                            }
                            edges {
                                node {
                                    id
                                    title
                                    handle
                                    status
                                    templateSuffix
                                    tags
                                    defaultCursor
                                    inCollection(id: "gid://shopify/Collection/{$productParams['collection_id']}")
                                    totalInventory
                                    productType
                                    variants(first: 100) {
                                        edges {
                                            node {
                                                id
                                                sku
                                                title
                                                price
                                                inventoryPolicy
                                                inventoryQuantity
                                            }
                                        }
                                    }
                                    images(first: {$productParams['limit']}) {
                                        edges {
                                            node {
                                                url
                                            }
                                        }
                                    }
                                    vendor
                                    variantsCount {
                                        count
                                    }
                                }
                            }
                        }
                    }
            JSON;
        $productArr = $this->graphQlRequest($productListQuery);

        return  $productArr;
    }

    /**
     * geting product details from store
     *
     * @author imprintNext
     *
     * @modified by divya@imprintnext.com
     * @date 20 Dec 2018
     * @param product id
     * @return product details
     */
    public function getProductAttrOptions($filter)
    {
        //total variant count associated to a product
        $totalVariantCountQuery = <<<JSON
                                query MyQuery {
                                product(id: "gid://shopify/Product/{$filter['productID']}") {
                                    variantsCount {
                                    count
                                    }
                                  }
                                }
                         JSON;
        $totalVariantData = $this->graphQlRequest($totalVariantCountQuery);
        $totalVariantCount = $totalVariantData['data']['product']['variantsCount']['count'];
        $variantCount = !empty($totalVariantCount) ? $totalVariantCount : 1;
        //product details query
        $productQuery = <<<JSON
                                query productdetails {
                                product(id: "gid://shopify/Product/{$filter['productID']}") {
                                    id
                                    options {
                                          name
                                        }
                                    variants(first: $variantCount) {
                                    edges {
                                        node {
                                        id
                                        title
                                        price
                                        sku
                                        position
                                        selectedOptions {
                                                name
                                                value
                                        }
                                        inventoryPolicy
                                        createdAt
                                        updatedAt
                                        inventoryQuantity
                                        inventoryItem {
                                            id
                                        }
                                        }
                                      }
                                    }
                                    variantsCount {
                                    count
                                  }
                                }
                            }
                        JSON;
        $getProductData = $this->graphQlRequest($productQuery);
        $productDetails = $getProductData['data']['product']; //getting product data

        if ($filter['variantID'] == $filter['productID']) {
            $filter['variantID'] =  $this->getNumericData($productDetails['variants']['edges'][0]['node']['id']); //in case of decorated templates
        }
        //variant details query
        $variantQuery = <<<JSON
                            query variantDetails {
                                productVariant(id: "gid://shopify/ProductVariant/{$filter['variantID']}") {
                                    id
                                    selectedOptions {
                                    name
                                    value
                                    }
                                  }
                               }
                        JSON;
        $getVariantDetails = $this->graphQlRequest($variantQuery);
        $variantDetails = $getVariantDetails['data']['productVariant']; //getting selected variant details associated with the product


        $thisOptionPos = $this->getAttributePostion($filter['option'], $filter['productID']);

        $tierPriceData = array();
        $commonTierPrice = array();
        $variantTierPrice = array();
        $sameforAllVariants = $isTier = false;
        $shopifyDiscountPath = ASSETS_PATH_W . 'products/discount/';
        $thisProdDiscountFile = $shopifyDiscountPath . $filter['productID'] . ".json";

        if (file_exists($thisProdDiscountFile)) {
            $tierPriceData = json_clean_decode(file_get_contents($thisProdDiscountFile));
            $isTier = true;
            // little confusion with the key here but was done as sent from admin form field
            if ($tierPriceData['pricing_per_variants'] == 'true') {
                $sameforAllVariants = true;
                foreach ($tierPriceData['price_rules'][0]['discounts'] as $discount) {
                    $commonTierPrice[] = array(
                        "upper_limit" => $discount['upper_limit'],
                        "lower_limit" => $discount['lower_limit'],
                        "discount" => $discount['discount'],
                        "discountType" => $tierPriceData['discount_type']
                    );
                }
            } else {
                foreach ($tierPriceData['price_rules'] as $variant) {
                    foreach ($variant['discounts'] as $discount) {
                        $variantTierPrice[$variant['id']][] = array(
                            "upper_limit" => $discount['upper_limit'],
                            "lower_limit" => $discount['lower_limit'],
                            "discount" => $discount['discount'],
                            "discountType" => $tierPriceData['discount_type']
                        );
                    }
                }
            }
        }
        if (!empty($thisOptionPos)) {

            $options = $checkOptions = array();
            for ($pos = 1; $pos < $thisOptionPos; $pos++) {
                $checkPos = $pos - 1;
                $checkOptions[] = $variantDetails['selectedOptions'][$checkPos]['value'];
            }

            $selectedVariantColorData = array_column($variantDetails['selectedOptions'], 'value', 'name');
            $selectedVariantColorData = array_change_key_case($selectedVariantColorData, CASE_LOWER);
            $selectedVariantColor = $selectedVariantColorData[$this->colorAttrName]; //getting all the selected variant options data from variant


            foreach ($productDetails['variants']['edges'] as $variant) {
                $productVariantColorData = array_column($variant['node']['selectedOptions'], 'value', 'name'); //getting all the variant options data from product
                $productVariantColorData = array_change_key_case($productVariantColorData, CASE_LOWER);
                $productVariantColorValue = $productVariantColorData[$this->colorAttrName];

                $thisOptions = $optionDetails = array();
                for ($position = 1; $position <= $thisOptionPos; $position++) {
                    $varPos = $position - 1;
                    $thisOptions[] = $variant['node']['selectedOptions'][$varPos]['value'];
                }


                if (!empty($variant['imp_image_id'])) {
                    $ProductVar = new ProductVariants();
                    $variantID = $this->getNumericData($variant['node']['id']);
                    $catlogVar = $ProductVar->where('xe_id', '=', $variantID)->first()->toArray();
                    $variant['node']['inventoryQuantity'] = $catlogVar['inventory'];
                }


                if (count(array_intersect($checkOptions, $thisOptions)) == ($thisOptionPos - 1) && (strtolower($productVariantColorValue) == strtolower($selectedVariantColor) || empty($selectedVariantColor))) {
                    $variantValueData = array_column($variant['node']['selectedOptions'], 'value', 'name');
                    $variantValueData = array_change_key_case($variantValueData);
                    $variantValue = $variantValueData[$filter['option']];
                    $collectedOptions = (!empty($options[$filter['option']])) ? array_column($options[$filter['option']], 'name') : array();
                    if (!in_array($variantValue, $collectedOptions)) {
                        $optionDetails = array();

                        $optionDetails['id'] = $variantValue;
                        $optionDetails['name'] = $variantValue;
                        $optionDetails['variant_id'] = $this->getNumericData($variant['node']['id']);
                        if ($filter['is_price'] > 0) {
                            $optionDetails['inventory']['stock'] = ($variant['node']['inventoryPolicy'] == "CONTINUE" || $variant['node']['inventoryItem']['tracked'] == 'false' ? 100000 : $variant['node']['inventoryQuantity']);
                            $optionDetails['inventory']['min_quantity'] = 1;
                            $optionDetails['inventory']['max_quantity'] = ($variant['inventoryPolicy'] == "CONTINUE" || $variant['node']['inventoryItem']['tracked'] == 'false' ? 100000 : $variant['node']['inventoryQuantity']);
                            $optionDetails['inventory']['quantity_increments'] = 1;
                            $optionDetails['price'] = $variant['node']['price'];
                            $optionDetails['tier_prices'] = [];
                            if ($isTier) {
                                $optionDetails['tier_prices'] = ($sameforAllVariants === true ? $this->createTierPrice($commonTierPrice, $variant['node']['price']) : $this->createTierPrice($variantTierPrice[$this->getNumericData($variant['node']['id'])], $variant['node']['price']));
                            }

                            $optionDetails['attributes'] = array();
                            for ($count = 0; $count < count($productDetails['options']); $count++) {
                                if (isset($variant['node']['selectedOptions']) && !empty($variant['node']['selectedOptions'])) {
                                    $isTitlePresent = array_search('Default Title', array_column($variant['node']['selectedOptions'], 'value'));
                                    if (!$isTitlePresent) {
                                        $attributeKey = strtolower($productDetails['options'][$count]['name']);
                                        $optionDetails['attributes'][$attributeKey] = $variant['node']['selectedOptions'][$count]['value'];
                                        $optionDetails['attributes'][$attributeKey . "_id"] = strtolower($variant['node']['selectedOptions'][$count]['value']);
                                    }
                                }
                            }
                        }
                        $options[$filter['option']][] = $optionDetails;
                    }
                }
            }
            return $options;
        } else {
            // print_r("Attribute not found !!!");
            // exit();
            return json_encode("Attribute not found !!!");
        }
    }

    private function createTierPrice($tierPriceRule, $variantPrice)
    {
        $tierPrice = array();
        foreach ($tierPriceRule as $tier) {
            $thisTier = array();
            $thisTier['quantity'] = $tier['lower_limit'];
            $thisTier['percentage'] = ($tier['discountType'] == "percentage" ? $tier['discount'] : number_format(($tier['discount'] / $variantPrice) * 100, 2));
            $thisTier['price'] = ($tier['discountType'] == "flat" ? ($variantPrice - $tier['discount']) : ($variantPrice - (($tier['discount'] / 100) * $variantPrice)));
            $thisTier['discount'] = $tier['discount'] . "_" . $tier['discountType'];
            $tierPrice[] = $thisTier;
        }

        return $tierPrice;
    }


    /**
     * geting product details from store
     *
     * @author inkXE
     *
     * @modified by divya@imprintnext.com
     * @date 20 Dec 2018
     * @param product id
     * @return product details
     */
    public function getShopProductDetails($productId)
    {
        $productQuery = <<<JSON
        query productdetails {
            product(id: "gid://shopify/Product/$productId") {
              id
              title
              tags
              descriptionHtml
              createdAt
              images(first: 250) {
                    nodes {
                         id
                         url
                 }
               }
              variants(first: 200) {
                  nodes {
                    id
                    title
                    price
                    sku
                    position
                    inventoryPolicy
                    createdAt
                    updatedAt
                    inventoryQuantity
                    image {
                        id
                        url
                    }
                    selectedOptions {
                      name
                      value
                      optionValue {
                        id
                        name
                    }
                  }
                }
              }
               options(first: 10) {
                    id
                    position
                    name
                    values
                }
                variantsCount {
                        count
                    }
             }
          }
        JSON;
        $productData = $this->graphQlRequest($productQuery, '/product/' . $productId . '.json'); //read from product saved cache
        $product = $productData['data']['product'];
        $impImagId = $product['variants']['nodes'][0]['imp_image_id']; //product extra options key
        $variant = $product['variants']['nodes'][0];
        $colorPos = $this->getAttributePostion($this->colorAttrName, $productId);

        foreach ($product['images']['nodes'] as $pi) {
            $id = $this->getNumericData($pi['id']);
            $images[$id] = $pi;
            $images[$pi['id']]['variant_ids'] = [];
        }


        foreach ($product['variants']['nodes'] as $variants) {
            if (!empty($variants['image']) && array_key_exists($variants['image']['id'], $images)) {
                foreach ($images as $pimg) {
                    if (!in_array($variants['id'], $images[$variants['image']['id']]['variant_ids'])) {
                        $images[$variants['image']['id']]['variant_ids'][] = $variants['id'];
                    }
                }
            }
        }


        // Get Product Attributes
        $attributes = [];
        foreach ($product['options'] as $attribute) {

            if (isset($attribute['name']) && strtolower($attribute['name']) != "title") {
                $attributeValues = array();
                $thisAttribute['id'] = strtolower($attribute['name']);
                $thisAttribute['name'] = $attribute['name'];
                foreach ($attribute['optionValues'] as $storeSizeKey => $storeSize) {
                    $attributeValues[$storeSizeKey] = [
                        'id' => $storeSize['name'],
                        'name' => $storeSize['name']
                    ];
                }
                $thisAttribute['options'] = $attributeValues;
                $attributes[] = $thisAttribute;
            }
        }


        //Choosing variant price as product price
        $productPrice = 10000000;
        foreach ($product['variants']['nodes'] as $pv) {
            if ($pv['price'] < $productPrice) {
                $productPrice = $pv['price'];
                break;
            }
        }

        $productType = (strpos(strtolower($product['variants']['nodes'][0]['title']), 'default title') !== false ? "simple" : "variable");
        $products = [
            'id' => $this->getNumericData($product['id']),
            'variant_id' => $this->getNumericData($product['variants']['nodes'][0]['id']),
            'name' => $product['title'],
            'description' => $product['descriptionHtml'],
            'type' => $productType,
            'sku' => ($product['variantsCount']['count'] > 0) ? $product['variants']['nodes'][0]['sku'] : '',
            'is_decoration_exists' => 0,
            'print_profile' => [],
            'price' => $productPrice,
        ];

        if ($colorPos > 0) {
            foreach ($variant['selectedOptions'] as $optionData) {
                if (strtolower($optionData['name']) == strtolower($this->colorAttrName)) {
                    $color_look =  $this->removeSPLChars($optionData['value']);
                    $color_lookup = ($productType == 'simple' ? '_' : $color_look);
                }
            }
        } else {
            // if color is not available first option would be searched in image name
            // $color_lookup = "_" . $this->removeSPLChars($variant['selectedOptions'][0]['value']) . "_";
            $color_lookup = "_" . $this->removeSPLChars($variant['selectedOptions'][0]['value']) . "_";
        }

        $variantImageID = ($this->getNumericData($variant['image']['id']) ?
            $this->getNumericData($variant['image']['id']) : $this->getNumericData($product['images']['nodes'][0]['id']));
        // get variant images

        if (isset($images) && $variantImageID && array_key_exists($variantImageID, $images)) {
            foreach ($images as $key => $pimg) {
                if (!empty($pimg['variant_ids'])) {
                    if (in_array($variant['id'], $pimg['variant_ids'])) {
                        $arrKey = $this->getNumericData($key);
                        $unassignedImg['id'] = $this->getNumericData($images[$arrKey]['id']);
                        // $unassignedImg['labels'] = "Front";
                        $unassignedImg['src'] = self::shopify_image($images[$arrKey]['url'], $this->fullSize);
                        $unassignedImg['thumbnail'] = self::shopify_image($images[$arrKey]['url'], $this->thumbSize);
                        $unassignedImgs[] = $unassignedImg;
                    }
                }

                $thisImage = array();
                if ($this->str_contains_all(strtolower($pimg['url']), array($color_lookup, "front"))) {
                    $thisImage['id'] = $this->getNumericData($pimg['id']);
                    $thisImage['labels'] = "Front";
                    $thisImage['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                    $thisImage['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                } elseif ($this->str_contains_all(strtolower($pimg['url']), array($color_lookup, "left"))) {
                    $thisImage['id'] = $this->getNumericData($pimg['id']);
                    $thisImage['labels'] = "Left";
                    $thisImage['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                    $thisImage['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                } elseif ($this->str_contains_all(strtolower($pimg['url']), array($color_lookup, "right"))) {
                    $thisImage['id'] = $this->getNumericData($pimg['id']);
                    $thisImage['labels'] = "Right";
                    $thisImage['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                    $thisImage['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                } elseif ($this->str_contains_all(strtolower($pimg['url']), array($color_lookup, "back"))) {
                    $thisImage['id'] = $this->getNumericData($pimg['id']);
                    $thisImage['labels'] = "Back";
                    $thisImage['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                    $thisImage['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                } elseif ($this->str_contains_all(strtolower($pimg['url']), array($color_lookup, "top"))) {
                    $thisImage['id'] = $this->getNumericData($pimg['id']);
                    $thisImage['labels'] = "Top";
                    $thisImage['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                    $thisImage['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                } elseif ($this->str_contains_all(strtolower($pimg['url']), array($color_lookup, "bottom"))) {
                    $thisImage['id'] = $this->getNumericData($pimg['id']);
                    $thisImage['labels'] = "Bottom";
                    $thisImage['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                    $thisImage['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                } else {
                    $thisImage = [];
                }
                if (!empty($thisImage)) {
                    $products['images'][] = $thisImage;
                }
            }
        } else {
            if ($variant['request'] == 'quote') {
                $thisImage['thumbnail'] = array($product['image']['src']);
                $thisImage['src'] = array($product['image']['src']);
                $thisImage['labels'] = "Front";
                $products['images'][] = $thisImage;
            } else {
                $thisImage['thumbnail'] = array();
                $thisImage['src'] = array();
                $thisImage['labels'] = "";
                $products['images'][] = $thisImage;
            }
        }

          //for simple pre decorated products
        if($product['tags'][0]!='catalogue'){
        $product['images']['nodes'] = array_filter($product['images']['nodes'], function ($item) {
                     $filename = basename(parse_url($item['url'], PHP_URL_PATH));
                        return !preg_match('/^\d+/', $filename);
                    });

                $product['images']['nodes'] = array_values($product['images']['nodes']);

        }

        if (empty($unassignedImgs) || $productType == 'simple') {
            $imgLen = (count($product['images']['nodes']) > 4) ? 4 : count($product['images']['nodes']);
            for ($i = 0; $i < $imgLen; $i++) {
                if (isset($product['images']['nodes'][$i])) {
                    $unassignedImg['id'] =  $this->getNumericData($product['images']['nodes'][$i]['id']);
                    $unassignedImg['src'] = self::shopify_image($product['images']['nodes'][$i]['url'], $this->fullSize);
                    $unassignedImg['thumbnail'] = self::shopify_image($product['images']['nodes'][$i]['url'], $this->thumbSize);
                }
                $unassignedImgs[] = $unassignedImg;
            }
        }



        if (empty($products['images'])) {
            $products['images'] = $unassignedImgs;
        }
        if (!empty($impImagId)) {
            $newSideImage = new ProductImageSides();
            $getImgSides = $newSideImage->where('product_image_id', '=', $impImagId)->get()->toArray();
            foreach ($getImgSides as $imgSide) {
                $dbImg[] = [
                    'id' => $imgSide['xe_id'],
                    'labels' => $imgSide['side_name'],
                    'src' => $imgSide['file_name'],
                    'thumbnail' => $imgSide['thumbnail']
                ];
            }
            $products['images'] = $dbImg;
        }


        $products['slug'] = $product['title'];
        $products['categories'] = $this->getProductCategories($productId);
        $products['attributes'] = $attributes;
        $products['date_created'] = date('Y-m-d', strtotime($product['createdAt']));
        if (isset($products) && is_array($products) && !empty($products)) {
            $storeResponse = [
                'products' => $products
            ];
        } else {
            $storeResponse = [
                'status' => 0,
                'message' => 'No products available',
                'data' => []
            ];
        }

        return $storeResponse;
    }

    /**
     * Counting total no of products from store(Numeric value).
     *
     * @author inkXE
     * @modified by pansy@imprintnext.com
     * @date 16 Dec 2018
     * @param filter parameters
     * @return integer (Total no of products numeric value)
     */
    public function getTotalProductsCount($filters, $isCustomize = '')
    {
        if (!empty($isCustomize) && $isCustomize == "1") {
            $showInDesignerID = $this->getPreDesignedCollectionId();
        } else {
            $showInDesignerID = $this->getShowInDesignerId();
        }
        if (!empty($filters['collection_id'])) {
            $showInDesignerID = $filters['collection_id'];
        }
        $query = <<<JSON
        query starts {
            collection(id: "gid://shopify/Collection/$showInDesignerID") {
                        productsCount {
                            count
                        }
            }
        }
        JSON;
        $collectionArr = $this->graphQlRequest($query);
        return $collectionArr['data']['collection']['productsCount']['count'];
    }
    /**
     * Update smart collection rules.
     *
     * @author sonali@imprintnext.com
     * @modified by pansy@imprintnext.com
     * @date 10 Feb 2023
     * @param arraynull
     * @return array of collections
     */

    public function getCollectionsData($colId)
    {
        $collection = [
            "status" => 0,
            "message" => "something went wrong"
        ];
        $imprintSmartRules = [
            "condition" => "imprintNext",
            "column" => "VENDOR",
            "relation" => "NOT_EQUALS"
        ];
        $query = <<<JSON
            query starts {
                collection(id: "gid://shopify/Collection/$colId") {
                    handle
                    id
                    title
                    ruleSet {
                        rules {
                            condition
                            column
                            relation
                        }
                    }
                }
            }
        JSON;
        $collectionArr = $this->graphQlRequest($query);
        $smartCollections = $collectionArr['data']['collection'];
        if (empty($smartCollections) ||  empty($smartCollections['ruleSet'])) {
            $collection = [
                "status" => 0,
                "message" => "it's not a smart collection"
            ];
        } else {
            if ($smartCollections['title'] != 'customized') {
                foreach ($smartCollections['ruleSet']['rules'] as $colrule) {
                    if (!empty(array_diff($colrule,  $imprintSmartRules))) {
                        $smartCollections['ruleSet']['rules'][]  = $imprintSmartRules;
                        $rules = array_unique($smartCollections['ruleSet']['rules'], SORT_REGULAR);
                        $outputArray = array();
                        foreach ($rules as $item) {
                            $outputArray[] = "{column: {$item['column']}, relation: {$item['relation']}, condition: \"{$item['condition']}\"}";
                        }
                        $rules = "[" . implode(",", $outputArray) . "]";

                        $query = <<<JSON
                        mutation starts {
                            collectionUpdate(
                                input: {id: "gid://shopify/Collection/$colId", ruleSet: {appliedDisjunctively: false, rules: $rules}}
                                ) {
                                    collection {
                                        id
                                    }
                                }
                            }
                        JSON;
                        $updateCollection = $this->graphQlRequest($query);
                        if (!empty($updateCollection['data']['collectionUpdate']['collection'])) {
                            $collection = [
                                "status" => 1,
                                "message" => "Smart collection updated sucessfully."
                            ];
                        }
                    }
                }
            }
        }
        return $collection;
    }

    /**
     * Getting Collections/attributes from store
     *
     * @author inkXE
     * @modified by pansy@imprintnext.com
     * @date 16 Dec 2018
     * @param arraynull
     * @return array of collections
     */
    public function getCollections()
    {
        $checkCollections = array();
        $result = array();
        $query = <<<JSON
        query starts {
            collections(first: 250) {
              edges {
                 node {
                        handle
                        id
                        title
                        ruleSet {
                            rules {
                                condition
                                relation
                                column
                            }
                        }
                    }
                }
            }
        }
        JSON;
        $collectionArr = $this->graphQlRequest($query); //getting collections data
        $collections = $collectionArr['data']['collections']['edges'];
        foreach ($collections as $eachCollection) {
            $eachCollection = $eachCollection['node'];
            if ($eachCollection['ruleSet'] == null && $eachCollection['handle'] != "show-in-designer" && $eachCollection['handle'] != "pre-designed-product" && !in_array($eachCollection['title'], $checkCollections)) {
                $checkCollections[] = $eachCollection['title'];
                $result[] = array(
                    'id' => end(explode('/', $eachCollection['id'])),
                    'name' => $eachCollection['title'],
                    'type' => 'custom',
                    'parent_id' => 0
                );
            } elseif (!empty($eachCollection['ruleSet']) && $eachCollection['handle'] != "customized" && $eachCollection['handle'] != "all" && $eachCollection['handle'] != "show-in-designer") {
                $checkCollections[] = $eachCollection['title'];
                $result[] = array(
                    'id' => end(explode('/', $eachCollection['id'])),
                    'name' => $eachCollection['title'],
                    'type' => 'smart',
                    'parent_id' => 0
                );
            }
        }
        return $result;
    }

    /**
     * Getting smart collections from store
     *
     * @author inkXE
     * @modified by pansy@imprintnext.com
     * @date 16 Dec 2018
     * @param null
     * @return array of ids
     */
    public function getSmartCollections()
    {
        $collectionIds = array();
        $query = <<<JSON
        query starts {
            collections(first: 250) {
              edges {
                 node {
                        id
                        ruleSet {
                            rules {
                                condition
                                relation
                                column
                            }
                        }
                    }
                }
            }
        }
        JSON;
        $collectionArr = $this->graphQlRequest($query);
        if (!empty($collectionArr)) {
            $collections = $collectionArr['data']['collections']['edges'];
            foreach ($collections as $eachCollection) {
                $eachCollection = $eachCollection['node'];
                if (!empty($eachCollection['ruleSet'])) {
                    $collectionIds[] = end(explode('/', $eachCollection['id']));
                }
            }
        }
        return $collectionIds;
    }
    /**
     * Fetch all categories for a single product
     *
     * @author inkXE
     * @modified by pansy@imprintnext.com
     * @date 16 Dec 2018
     * @param product id
     * @return array of categories
     */
    public function getProductCategories($productId)
    {
        $productData = json_decode($productId, true);
        $productId = !empty($productData['pid']) ? $productData['pid'] : $productId;
        $collection = array();
        $query = <<<JSON
        query starts {
            collections(first: 250) {
              edges {
                 node {
                        handle
                        id
                        title
                        ruleSet {
                            rules {
                                condition
                                relation
                                column
                            }
                        }
                    }
                }
            }
        }
        JSON;
        $collectionArr = $this->graphQlRequest($query);
        $collections = $collectionArr['data']['collections']['edges'];
        foreach ($collections as $eachCollection) {
            $eachCollection = $eachCollection['node'];
            $excludeCustomHandles = ['show-in-designer', 'pre-designed-product'];
            $excludeSmartHandles = ['all', 'customized', 'catalog', 'show-in-designer'];
            if ($eachCollection['ruleSet'] == null && !in_array($eachCollection['handle'], $excludeCustomHandles)) {
                $collection[] = array(
                    'id' => end(explode('/', $eachCollection['id'])),
                    'name' => $eachCollection['title'],
                    'slug' => $eachCollection['handle'],
                    'parent_id' => 0
                );
            } elseif (!empty($eachCollection['ruleSet']) && !in_array($eachCollection['handle'], $excludeSmartHandles)) {
                $collection[] = array(
                    'id' => end(explode('/', $eachCollection['id'])),
                    'name' => $eachCollection['title'],
                    'slug' => $eachCollection['handle'],
                    'parent_id' => 0
                );
            }
        }
        return $collection;
    }

    /**
     * Getting only color attribute list from store
     *
     * @author inkXE
     * @modified by pansy@imprintnext.com
     * @date 16 Dec 2018
     * @param null
     * @return array of color attribute value
     */
    public function getColorAttributes()
    {
        $collection_id = $this->getShowInDesignerId();
        $limit = 250;
        $query = <<<JSON
                    query starts {
                        collection(id: "gid://shopify/Collection/$collection_id") {
                          products(first: $limit) {
                                nodes {
                                    options(first: 20) {
                                        name
                                        values
                                    }
                                    variants(first: 50) {
                                            nodes {
                                                selectedOptions {
                                                    name
                                                    value
                                                }
                                            }
                                        }
                                }
                            }
                        }
                    }
                JSON;
        $productArr = $this->graphQlRequest($query);
        $products = $productArr['data']['collection']['products']['nodes'];
        $colors = array();
        $checkColors = array();
        foreach ($products as $p) {
            $colorPos = null;
            foreach ($p['options'] as $key => $option) {
                if (strtolower($option['name']) == $this->colorAttrName) {
                    $colorPos = $key;
                }
            }
            if ($colorPos !== null) {
                foreach ($p['variants']['nodes'] as $pv) {
                    if ($pv['selectedOptions'][$colorPos]['value'] !== null && !in_array(str_replace(' ', '_', strtolower($pv['selectedOptions'][$colorPos]['value'])), $checkColors)) {
                        $colors['data'][] = array(
                            'id' => str_replace([' ', '/'], '_', strtolower($pv['selectedOptions'][$colorPos]['value'])),
                            'name' => strtolower($pv['selectedOptions'][$colorPos]['value'])
                        );
                        $checkColors[] = str_replace(' ', '_', strtolower($pv['selectedOptions'][$colorPos]['value']));
                    }
                }
            }
        }
        return $colors;
    }

    /**
     * Fetching all attributes from store
     *
     * @author inkXE
     * @modified by pansy@imprintnext.com
     * @date 18 Dec 2019
     * @param null
     * @return array - Array of all attribute list
     */
    public function getAttributes($productID = "")
    {
        $dataKey = "terms";
        $products = [];
        if (!empty($productID)) {
            $query = <<<JSON
                        query starts {
                            product(id: "gid://shopify/Product/$productID") {
                                images(first: 250) {
                                    nodes {
                                    id
                                    url
                                    }
                                }
                                 options {
                                    id
                                    position
                                    name
                                    values
                                }
                              variants(first: 250) {
                                nodes {
                                    id
                                    image {
                                        id
                                        url
                                    }
                                    selectedOptions {
                                    name
                                    value
                                    optionValue {
                                        id
                                        name
                                    }
                                 }
                                }
                              }
                            }
                        }
                    JSON;
            $productArr = $this->graphQlRequest($query, '/product/' . $productID . '.json');
            $products[] = $productArr['data']['product'];
            $dataKey = "options";
        } else {
            $collection_id = $this->getShowInDesignerId();
            $limit = 250;
            $query = <<<JSON
                        query starts {
                            collection(id: "gid://shopify/Collection/$collection_id") {
                              products(first: $limit) {
                                nodes {
                                    images(first: 250) {
                                        nodes {
                                        id
                                        url
                                        }
                                    }
                                    options {
                                        id
                                        position
                                        name
                                        values
                                    }
                                    variants(first: 250) {
                                    nodes {
                                        id
                                        image {
                                            id
                                            url
                                        }
                                        selectedOptions {
                                        name
                                        value
                                        optionValue {
                                            id
                                            name
                                        }
                                    }
                                    }
                                  }
                                }
                              }
                            }
                        }
                    JSON;
            $productArr = $this->graphQlRequest($query);
            $products = $productArr['data']['collection']['products']['nodes'];
        }

        $options = [];
        foreach ($products as $p) {
            $colorExist = 0;
            foreach ($p['options'] as $optionsValues) {
                if (strtolower($optionsValues['name']) == strtolower($this->colorAttrName)) {
                    $colorExist = 1;
                    break;
                }
            }

            $images = [];
            foreach ($p['images']['nodes'] as $pi) {
                $images[$pi['id']] = $pi;
                $images[$pi['id']]['variant_ids'] = [];
            }

            foreach ($p['variants']['nodes'] as $variant) {
                if (!empty($variant['image']) && array_key_exists($variant['image']['id'], $images)) {
                    foreach ($images as $pimg) {
                        if (!in_array($variant['id'], $images[$variant['image']['id']]['variant_ids'])) {
                            $images[$variant['image']['id']]['variant_ids'][] = $variant['id'];
                        }
                    }
                }
            }

            $thisProductColors = [];
            $flag = 1;
            foreach ($p['variants']['nodes'] as $variant) {
                $colorName = '';
                foreach ($variant['selectedOptions'] as $option) {
                    if (strtolower($option['name']) == strtolower($this->colorAttrName)) {
                        $colorName = $option['value'];
                    } else {
                        $flag = 0;
                        $colorName = $option['value'];
                    }

                    if (strtolower($option['name']) == "title") {
                        continue;
                    }

                    $optionKey = strtolower($option['name']);
                    if (!isset($options[$optionKey])) {
                        $options[$optionKey] = [
                            'id' => str_replace(' ', '_', strtolower($option['name'])),
                            'name' => $option['name'],
                            $dataKey => []
                        ];
                    }

                    $optionValueId = str_replace(' ', '_', strtolower($option['value']));

                    if (!in_array(strtolower($colorName), array_map('strtolower', $thisProductColors)) && strtolower($variant['title']) != "default title") {
                        $thisProductColors[] = $colorName;

                        $color_lookup = $colorExist > 0 ? $this->removeSPLChars($colorName) : $this->removeSPLChars($variant['selectedOptions'][0]['value']) . "_";

                        $variantImageID = $variant['image']['id'] ?? $p['images']['nodes'][0]['id'];
                        $image = [];
                        if (isset($images) && $variantImageID && array_key_exists($variantImageID, $images)) {
                            $unassignedImgs = [];
                            foreach ($images as $pimg) {
                                if (in_array($variant['id'], $pimg['variant_ids']) && !in_array($pimg['url'], array_column($unassignedImgs, 'src'))) {
                                    $unassignedImg['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                                    $unassignedImg['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                                    $unassignedImgs[] = $unassignedImg;
                                }

                                $thisImage = [];
                                if ($this->str_contains_all(strtolower($pimg['url']), [$color_lookup, "front"])) {
                                    $thisImage['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                                    $thisImage['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                                } elseif ($this->str_contains_all(strtolower($pimg['url']), [$color_lookup, "left"])) {
                                    $thisImage['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                                    $thisImage['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                                } elseif ($this->str_contains_all(strtolower($pimg['url']), [$color_lookup, "right"])) {
                                    $thisImage['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                                    $thisImage['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                                } elseif ($this->str_contains_all(strtolower($pimg['url']), [$color_lookup, "back"])) {
                                    $thisImage['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                                    $thisImage['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                                } elseif ($this->str_contains_all(strtolower($pimg['url']), [$color_lookup, "top"])) {
                                    $thisImage['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                                    $thisImage['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                                } elseif ($this->str_contains_all(strtolower($pimg['url']), [$color_lookup, "bottom"])) {
                                    $thisImage['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                                    $thisImage['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                                }

                                if (!empty($thisImage)) {
                                    $image[] = $thisImage;
                                }
                            }
                        }

                        if (empty($image)) {
                            $imgLen = min(count($p['images']['nodes']), 4);
                            for ($i = 0; $i < $imgLen; $i++) {
                                $unassignedImg['src'] = self::shopify_image($p['images']['nodes'][$i]['url'], $this->fullSize);
                                $unassignedImg['thumbnail'] = self::shopify_image($p['images']['nodes'][$i]['url'], $this->thumbSize);
                                $image[] = $unassignedImg;
                        }
                        }

                        // // Only include the first variant's images for non-color options
                        if ($optionKey !== strtolower($this->colorAttrName)) {
                            $image = array_slice($image, 0, 4);
                        }


                        $options[$optionKey][$dataKey][] = [
                            'id' => $optionValueId,
                            'name' => $option['value'],
                            'image' => $image
                        ];
                    }
                }
            }
        }
        $options = array_values($options);
        foreach ($options as $index => &$opt) {
            $opt['option_id'] = $index + 1;
        }
        return $options;
    }

    /**
     * get the Online Store publication ID
     *
     * @author pansy@imprintnext.com
     * @date 26 Jun 2024
     * @param null
     * @return Id
     */
    private function getPublicationId()
    {
        $publicationIDquery = <<<JSON
                            query publicationIDquery {
                                publications(first: 10) {
                                    nodes {
                                    id
                                    name
                                    }
                                }
                            }
                        JSON;
        $publications = $this->graphQlRequest($publicationIDquery);
        $publicationId = '';
        if (!empty($publications['data']['publications']['nodes'])) {
            foreach ($publications['data']['publications']['nodes'] as $eachPublication) {
                if (strtolower($eachPublication['name']) == 'online store') {
                    $publicationId = $eachPublication['id'];
                }
            }
        }
        return $publicationId;
    }

    /**
     * Retrieve a single product's category(not used currently)
     *
     * @author inkXE
     * @modified by pansy@imprintnext.com
     * @date 18 Dec 2019
     * @param array|object Request parameters
     * @return string New product id
     */

    public function createDecoratedProduct($params)
    {
        $imagesInfo = array();
        $colorVarArr = array();
        if (isset($params['type']) && $params['type'] != "") {
            $productType = $params['type'];
        }

        if ($productType == 'simple') {
            $response = $this->createSimpleDecoratedProduct($params);
            return $response;
        }
        // get parent product details
        if (isset($params['product_id']) && $params['product_id'] > 0) {
            $productId = $params['product_id'];
            $query = <<<JSON
                    query starts {
                        product(id: "gid://shopify/Product/$productId") {
                          images(first: 50) {
                            nodes {
                              id
                              url
                            }
                          }
                        }
                    }
                JSON;
            $productArr = $this->graphQlRequest($query, '/product/' . $productId . '.json');
            $thisProdImgs = $productArr['data']['product']['images']['nodes'];
        }
        if (isset($params['parent_product_id']) && $params['parent_product_id'] > 0) {
            $productId = $params['parent_product_id'];
            $query = <<<JSON
                    query starts {
                        product(id: "gid://shopify/Product/$productId") {
                          images(first: 50) {
                            nodes {
                              id
                              url
                            }
                          }
                        }
                    }
                JSON;
            $productArr = $this->graphQlRequest($query,  '/product/' . $productId . '.json');
            $parentProduct = $productArr['data']['product'];
        } else {
            $parentProduct = array();
        }
        //get all variant colors
        if (isset($params['color_images']) && !empty($params['color_images'])) {
            foreach ($params['color_images'] as $colorImg) {
                $colorVarArr[] = $colorImg['id'];
            }
        }

        $imgArr = array();
        foreach ($params['product_image_url'] as $key => $img) {
            $key = $key + 1;
            array_push($imgArr, array("originalSource" => $img, "mediaContentType" => "IMAGE"));
        }
        $imgCount = ($params['product_id'] == '' ? (count($imgArr) + 1) : (count($thisProdImgs) + 1));
        //get parent variant product images
        if ($params['product_id'] == '' && $params['ref_id'] > 0) {
            $selImgs = array();
            foreach ($parentProduct['images']['nodes'] as $prodImg) {
                foreach ($colorVarArr as $eachVarColor) {
                    if (strpos(strtolower($prodImg['url']), strtolower(str_replace("_", "", $eachVarColor))) !== false) {
                        $selImgs[] = array("originalSource" => $prodImg['url'], "mediaContentType" => "IMAGE");
                        $imgCount++;
                    }
                }
            }
            $imgArr = array_merge($imgArr, $selImgs);
        }

        if (isset($params['color_images'])) {
            $sides = array_column($params['color_images'], 'sides');
            $sides = array_merge(...$sides);
            $colorImage = [];
            $i = 1;
            foreach ($sides as $value) {
                if (!in_array($value, $params['product_image_url'])) {
                    $colorImage[] = ["originalSource" => $value, "mediaContentType" => "IMAGE"];
                    $i++;
                }
            }
            $imgArr = array_merge($imgArr, $colorImage);
        }

        //create  pre deco product
        $title = $this->shopify_body(addslashes($params['name']));
        $desc = $this->shopify_body(addslashes($params['description']));
        $refId = $params['ref_id'];
        $collectionId[] = $this->getPreDesignedCollectionId(); // Add pre-designed-collection-id
        // assign product to "Show in designer" collection if is customized is checked.
        if ($params['is_redesign'] == 1) {
            $collectionId[] = $this->getShowInDesignerId();
        }
        // assign categories one by one (collections)
        $smartCollectionIds = $this->getSmartCollections();
        if (!empty($params['categories'])) {
            foreach ($params['categories'] as $category) {
                if (!in_array($category['category_id'], $smartCollectionIds)) {
                    $collectionId[] = $category['category_id'];
                }
            }
        }
        foreach ($collectionId as $eachCol) {
            $collections[] = "\"gid://shopify/Collection/$eachCol\"";
        }
        $collections = "[" . implode(",", $collections) . "]";
        $position = [];
        //to format the attribute options as per requirement
        $options = [];
        $colorAttr = [];

        if (!empty($params['attributes'])) {
            foreach ($params['attributes'] as $key => $attribute) {
                $position[$key] = $attribute['attribute_name'];
                $option = [
                    "name" => $attribute['attribute_name'],
                    "position" => $key,
                    "values" => isset($attribute['attribute_options'][0]) ?  $attribute['attribute_options'][0] : null,
                ];
                $options[] = $option;
                $key++;
                if ($attribute['attribute_id'] == 'color') {
                    $colorAttr = $attribute['attribute_options'];
                }
            }
            foreach ($options as $eachOpt) {
                $optRes[] = "{name: \"{$eachOpt['name']}\", position: {$eachOpt['position']}, values: {name: \"{$eachOpt['values']}\"}}";
            }
            $options = "[" . implode(", ", $optRes) . "]";
        }

        $dupColor = [];
        $outputArr = [];

        foreach ($imgArr as $item) {
            $found = false;
            foreach ($colorAttr as $eachColor) {
                if (strpos(strtolower($item['originalSource']), strtolower(str_replace('_', '', $eachColor))) !== false && strpos(strtolower($item['originalSource']), '_front') !== false) {
                    if (!in_array($eachColor, $dupColor)) {
                        $dupColor[] = $eachColor;
                        $outputArr[] = "{originalSource: \"{$item['originalSource']}\", mediaContentType: {$item['mediaContentType']}, alt: \"{$eachColor}\"}";
                    }
                    $found = true;
                    break; // Exit inner loop once a match is found
                }
            }
            if (!$found) {
                $outputArr[] = "{originalSource: \"{$item['originalSource']}\", mediaContentType: {$item['mediaContentType']}}";
            }
        }

        $imagesInfo = "[" . implode(",", $outputArr) . "]";
        //Note: Product create with options only supports in 2024-04 and higher shopify version
        $query = <<<JSON
                    mutation CreatePredecoProduct {
                        productCreate(
                            input: {title: "$title", metafields: {namespace: "Pre-Deco", key: "imprint_design_id", value: "$refId", type: "number_integer"}, tags: "Pre-Deco", descriptionHtml: "$desc", collectionsToJoin: $collections,status: ACTIVE, productOptions: $options, productType: "$productType"}
                            media: $imagesInfo
                            )  {
                            product {
                                id
                                    media(first: 250) {
                                        edges {
                                        node {
                                            id
                                            alt
                                        }
                                        }
                                    }
                                    variants(first: 100) {
                                        edges {
                                            node {
                                                inventoryItem {
                                                    inventoryLevels(first: 100) {
                                                        edges {
                                                            node {
                                                                location {
                                                                id
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                            }
                        }
                    }
                JSON;

        $productCreate = $this->graphQlRequest($query);


        $newProduct = !empty($productCreate['data']['productCreate']['product']) ? $productCreate['data']['productCreate']['product'] : null;
        $prodId = end(explode('/', $newProduct['id']));
        $publicationId = $this->getPublicationId();
        //publish the created product to Online Store
        $query = <<<JSON
                    mutation starts {
                        publishablePublish(
                            id: "gid://shopify/Product/$prodId"
                            input: {publicationId: "$publicationId"}
                        ) {
                            userErrors {
                            message
                            }
                        }
                    }
                JSON;
        $this->graphQlRequest($query);

        //get mediaId to assign each variant
        $newProductImage = array();
        foreach ($newProduct['media']['edges'] as $img) {
            if (isset($img['node']['alt'])) {
                array_push($newProductImage, array("id" => $img['node']['id'],  "alt" => $img['node']['alt']));
            }
        }

        $variantArr = array();
        if (!empty($params['attributes'])) {
            $optionValues = array_column($params['attributes'], 'attribute_options');
            $variantCombinations = $this->variantCombinations($optionValues);
            foreach ($variantCombinations as $varKey => $eachVar) {
                $optItem = array();
                for ($i = 0; $i < count($position); $i++) {
                    $optItem[$position[$i]] = $eachVar[$i];
                }
                $varItem['price'] = $params['price'];
                $varItem['inventoryPolicy'] = "DENY";
                $varItem['optionValues'] = $optItem;
                $varItem['sku'] = $params['sku'] . "_" . $varKey;
                $varItem['quantity'] = $params['quantity'];
                $variantArr[] = $varItem;
            }
        }

        $locationId = $newProduct['variants']['edges'][0]['node']['inventoryItem']['inventoryLevels']['edges'][0]['node']['location']['id'];
        $duplicateColor = [];
        foreach ($variantArr as $varKey => $eachVar) {
            if ($varKey < 100) {
                $optionVal = [];
                foreach ($eachVar['optionValues'] as $key => $eachOpt) {
                    $optionVal[] = "{name: \"{$eachOpt}\", optionName: \"{$key}\"}";
                }
                $optionVal = "[" . implode(",", $optionVal) . "]";
                foreach ($newProductImage as $eachImg) {
                    if ($eachImg['alt'] != '' && ((strtolower($eachVar['optionValues']['Color']) == strtolower($eachImg['alt'])) || (strtolower($eachVar['optionValues']['color']) == strtolower($eachImg['alt']))) &&  !in_array(strtolower($eachImg['alt']), $duplicateColor)) {
                        $imgId = $eachImg['id'];
                        $duplicateColor[] = strtolower($eachImg['alt']);
                    }
                }
                $varRes[] = ($imgId != '') ?
                    "{price: {$eachVar['price']}, inventoryPolicy: {$eachVar['inventoryPolicy']},inventoryItem: {sku: \"{$eachVar['sku']}\",tracked: true}, optionValues: $optionVal,inventoryQuantities: {availableQuantity:{$eachVar['quantity']} , locationId: \"{$locationId}\"},mediaId: \"{$imgId}\"}" :
                    "{price: {$eachVar['price']}, inventoryPolicy: {$eachVar['inventoryPolicy']},inventoryItem: {sku: \"{$eachVar['sku']}\",tracked: true}, optionValues: $optionVal,inventoryQuantities: {availableQuantity:{$eachVar['quantity']} , locationId: \"{$locationId}\"}}";
            }
        }

        $variants = "[" . implode(",", $varRes) . "]";

        //update options and variants of the created product
        if (!empty($newProduct)) {
            $query = <<<JSON
                mutation variantCreate {
                    productVariantsBulkCreate(
                        productId: "gid://shopify/Product/$prodId"
                        strategy: REMOVE_STANDALONE_VARIANT
                        variants: $variants
                    ){
                        product {
                            id
                        }
                    }
                }
            JSON;
            $updateVariant = $this->graphQlRequest($query);
        }
        if (!empty($updateVariant['data']['productVariantsBulkCreate']['product'])) {
            $response = [
                'product_id' => $prodId,
            ];
        }
        return $response;
    }

    private function variantCombinations($arrays, $i = 0)
    {
        if (!isset($arrays[$i])) {
            return array();
        }
        if ($i == count($arrays) - 1) {
            return $arrays[$i];
        }

        // get combinations from subsequent arrays
        $tmp = $this->variantCombinations($arrays, $i + 1);
        $combinations = array();
        // concat each array from tmp with each element from $arrays[$i]
        foreach ($arrays[$i] as $v) {
            foreach ($tmp as $t) {
                $combinations[] = is_array($t) ?
                    array_merge(array($v), $t) :
                    array($v, $t);
            }
        }
        return $combinations;
    }

    /**
     * Creating predecorated product for simple product
     * This method will be optimised in future enhancement
     *
     * @author inkXE
     * @modified by pansy@imprintnext.com
     * @date 18 Dec 2019
     * @param array
     * @return array New product details
     */
    public function createSimpleDecoratedProduct($params)
    {
        $parentProductId = $params['parent_product_id'];
        $images = $params['product_image_url'];
        $prodId = 0;
        $query = <<<JSON
                    query starts {
                        product(id: "gid://shopify/Product/$parentProductId") {
                           images(first: 50) {
                                nodes {
                                    id
                                    url
                                }
                           }
                           variants(first: 100) {
                                nodes {
                                    selectedOptions {
                                    name
                                    value
                                    }
                                }
                            }
                            options(first: 50) {
                                name
                                values
                            }

                        }
                    }
                JSON;
        $productArr = $this->graphQlRequest($query, '/product/' . $parentProductId . '.json');
        $productInfo = $productArr['data']['product'];
        $thisProdImgs = array_column($productInfo['images']['nodes'], 'url');

        // get parent product images
        $imgArr = array();
        foreach ($images as  $img) {
            array_push($imgArr, array("originalSource" => $img, "mediaContentType" => "IMAGE"));
        }

        $imgCount = ($params['product_id'] == '' ? (count($imgArr) + 1) : (count($thisProdImgs) + 1));
        $selImgs = array();
        foreach ($thisProdImgs as $prodImg) {
            $selImgs[] = array("originalSource" => $prodImg, "mediaContentType" => "IMAGE");
            $imgCount++;
        }

        $imgArr = array_merge($imgArr, $selImgs);
        foreach ($imgArr as $item) {
            $outputArray[] = "{originalSource: \"{$item['originalSource']}\", mediaContentType: {$item['mediaContentType']}}";
        }
        $imagesInfo = "[" . implode(",", $outputArray) . "]";
        //create  pre deco product
        $title = $this->shopify_body(addslashes($params['name']));
        $desc = $this->shopify_body(addslashes($params['description']));
        $refId = $params['ref_id'];
        $collectionId[] = $this->getPreDesignedCollectionId(); // Add pre-designed-collection-id
        // assign product to "Show in designer" collection if is customized is checked.
        if ($params['is_redesign'] == 1) {
            $collectionId[] = $this->getShowInDesignerId();
        }
        // assign categories one by one (collections)
        $smartCollectionIds = $this->getSmartCollections();
        if (!empty($params['categories'])) {
            foreach ($params['categories'] as $category) {
                if (!in_array($category['category_id'], $smartCollectionIds)) {
                    $collectionId[] = $category['category_id'];
                }
            }
        }
        foreach ($collectionId as $eachCol) {
            $collections[] = "\"gid://shopify/Collection/$eachCol\"";
        }
        $collections = "[" . implode(",", $collections) . "]";
        $position = [];
        $options = '';

        //to format the options as per requirement
        if (strtolower($productInfo['options'][0]['name']) != 'title') {
            foreach ($productInfo['options'] as $key => $attribute) {
                $position[$key] = $attribute['name'];
                $option = [
                    "name" => $attribute['name'],
                    "position" => $key,
                    "values" => isset($attribute['values'][0]) ?  $attribute['values'][0] : null,
                ];
                $optionArr[] = $option;
                $key++;
            }
            foreach ($optionArr as $eachOpt) {
                $optRes[] = "{name: \"{$eachOpt['name']}\", position: {$eachOpt['position']}, values: {name: \"{$eachOpt['values']}\"}}";
            }
            $options = "[" . implode(", ", $optRes) . "]";
        }

        //Note: Product create with options only supports in 2024-04 and higher shopify version

        if ($options != '') {
            $query = <<<JSON
                    mutation CreatePredecoProduct {
                        productCreate(
                            input: {title: "$title", metafields: {namespace: "Pre-Deco", key: "imprint_design_id", value: "$refId", type: "number_integer"}, tags: "Pre-Deco", descriptionHtml: "$desc", collectionsToJoin: $collections,status: ACTIVE,productOptions: $options}
                            media: $imagesInfo
                            ) {
                            product {
                                id
                            }
                            userErrors {
                                message
                            }
                        }
                    }
                JSON;
        } else {
            $query = <<<JSON
                    mutation CreatePredecoProduct {
                        productCreate(
                            input: {title: "$title", metafields: {namespace: "Pre-Deco", key: "imprint_design_id", value: "$refId", type: "number_integer"}, tags: "Pre-Deco", descriptionHtml: "$desc", collectionsToJoin: $collections,status: ACTIVE}
                            media: $imagesInfo
                            ) {
                            product {
                                id
                            }
                            userErrors {
                                message
                            }
                        }
                    }
                JSON;
        }
        $productCreate = $this->graphQlRequest($query);
        $newProduct = !empty($productCreate['data']['productCreate']['product']) ? $productCreate['data']['productCreate']['product'] : null;
        $prodId = end(explode('/', $newProduct['id']));
        $publicationId = $this->getPublicationId();

        //publish the created product to Online Store
        $query = <<<JSON
                    mutation starts {
                        publishablePublish(
                            id: "gid://shopify/Product/$prodId"
                            input: {publicationId: "$publicationId"}
                        ) {
                            userErrors {
                            message
                            }
                        }
                    }
                JSON;
        $this->graphQlRequest($query);

        $isExtraAttr = false;
        if (strtolower($productInfo['variants']['nodes'][0]['selectedOptions'][0]['value']) !== 'default title') {
            $isExtraAttr = true;
            $optionValues = array_column($productInfo['options'], 'values');
            $variantCombinations = $this->variantCombinations($optionValues);
            foreach ($variantCombinations as $varKey => $eachVar) {
                $optItem = array();
                for ($i = 0; $i < count($position); $i++) {
                    $optItem[$position[$i]] = $eachVar[$i];
                }
                $varItem['price'] = $params['price'];
                $varItem['inventoryPolicy'] = "DENY";
                $varItem['optionValues'] = $optItem;
                $varItem['sku'] = $params['sku'] . "_" . $varKey;
                $variantArr[] = $varItem;
            }
        }

        if ($isExtraAttr) {
            foreach ($variantArr as $eachVar) {
                $optionVal = [];
                foreach ($eachVar['optionValues'] as $key => $eachOpt) {
                    $optionVal[] = "{name: \"{$eachOpt}\", optionName: \"{$key}\"}";
                }
                $optionVal = "[" . implode(",", $optionVal) . "]";
                $varRes[] = "{price: {$eachVar['price']}, inventoryPolicy: {$eachVar['inventoryPolicy']},inventoryItem: {sku: \"{$eachVar['sku']}\",tracked: true}, optionValues: $optionVal}";
            }
            $variants = "[" . implode(",", $varRes) . "]";

            //update options and variants of the created product

            $query = <<<JSON
                mutation variantCreate {
                    productVariantsBulkCreate(
                        productId: "gid://shopify/Product/$prodId"
                        strategy: REMOVE_STANDALONE_VARIANT
                        variants: $variants
                    ){
                        userErrors {
                            message
                        }
                    }
                }
            JSON;
            $updateVariant = $this->graphQlRequest($query);
        }
        //get product variants inventory details of the new created product
        $query = <<<JSON
                        query getProduct {
                            product(id: "gid://shopify/Product/$prodId") {
                                variants(first: 100) {
                                    nodes {
                                        id
                                        inventoryItem {
                                            id
                                            tracked
                                            inventoryLevels(first: 100) {
                                                nodes {
                                                location {
                                                    id
                                                }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    JSON;
        $getVariantsArr = $this->graphQlRequest($query);
        $getVariants = $getVariantsArr['data']['product']['variants']['nodes'];
        if ($getVariants[0]['inventoryItem']['tracked'] != 1) { //update variants in case of default title
            $sku = $params['sku'] . "_" . 0;
            $query = <<<JSON
            mutation variantUpadte {
                productVariantsBulkUpdate(
                    productId: "gid://shopify/Product/$prodId"
                    variants: {id: "{$getVariants[0]['id']}", inventoryItem: {tracked: true, sku: "$sku"}, inventoryPolicy: DENY, price: "{$params['price']}"}
                ) {
                    productVariants {
                    id
                    }
                    userErrors {
                    message
                    }
                }
                }
            JSON;
            $updateVariant = $this->graphQlRequest($query);
        }
        foreach ($getVariants as $eachVar) {
            //update inventory levels
            $query = <<<JSON
                            mutation updateInventory {
                                inventoryAdjustQuantities(
                                    input: {changes: {delta: {$params['quantity']}, inventoryItemId: "{$eachVar['inventoryItem']['id']}", locationId: "{$eachVar['inventoryItem']['inventoryLevels']['nodes'][0]['location']['id']}"}, name: "available", reason: "correction"}
                                ) {
                                    inventoryAdjustmentGroup {
                                    id
                                    }
                                    userErrors {
                                    message
                                    }
                                }
                            }
                        JSON;
            $this->graphQlRequest($query);
        }

        $response =  [
            'product_id' => $prodId,
        ];
        return $response;
    }

    /**
     * GET: Variant information by ID
     *
     * @author inkXE
     *
     * @modified by divya@imprintnext.com
     * @date 18 Dec 2019
     * @param $variant variant ID
     * @return array New product details
     */
    public function getVariantShortInfo($variant)
    {
        $variantID = $variant['variantID'];
        $productId = $variant['productID'];
        $productQuery = <<<JSON
        query productdetails {
            product(id: "gid://shopify/Product/$productId") {
              id
              title
              descriptionHtml
              createdAt
              images(first: 250) {
                    nodes {
                         id
                         url
                 }
               }
              variants(first: 250) {
                  nodes {
                    id
                    title
                    price
                    sku
                    position
                    inventoryPolicy
                    createdAt
                    updatedAt
                    inventoryQuantity
                    image {
                        id
                        url
                    }
                    selectedOptions {
                      name
                      value
                      optionValue {
                        id
                        name
                    }
                  }
                }
              }
               options(first: 100) {
                    id
                    position
                    name
                    values
                }
                variantsCount {
                        count
                    }
             }
          }
        JSON;
        $productData = $this->graphQlRequest($productQuery, '/product/' . $productId . '.json'); //read from product saved cache
        $product = $productData['data']['product'];

        if ($variantID == $productId) {
            $variantID = $this->getNumericData($product['variants']['nodes'][0]['id']);
        }
        $variant = $product['variants']['nodes'][0];
        if (SHOPIFY_VARIANTS_PLUGIN != 1) {
            $getVariantQuery = <<<JSON
                            query getSelectedVar {
                                productVariant(id: "gid://shopify/ProductVariant/$variantID") {
                                    id
                                    price
                                    sku
                                    title
                                    selectedOptions {
                                    name
                                    value
                                    }
                                    image{
                                        id
                                        url
                                    }
                                }
                              }
                        JSON;
            $getVariantData = $this->graphQlRequest($getVariantQuery);
            $variant = $getVariantData['data']['productVariant'];
        } else {
            $variant = $product['variants']['nodes'][$variantID - 1];
        }
        // print_r($variant);
        // exit;

        $colorPos = $this->getAttributePostion($this->colorAttrName, $productId);
        $this->getAttributePostion($this->sizeAttrName, $productId);

        // for tier price


        $tierPriceData = array();
        $commonTierPrice = array();
        $variantTierPrice = array();
        $sameforAllVariants = $isTier = false;
        $shopifyDiscountPath = ASSETS_PATH_W . 'products/discount/';
        $thisProdDiscountFile = $shopifyDiscountPath . $productId . ".json";

        if (file_exists($thisProdDiscountFile)) {
            $tierPriceData = json_clean_decode(file_get_contents($thisProdDiscountFile));

            $isTier = true;

            // little confusion with the key here but was done as sent from admin form field
            if ($tierPriceData['pricing_per_variants'] == 'true') {
                $sameforAllVariants = true;
                foreach ($tierPriceData['price_rules'][0]['discounts'] as $discount) {
                    $commonTierPrice[] = array(
                        "upper_limit" => $discount['upper_limit'],
                        "lower_limit" => $discount['lower_limit'],
                        "discount" => $discount['discount'],
                        "discountType" => $tierPriceData['discount_type']
                    );
                }
            } else {
                foreach ($tierPriceData['price_rules'] as $var) {
                    if ($var['id'] == $variantID) {
                        foreach ($var['discounts'] as $discount) {
                            $variantTierPrice[$this->getNumericData($variant['id'])][] = array(
                                "upper_limit" => $discount['upper_limit'],
                                "lower_limit" => $discount['lower_limit'],
                                "discount" => $discount['discount'],
                                "discountType" => $tierPriceData['discount_type']
                            );
                        }
                    }
                }
            }
        }

        foreach ($product['images']['nodes'] as $pi) {
            $id = $this->getNumericData($pi['id']);
            $images[$id] = $pi;
            $images[$pi['id']]['variant_ids'] = [];
        }

        //to add the applicable variantIds to each image node

        foreach ($product['variants']['nodes'] as $variantInfo) {
            if (!empty($variantInfo['image']) && array_key_exists($variantInfo['image']['id'], $images)) {
                foreach ($images as $pimg) {
                    if (!in_array($variantInfo['id'], $images[$variantInfo['image']['id']]['variant_ids'])) {
                        $images[$variantInfo['image']['id']]['variant_ids'][] = $variantInfo['id'];
                    }
                }
            }
        }

        $variantDetails = array();

        $productType = (strpos(strtolower($variant['title']), 'default title') !== false ? "simple" : "variable");

        if (!empty($variant)) {

            $variantDetails['name'] = $product['title'];
            $variantDetails['price'] = $variant['price'];
            $variantDetails['attributes'] = array();
            // position value is increamented+1 while saving as json
            $attributeNames = array_column($product['options'], 'name');
            if (!empty($attributeNames)) {
                array_walk($attributeNames, function (&$name) {
                    $name = strtolower($name);
                });
                // keep the color at the begining
                $colorAttrPos = array_search($this->colorAttrName, $attributeNames);
                if ($colorAttrPos !== false) {
                    $colorOption = [$colorAttrPos => $attributeNames[$colorAttrPos]];
                    unset($attributeNames[$colorAttrPos]);
                    $attributeNames = $colorOption + $attributeNames;
                }
                foreach ($attributeNames as $position => $attributeName) {
                    $optionName = $product['options'][$position]['name'];
                    foreach ($variant['selectedOptions'] as $optionsVal) {
                        if ($optionName == $optionsVal['name']) {
                            $variantOption =  $optionsVal['value'];
                        }
                    }

                    if (strtolower($variantOption) != "default title") {
                        $variantDetails['attributes'][$attributeName] = [
                            'id' => strtolower($variantOption),
                            'name' => $variantOption,
                            'attribute_id' => $attributeName
                        ];
                    }
                    if (!isset($variantOption)) {
                        $selectedOptions = $product['variants']['nodes'][0]['selectedOptions'];
                        foreach ($selectedOptions as $key => $option) {
                            $variantDetails['attributes'][strtolower($option['name'])] = [
                                'id' => strtolower($option['name']) == 'color' ? $option['value'] : $key + 1,
                                'name' => $option['value'],
                                'attribute_id' => strtolower($option['value'])
                            ];
                        }
                    }
                }

                if ($isTier) {
                    $variantDetails['tier_prices'] = ($sameforAllVariants === true ? $this->createTierPrice($commonTierPrice, $variant['price']) : $this->createTierPrice($variantTierPrice[$this->getNumericData($variant['id'])], $variant['price']));
                }
                $variantDetails['images'] = array();
                $variantDetails['categories'] = $this->getProductCategories($productId);
                $thisProdType = (strpos(strtolower($variant['title']), 'default title') !== false ? "simple" : "configurable");
                if ($variantID == $productId) {
                    $thisProdType = "simple";
                }

                // if image is set on the custom variant (StoreProductController will handle the images )
                if (!empty($variant['imp_image_id'])) {
                    $variantDetails['imp_image_id'] = $variant['imp_image_id'];
                    return $variantDetails;
                }
                if ($colorPos > 0) {
                    foreach ($variant['selectedOptions'] as $optionData) {
                        if (strtolower($optionData['name']) == strtolower($this->colorAttrName)) {
                            $color_look =  $this->removeSPLChars($optionData['value']);
                            $color_lookup = ($thisProdType == 'simple' ? '_' : $color_look);
                        }
                    }
                } else {
                    // if color is not available first option would be searched in image name
                    // $color_lookup = "_" . $this->removeSPLChars($variant['selectedOptions'][0]['value']) . "_";
                    $color_lookup = $this->removeSPLChars($variant['selectedOptions'][0]['value']) . "_";
                }


                $variantDetails['color_lookup'] = $color_lookup;
                $variantImageID = ($this->getNumericData($variant['image']['id']) ?
                    $this->getNumericData($variant['image']['id']) : $this->getNumericData($product['images']['nodes'][0]['id']));

                // get variant images
                if (isset($images) && $variantImageID && array_key_exists($variantImageID, $images)) {
                    foreach ($images as $pimg) {
                        if (!empty($pimg['variant_ids'])) {
                            if (in_array($variant['id'], $pimg['variant_ids'])) {
                                $unassignedImgs['id'] = $this->getNumericData($pimg['id']);
                                $unassignedImgs['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                                $unassignedImgs['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                            }
                        }

                        $thisImage = array();
                        if ($this->str_contains_all(strtolower($pimg['url']), array($color_lookup, "front"))) {
                            $thisImage['id'] = $this->getNumericData($pimg['id']);
                            $thisImage['labels'] = "Front";
                            $thisImage['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                            $thisImage['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                        } elseif ($this->str_contains_all(strtolower($pimg['url']), array($color_lookup, "left"))) {
                            $thisImage['id'] = $this->getNumericData($pimg['id']);
                            $thisImage['labels'] = "Left";
                            $thisImage['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                            $thisImage['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                        } elseif ($this->str_contains_all(strtolower($pimg['url']), array($color_lookup, "right"))) {
                            $thisImage['id'] = $this->getNumericData($pimg['id']);
                            $thisImage['labels'] = "Right";
                            $thisImage['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                            $thisImage['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                        } elseif ($this->str_contains_all(strtolower($pimg['url']), array($color_lookup, "back"))) {
                            $thisImage['id'] = $this->getNumericData($pimg['id']);
                            $thisImage['labels'] = "Back";
                            $thisImage['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                            $thisImage['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                        } elseif ($this->str_contains_all(strtolower($pimg['url']), array($color_lookup, "top"))) {
                            $thisImage['id'] = $this->getNumericData($pimg['id']);
                            $thisImage['labels'] = "Top";
                            $thisImage['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                            $thisImage['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                        } elseif ($this->str_contains_all(strtolower($pimg['url']), array($color_lookup, "bottom"))) {
                            $thisImage['id'] = $this->getNumericData($pimg['id']);
                            $thisImage['labels'] = "Bottom";
                            $thisImage['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                            $thisImage['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                        } else {
                            $thisImage = [];
                        }
                        if (!empty($thisImage)) {
                            $variantDetails['images'][] = $thisImage;
                        }
                    }
                } else {
                    if ($variant['request'] == 'quote') {
                        $thisImage['thumbnail'] = array($product['image']['src']);
                        $thisImage['src'] = array($product['image']['src']);
                        $thisImage['labels'] = "Front";
                        $variantDetails['images'][] = $thisImage;
                    } else {
                        $thisImage['thumbnail'] = array();
                        $thisImage['src'] = array();
                        $thisImage['labels'] = "";
                        $variantDetails['images'][] = $thisImage;
                    }
                }

                   //for simple pre decorated products
               $product['images']['nodes'] = array_filter($product['images']['nodes'], function($item) {
                     $filename = basename(parse_url($item['url'], PHP_URL_PATH));
                        return !preg_match('/^\d+/', $filename);
                    });

                $product['images']['nodes'] = array_values($product['images']['nodes']);


                if (empty($unassignedImgs) || $productType == 'simple') {
                    $imgLen = (count($product['images']['nodes']) > 4) ? 4 : count($product['images']['nodes']);
                    for ($in = 0; $in < $imgLen; $in++) {
                        if (isset($product['images']['nodes'][$in])) {
                            $unassignedImg['id'] =  $this->getNumericData($product['images']['nodes'][$in]['id']);
                            $unassignedImg['src'] = self::shopify_image($product['images']['nodes'][$in]['url'], $this->fullSize);
                            $unassignedImg['thumbnail'] = self::shopify_image($product['images']['nodes'][$in]['url'], $this->thumbSize);
                        }
                        $unassignedImgs[] = $unassignedImg;
                    }
                }

                if (empty($variantDetails['images'])) {
                    $variantDetails['images'] = $unassignedImgs;
                }
            }
        } else {
            $variantDetails = [];
        }
        return $variantDetails;
    }

    private function str_contains_all($haystack, array $needles)
    {
        foreach ($needles as $needle) {
            if (strpos($haystack, $needle) === false) {
                return false;
            }
        }
        return true;
    }

    /**
     * retrieve images from store
     *
     * @param string $src
     * @param string $size
     * @return string
     */
    private static function shopify_image($src, $size)
    {
        if (empty($size) || strpos($src, '/assets/products/') !== false) {
            return $src;
        }

        $img_path = pathinfo($src);
        return str_replace("." . $img_path['extension'], "_" . $size . "." . $img_path['extension'], $src);
    }

    /**
     * GET: product color options
     *
     * @author inkXE
     * @modified by pansy@imprintnext.com
     * @date 18 Dec 2019
     * @param $filter variant information
     * @return array colors details
     */
    public function getColorOptions($filter)
    {
        $productId = $filter['product_id'];
        $productQuery = <<<JSON
                    query starts {
                        product(id: "gid://shopify/Product/$productId") {
                          id
                          variants(first: 250) {
                                nodes {
                                    title
                                    id
                                    price
                                    inventoryPolicy
                                    inventoryQuantity
                                    inventoryItem {
                                        tracked
                                    }
                                    image {
                                        id
                                    }
                                    selectedOptions {
                                        name
                                        value
                                    }
                                }
                            }
                          images(first: 250) {
                            nodes {
                              id
                              url
                            }
                          }
                          options {
                            id
                            position
                            name
                            values
                          }
                        }
                    }
                JSON;
        $productArr = $this->graphQlRequest($productQuery, '/product/' . $productId . '.json');
        $product = $productArr['data']['product'];

        foreach ($product['images']['nodes'] as $pi) {
            $images[$pi['id']] = $pi;
            $images[$pi['id']]['variant_ids'] = [];
        }
        //to add the applicable variantIds to each image node
        foreach ($product['variants']['nodes'] as $variant) {
            if (!empty($variant['image']) && array_key_exists($variant['image']['id'], $images)) {
                foreach ($images as $pimg) {
                    if (!in_array($variant['id'], $images[$variant['image']['id']]['variant_ids'])) {
                        $images[$variant['image']['id']]['variant_ids'][] = $variant['id'];
                    }
                }
            }
        }

        $colorPos = $this->getAttributePostion($this->colorAttrName, $productId);
        if (empty($colorPos)) {
            $colorPos = 1;
        }
        $colorVariants = array();
        $thisProductColors = array();
        // for tier price

        $tierPriceData = array();
        $commonTierPrice = array();
        $variantTierPrice = array();
        $sameforAllVariants = $isTier = false;

        $shopifyDiscountPath = ASSETS_PATH_W . 'products/discount/';
        $thisProdDiscountFile = $shopifyDiscountPath . $productId . ".json";

        if (file_exists($thisProdDiscountFile)) {
            $tierPriceData = json_clean_decode(file_get_contents($thisProdDiscountFile));
            $isTier = true;
            // little confusion with the key here but was done as sent from admin form field
            if ($tierPriceData['pricing_per_variants'] == 'true') {
                $sameforAllVariants = true;
                foreach ($tierPriceData['price_rules'][0]['discounts'] as $discount) {
                    $commonTierPrice[] = array(
                        "upper_limit" => $discount['upper_limit'],
                        "lower_limit" => $discount['lower_limit'],
                        "discount" => $discount['discount'],
                        "discountType" => $tierPriceData['discount_type']
                    );
                }
            } else {
                foreach ($tierPriceData['price_rules'] as $variant) {
                    foreach ($variant['discounts'] as $discount) {
                        $variantTierPrice[$variant['id']][] = array(
                            "upper_limit" => $discount['upper_limit'],
                            "lower_limit" => $discount['lower_limit'],
                            "discount" => $discount['discount'],
                            "discountType" => $tierPriceData['discount_type']
                        );
                    }
                }
            }
        }
        if ($colorPos !== 1) {
            foreach ($product['options'] as $key => $productOption) {
                if ($productOption['position'] == $colorPos) {
                    $selectedAttrKey = $key;
                    $attributeData = [
                        "name" => $productOption['name'],
                        "attribute_id" => strtolower($productOption['name'])
                    ];
                }
            }
        } else {
            $selectedAttrKey = 0;
            $attributeData = [
                "name" => $product['options'][0]['name'],
                "attribute_id" => strtolower($product['options'][0]['name'])
            ];
        }

        $colorExist = 0;
        foreach ($product['options'] as $optionsValues) {
            if (strtolower($optionsValues['name']) == strtolower($this->colorAttrName)) {
                $colorExist = 1;
                break;
            }
        }

        // for tier price
        $colorName = '';

        foreach ($product['variants']['nodes'] as $variant) {

             // If the first selected option is size, then find and use color; otherwise, use the first available value.
            if (isset($variant['selectedOptions'][0]['name']) && strtolower($variant['selectedOptions'][0]['name']) == strtolower($this->sizeAttrName)) {
                $colorName = '';
                foreach ($variant['selectedOptions'] as $choosedOption) {
                    if (strtolower($choosedOption['name']) == strtolower($this->colorAttrName)) {
                        $colorName = $choosedOption['value'];
                        break;
                    }
                }
                if ($colorName === '') {
                    $colorName = $variant['selectedOptions'][0]['value'];
                }
            } else {
                foreach ($variant['selectedOptions'] as $choosedOption) {
                    if (strtolower($choosedOption['name']) == strtolower($this->colorAttrName)) {
                        $colorName = $choosedOption['value'];
                        break;
                    }else {
                        $colorName = $choosedOption['value'];
                    }
                }
            }
            //echo $colorName;exit;
            $productType = (strpos(strtolower($variant['title']), 'default title') !== false ? "simple" : "variable");
            if (!in_array($colorName, $thisProductColors) && $variant['title'] != "Default Title") {
                $thisProductColors[] = $colorName; // color should be unique
                $thisColorVar = [
                    'id' => str_replace([' ', '/'], '_', strtolower($colorName)),
                    'name' => $colorName,
                    'variant_id' => end(explode('/', $variant['id'])),
                    'price' => $variant['price'],
                    'attrbitue_name' => $this->colorAttrName,
                    'inventory' => [
                        'stock' => (strtolower($variant['inventoryPolicy']) == "continue" || empty($variant['inventoryItem']['tracked']) ? 100000 : $variant['inventoryQuantity']),
                        'min_quantity' => 1,
                        'max_quantity' => 10000,
                        'quantity_increments' => 1
                    ],
                    'sides' => [], // get variant images
                    "attribute" => $attributeData
                ];
                if ($isTier) {
                    $thisColorVar['tier_prices'] = ($sameforAllVariants === true ? $this->createTierPrice($commonTierPrice, $variant['price']) : $this->createTierPrice($variantTierPrice[end(explode('/', $variant['id']))], $variant['price']));
                }

                if (empty($variant['imp_image_id'])) {
                    if ($colorExist > 0) {
                        $color_look = $this->removeSPLChars($colorName);
                        $color_lookup = ($colorName != '' ? $color_look : '_');
                    } else {
                        // if color is not available first option would be searched in image name
                        $color_lookup =  $this->removeSPLChars($variant['selectedOptions'][0]['value']) . "_";
                    }
                    $thisColorVar['color_lookup'] = $color_lookup;

                    $variantImageID = ($variant['image']['id'] ? $variant['image']['id'] : $product['images']['nodes'][0]['id']);
                    if (isset($images) && $variantImageID && array_key_exists($variantImageID, $images)) {
                        $unassignedImgs = [];
                        foreach ($images as $pimg) {
                            if (in_array($variant['id'], $pimg['variant_ids']) && !in_array($pimg['url'], array_column($unassignedImgs, 'src'))) {
                                $unassignedImg['labels'] = "front";
                                //$unassignedImg['id'] = $this->getNumericData($pimg['id']);
                                $unassignedImg['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                                $unassignedImg['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                                $unassignedImgs[] = $unassignedImg;
                            }
                            $thisImage = array();
                            if ($this->str_contains_all(strtolower($pimg['url']), array($color_lookup, "front"))) {
                                $thisImage['labels'] = "Front";
                                $thisImage['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                                $thisImage['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                            } elseif ($this->str_contains_all(strtolower($pimg['url']), array($color_lookup, "left"))) {
                                $thisImage['labels'] = "Left";
                                $thisImage['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                                $thisImage['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                            } elseif ($this->str_contains_all(strtolower($pimg['url']), array($color_lookup, "right"))) {
                                $thisImage['labels'] = "Right";
                                $thisImage['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                                $thisImage['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                            } elseif ($this->str_contains_all(strtolower($pimg['url']), array($color_lookup, "back"))) {
                                $thisImage['labels'] = "Back";
                                $thisImage['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                                $thisImage['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                            } elseif ($this->str_contains_all(strtolower($pimg['url']), array($color_lookup, "top"))) {
                                $thisImage['labels'] = "Top";
                                $thisImage['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                                $thisImage['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                            } elseif ($this->str_contains_all(strtolower($pimg['url']), array($color_lookup, "bottom"))) {
                                $thisImage['labels'] = "Bottom";
                                $thisImage['src'] = self::shopify_image($pimg['url'], $this->fullSize);
                                $thisImage['thumbnail'] = self::shopify_image($pimg['url'], $this->thumbSize);
                            } else {
                                $thisImage = array();
                            }
                            if (!empty($thisImage)) {
                                $thisColorVar['sides'][] = array('image' => $thisImage);
                            }
                        }
                    } else {
                        if ($variant['request'] == 'quote') {
                            $thisImage['thumbnail'] = array($product['images']['nodes'][0]['url']);
                            $thisImage['src'] = array($product['image']['nodes'][0]['url']);
                            $thisImage['labels'] = "Front";
                            $thisColorVar['sides'][] = array('image' => $thisImage);
                        } else {
                            $thisImage['thumbnail'] = array();
                            $thisImage['src'] = array();
                            $thisImage['labels'] = "";
                            $thisColorVar['sides'][] = array('image' => $thisImage);
                        }
                    }
                    if (empty($unassignedImgs) || $productType == 'simple') {
                        $imgLen = (count($product['images']['nodes']) > 4) ? 4 : count($product['images']['nodes']);
                        for ($i = 0; $i < $imgLen; $i++) {
                            // $unassignedImg['id'] = $this->getNumericData($product['images']['nodes'][$i]['id']);
                            $unassignedImg['labels'] = "front";
                            $unassignedImg['src'] = self::shopify_image($product['images']['nodes'][$i]['url'], $this->fullSize);
                            $unassignedImg['thumbnail'] = self::shopify_image($product['images']['nodes'][$i]['url'], $this->thumbSize);
                            $unassignedImgs[] = $unassignedImg;
                        }
                    }

                    if (empty($thisColorVar['sides'])) {
                        foreach ($unassignedImgs as $eachunassignedImg) {
                            $thisColorVar['sides'][] = array('image' => $eachunassignedImg);
                        }
                    }
                } else {
                    $thisColorVar['imp_image_id'] = $variant['imp_image_id'];
                }
                $colorVariants[] = $thisColorVar;
            }
        }


        if ($colorExist == 1 && $filter['is_admin'] == 1) {
            return $colorVariants;
        } elseif ($filter['is_admin'] == 1) {
            return $colorVariants = [];
        }
        return $colorVariants;
    }

    /**
     * GET: product variant inventory
     *
     * @author inkXE
     * @date 18 Dec 2019
     * @param $params variant information
     * @return array variant inventory
     */
    public function getVariantInventory($params)
    {
        $productId = $params['productId'];
        $variantId = $params['variantId'];
        $product = $this->call('GET', '/admin/products/' . $productId . '.json');
        if ($variantId == $productId) {
            $variantID = $product['variants'][0]['id'];
        }
        $variant = $this->call('GET', '/admin/variants/' . $variantId . '.json');
        $colorPos = $this->getAttributePostion($this->colorAttrName, $productId);
        $sizePos = $this->getAttributePostion($this->sizeAttrName, $productId);
        $targetColor = $variant['option' . $colorPos];
        $quantities = array();
        if ($variantID != $productId) {
            foreach ($product['variants'] as $variant) {
                if ($variant['option' . $colorPos] == $targetColor) {
                    $thisVariant = array();
                    $thisVariant['variant_id'] = $variant['id'];
                    $thisVariant['price'] = $variant['price'];
                    $thisVariant['inventory']['stock'] = ($variant['inventory_policy'] == "continue" || empty($variant['inventory_management']) ? 100000 : $variant['inventory_quantity']);
                    $thisVariant['inventory']['min_quantity'] = 1;
                    $thisVariant['inventory']['max_quantity'] = 10000;
                    $thisVariant['inventory']['quantity_increments'] = 1;
                    $thisVariant['attributes']['color_id'] = $variant['option' . $colorPos];
                    $thisVariant['attributes']['color'] = $variant['option' . $colorPos];
                    $thisVariant['attributes']['size_id'] = $variant['option' . $sizePos];
                    $thisVariant['attributes']['size'] = $variant['option' . $sizePos];
                    $thisVariant['tier_prices'] = array();
                    $quantities[] = $thisVariant;
                }
            }
        } else {
            $thisVariant = array();
            $thisVariant['variant_id'] = $variant['id'];
            $thisVariant['price'] = $variant['price'];
            $thisVariant['inventory']['stock'] = ($variant['inventory_policy'] == "continue" || empty($variant['inventory_management'])  ? 100000 : $variant['inventory_quantity']);
            $thisVariant['inventory']['min_quantity'] = 1;
            $thisVariant['inventory']['max_quantity'] = 10000;
            $thisVariant['inventory']['quantity_increments'] = 1;
            $thisVariant['attributes']['color_id'] = $variant['option' . $colorPos];
            $thisVariant['attributes']['color'] = $variant['option' . $colorPos];
            $thisVariant['attributes']['size_id'] = $variant['option' . $sizePos];
            $thisVariant['attributes']['size'] = $variant['option' . $sizePos];
            $thisVariant['tier_prices'] = array();
            $quantities[] = $thisVariant;
        }
        return $quantities;
    }

    /**
     * GET: parent variant details
     *
     * @author inkXE
     * @date 18 Dec 2019
     * @param $productId requested product ID
     * @return string parent variant ID
     */
    public function getParentVariantID($variantID)
    {
        if (is_numeric($variantID)) {
            $variantQuery = <<<JSON
                query variantquery {
                    productVariant(id: "gid://shopify/ProductVariant/$variantID") {
                            id
                           product {
                            id
                               }
                            }
                        }
            JSON;
            $variant = $this->graphQlRequest($variantQuery);
            $thisProductID = $this->getNumericData($variant['data']['productVariant']['product']['id']);
            $metaDataInfo = <<<JSON
                    query metaData {
                                product(id: "gid://shopify/Product/$thisProductID") {
                                id
                                metafields(first: 10) {
                                        edges {
                                            node {
                                            value
                                    }
                                }
                            }
                        }
                    }
             JSON;
            $metaDataDetails = $this->graphQlRequest($metaDataInfo);
            $metaData = $metaDataDetails['data']['product']['metafields']['edges'];
            if (!empty($metaData)) {
                $idRelation = json_decode($metaData[0]['node']['value'], true);
            }
            $parentVarID = $idRelation[$variantID];
            $productType = $idRelation['product_type'];
            if ($productType == 'simple') {
                $productDetailsQuery = <<<JSON
                                query productQuery {
                                    product(id: "gid://shopify/Product/$parentVarID") {
                                        id
                                        variants(first: 50) {
                                            edges {
                                                node {
                                                    id
                                                }
                                            }
                                        }
                                    }
                                }
                JSON;
                $productDetails = $this->graphQlRequest($productDetailsQuery);
                $parentVarID = $this->getNumericData($productDetails['data']['product']['variants']['edges'][0]['node']['id']);
            } else {
                if (!is_numeric($parentVarID)) {
                    $parentVarID = $variantID;
                }
            }
        } else {
            $parentVarID = $variantID;
        }
        return $parentVarID;
    }

    public function shopifyParentProductID($variantID)
    {
        $variantQuery = <<<JSON
            query MyQuery {
            productVariant(id: "gid://shopify/ProductVariant/$variantID") {
                product {
                id
              }
            }
        }
        JSON;
        $variantDetails = $this->graphQlRequest($variantQuery);
        $variant = $variantDetails['data'];
        $thisProductData['pid'] = $this->getNumericData($variant['productVariant']['product']['id']);
        $thisProductData['vid'] = $this->getParentVariantID($variantID);
        return json_encode($thisProductData);
    }

    /**
     * GET: all variant list
     *
     * @author inkXE
     * @date 23 July 2020
     * @param $productId requested product ID
     * @return arrau list of variants
     */
    public function getStoreVariants($productId)
    {
        $variants = [];
        $productQuery = <<<JSON
                query productVariantDetails {
                    product(id: "gid://shopify/Product/$productId") {
                        id
                        variants(first: 30) {
                                nodes {
                                    id
                                    title
                                    price
                                    sku
                                    inventoryQuantity
                                    selectedOptions {
                                            name
                                            value
                                }
                            }
                        }
                    }
                }
            JSON;
        $product = $this->graphQlRequest($productQuery, '/product/' . $productId . '.json');
        $productVariants = $product['data']['product']['variants']['nodes'];
        if (!empty($product)) {
            foreach ($productVariants as $variant) {
                if ($variant['title'] != "Default Title") {
                    $thisVariant = [
                        'id' => $this->getNumericData($variant['id']),
                        'title' => $variant['title'],
                        'price' => $variant['price'],
                        'sku' => $variant['sku'],
                        'inventory' => $variant['inventoryQuantity'],
                    ];
                    foreach ($variant['selectedOptions'] as $selectedOptions) {
                        if (strtolower($selectedOptions['name']) == 'size') {
                            $thisVariant['size'] = $selectedOptions['value'];
                        }
                        if (strtolower($selectedOptions['name']) == strtolower($this->colorAttrName)) {
                            $thisVariant['color'] = $selectedOptions['value'];
                        }
                    }
                    $variants[] = $thisVariant;
                }
            }
        }
        return $variants;
    }

    /*
     *Get Tier discount
     *@modified by pansy@imprintnext.com
    */
    public function getTierDiscounts($productId)
    {
        $tierDiscounts = array();
        $shopifyDiscountPath = ASSETS_PATH_W . 'products/discount/';
        if (is_dir($shopifyDiscountPath)) {
            $thisProdDiscountFile = $shopifyDiscountPath . $productId . ".json";
            $tierDiscounts = json_clean_decode(file_get_contents($thisProdDiscountFile));
        }

        $product = $this->getProductDetails($productId);
        $tierDiscounts['name'] = $product['title'];
        $tierDiscounts['price'] = $product['variants']['nodes'][0]['price'];
        return $tierDiscounts;
    }



    /**
     * Save tier price discount in shopify store
     *
     * @author pansy@imprintnext.com
     * @date  27 Dec 2024
     * @return true/false
     */

    public function saveProductTierPrice($tierData)
    {

        $saveStatus = false;
        $prodId = "gid://shopify/Product/" . $tierData['productID'];
        $ids = [];
        $ids[] = $prodId;
        $variantDets = $this->getProductDetails($this->getNumericData($prodId));
        if (!empty($variantDets['variants'])) {
            foreach ($variantDets['variants']['nodes'] as $eachVar) {
                $ids[] = $eachVar['id'];
            }
        }

        $getAutomaticDiscounts = $this->getAutomaticDiscounts();

        if (!isset($getAutomaticDiscounts)) {
            $saveStatus = true;
        }

        $discountIds = [];
        //delete the discounts if product already exists with tier pricing
        if ($getAutomaticDiscounts) {
            foreach ($getAutomaticDiscounts as $eachAutoDisc) {
                if ($eachAutoDisc['automaticDiscount']['customerGets']['items']) {
                    $addedProds = array_column($eachAutoDisc['automaticDiscount']['customerGets']['items']['products']['nodes'], 'id');
                    if (empty($addedProds)) {
                        $addedProds = array_column($eachAutoDisc['automaticDiscount']['customerGets']['items']['productVariants']['nodes'], 'id');
                    }
                    foreach ($ids as $eachId) {
                        if (in_array($eachId, $addedProds)) {
                            $discountIds[] = $eachAutoDisc['id'];
                        }
                    }
                }
            }
        }

        // print_r($discountIds);exit;

        if ($discountIds && !empty($discountIds)) {
            $discountIds = "\$ids: [ID!] =[" . implode(",", array_map(fn($id) => '"' . $id . '"', $discountIds)) . "]";
            $deleteAutoDiscQuery = <<<JSON
                    mutation discountAutomaticBulkDelete($discountIds) {
                        discountAutomaticBulkDelete(ids: \$ids) {
                            userErrors {
                                code
                                field
                                message
                            }
                            }
                        }
                    JSON;
            $deleteAutoDisc = $this->graphQlRequest($deleteAutoDiscQuery);
            if (empty($deleteAutoDisc['discountAutomaticBulkDelete']['userErrors'])) {
                $shopifyDiscountPath = ASSETS_PATH_W . 'products/discount/';
                $thisProdDiscountFile = $shopifyDiscountPath . $tierData['productID'] . ".json";
                unlink($thisProdDiscountFile);
            }
            $saveStatus = true;
        } else {
            $saveStatus = true;
        }

        if (!empty($tierData['price_rules'])) {
            $date = date('Y-m-d\T00:00:00\Z');
            foreach ($tierData['price_rules'] as  $key => $discount) {
                foreach ($discount['discounts'] as  $disKey => $eachDiscount) {
                    $title = 'Imprint_' . rand() . '-' . $key + 1;
                    $discountVal =  $tierData['discount_type'] == 'flat' ? $eachDiscount['discount'] : $eachDiscount['discount'] / 100;
                    if ($tierData['pricing_per_variants'] == 'true' && $tierData['discount_type'] == 'flat') {
                        $input = "{combinesWith: {productDiscounts: true}, customerGets: {items: {products: {productsToAdd: [\"$prodId\"]}}, value: {discountAmount: {amount: \"$discountVal\", appliesOnEachItem: true}}}, startsAt: \"$date\", title: \"$title\", minimumRequirement: {quantity: {greaterThanOrEqualToQuantity: \"{$eachDiscount['lower_limit']}\"}}}";
                    } elseif ($tierData['pricing_per_variants'] == 'true' && $tierData['discount_type'] == 'percentage') {
                        $input = "{combinesWith: {productDiscounts: true}, customerGets: {items: {products: {productsToAdd: [\"$prodId\"]}}, value: {percentage: $discountVal}}, startsAt: \"$date\", title: \"$title\", minimumRequirement: {quantity: {greaterThanOrEqualToQuantity: \"{$eachDiscount['lower_limit']}\"}}}";
                    } elseif ($tierData['pricing_per_variants'] == 'false' && $tierData['discount_type'] == 'flat') {
                        $input = "{combinesWith: {productDiscounts: true}, customerGets: {items: {products: {productVariantsToAdd: [\"gid://shopify/ProductVariant/{$discount['id']}\"]}}, value: {discountAmount: {amount: \"$discountVal\", appliesOnEachItem: true}}}, startsAt: \"$date\", title: \"$title\", minimumRequirement: {quantity: {greaterThanOrEqualToQuantity: \"{$eachDiscount['lower_limit']}\"}}}";
                    } elseif ($tierData['pricing_per_variants'] == 'false' && $tierData['discount_type'] == 'percentage') {
                        $input = "{combinesWith: {productDiscounts: true}, customerGets: {items: {products: {productVariantsToAdd: [\"gid://shopify/ProductVariant/{$discount['id']}\"]}}, value: {percentage: $discountVal}}, startsAt: \"$date\", title: \"$title\", minimumRequirement: {quantity: {greaterThanOrEqualToQuantity: \"{$eachDiscount['lower_limit']}\"}}}";
                    }
                    $discountCreateQuery = <<<JSON
                        mutation discountAutomaticCreate {
                                discountAutomaticBasicCreate(
                                    automaticBasicDiscount: $input
                                ) {
                                    automaticDiscountNode {
                                    id
                                    }
                                    userErrors {
                                    message
                                    field
                                }
                         }
                    }
                JSON;

                    $discountCreate = $this->graphQlRequest($discountCreateQuery);
                    if (!empty($discountCreate['data']['discountAutomaticBasicCreate']['automaticDiscountNode'])) {
                        $tierData['price_rules'][$key]['discounts'][$disKey]['id'] = $discountCreate['data']['discountAutomaticBasicCreate']['automaticDiscountNode']['id'];
                    }
                }
            }
            $shopifyDiscountPath = ASSETS_PATH_W . 'products/discount/';
            if (!is_dir($shopifyDiscountPath)) {
                mkdir($shopifyDiscountPath);
            }
            $thisProdDiscountFile = $shopifyDiscountPath . $tierData['productID'] . ".json";
            file_put_contents($thisProdDiscountFile, json_encode($tierData));
            $saveStatus = true;
        }
        return $saveStatus;
    }

    //get all automatic discounts present in the store
    private function getAutomaticDiscounts($title = '')
    {
        $query = $title != '' ? "(status:active AND $title)" : "status:active";
        $getAutomaticDiscountsQuery = <<<JSON
                    query automaticDiscount {
            automaticDiscountNodes(first: 250, query: "status:active") {
                nodes {
                id
                automaticDiscount {
                    ... on DiscountAutomaticBasic {
                    customerGets {
                        items {
                        ... on DiscountProducts {
                            __typename
                            products(first: 10) {
                            nodes {
                                id
                            }
                            }
                            productVariants(first: 10) {
                            nodes {
                                id
                            }
                            }
                        }
                        }
                        value {
                        ... on DiscountAmount {
                            __typename
                            amount {
                            amount
                            }
                        }
                        ... on DiscountPercentage {
                            __typename
                            percentage
                        }
                        }
                    }
                    minimumRequirement {
                        ... on DiscountMinimumQuantity {
                        __typename
                        greaterThanOrEqualToQuantity
                        }
                    }
                    }
                }
                }
            }
            }
        JSON;

        $getAutomaticDiscounts = $this->graphQlRequest($getAutomaticDiscountsQuery);
        $getAutomaticDiscounts = $getAutomaticDiscounts['data']['automaticDiscountNodes']['nodes'];
        return $getAutomaticDiscounts;
    }

    //modify discount cache when updated in store admin
    public function updateDiscountCache($discountId)
    {
        $updateStatus = false;
        $discountDetailsQuery = <<<JSON
            query discountDetails {
            automaticDiscountNode(id: "$discountId") {
                automaticDiscount {
                ... on DiscountAutomaticBasic {
                    customerGets {
                    items {
                        ... on DiscountProducts {
                        __typename
                        products(first: 10) {
                            nodes {
                            id
                            }
                        }
                        productVariants(first: 250) {
                            nodes {
                            id
                            }
                        }
                        }
                    }
                    value {
                        ... on DiscountAmount {
                        __typename
                        amount {
                            amount
                        }
                        }
                        ... on DiscountPercentage {
                        __typename
                        percentage
                        }
                    }
                    }
                    minimumRequirement {
                    ... on DiscountMinimumQuantity {
                        __typename
                        greaterThanOrEqualToQuantity
                    }
                    }
                }
                }
            }
            }
        JSON;
        $discountDetails = $this->graphQlRequest($discountDetailsQuery);
        if (!empty($discountDetails['data']['automaticDiscountNode']['automaticDiscount']['customerGets'])) {
            $discountDetails = $discountDetails['data']['automaticDiscountNode']['automaticDiscount'];
            if (!empty($discountDetails['customerGets']['items']['products']['nodes'])) {
                $productId = $this->getNumericData($discountDetails['customerGets']['items']['products']['nodes'][0]['id']);
            } else {
                $varId = $this->getNumericData($discountDetails['customerGets']['items']['productVariants']['nodes'][0]['id']);
                $varDets = $this->getVariantDetails($varId);
                $productId =  $this->getNumericData($varDets['product']['id']);
            }

            $amount = $discountDetails['customerGets']['value']['__typename'] == "DiscountAmount" ? $discountDetails['customerGets']['value']['amount']['amount'] : ($discountDetails['customerGets']['value']['percentage']) * 100;
            $minQuanity = $discountDetails['minimumRequirement']['greaterThanOrEqualToQuantity'];
        }
        if ($productId) {
            $shopifyDiscountPath = ASSETS_PATH_W . 'products/discount/';
            $thisProdDiscountFile = $shopifyDiscountPath . $productId . ".json";
            if (file_exists($thisProdDiscountFile)) {
                $tierData = json_clean_decode(file_get_contents($thisProdDiscountFile));

                foreach ($tierData['price_rules'] as $key => $eachDiscount) {
                    foreach ($eachDiscount['discounts'] as $discKey => $discount) {
                        if ($discount['id'] == $discountId) {
                            $tierData['price_rules'][$key]['discounts'][$discKey]['lower_limit'] = $minQuanity;
                            $tierData['price_rules'][$key]['discounts'][$discKey]['discount'] = $amount;
                            unlink($thisProdDiscountFile);
                            file_put_contents($thisProdDiscountFile, json_encode($tierData, true));
                            $updateStatus = true;
                        }
                    }
                }
            }
        }
        return $updateStatus;
    }

    public function addCatalogProductToStore($priceInfo, $product, $price, $catalog_price, $storeCategories)
    {
        $newProductIds = [];
        $oldProdId = $product['old_product_id'];
        if ($oldProdId > 0) {
            if ($oldProdId > 0) {
                $deleteOldProdQuery = <<<JSON
                                      mutation {
                                        productDelete(input: {id: "gid://shopify/Product/$oldProdId"}) {
                                        deletedProductId
                                            userErrors {
                                            field
                                            message
                                            }
                                        }
                                }
                      JSON;
                $this->graphQlRequest($deleteOldProdQuery);
            }
        }

        $imgArr = $optionArr = $variantArr = $newProductIds = array();
        foreach ($product['variations'] as $variant) {
            $key = 1;
            foreach ($variant['image_path'] as $img) {
                if (!empty($img) && !in_array(array("src" => $img, "position" => $key), $imgArr)) {
                    array_push($imgArr, array("src" => $img, "position" => $key));
                }
                $key++;
            }

            $thisVarPrice = $variant['piece_price'];

            if (!empty($priceInfo['is_margin'])) {
                if ($priceInfo['is_margin'] == 2) {
                    $thisVarPrice = $variant['piece_price'] + $priceInfo['product_margin'];
                } else {
                    $percentagePrice = $variant['piece_price'] * ($priceInfo['product_margin'] / 100);
                    $thisVarPrice = $variant['piece_price'] + $percentagePrice;
                }
            } else {
                $thisVarPrice = $price;
            }
            $thisVariant = array(
                "sku" => $variant['sku'],
                "barcode" => isset($variant['gtin']) ? $variant['gtin']  : '',
                "price" => number_format((float)$thisVarPrice, 2, '.', ''),
                "inventory_management" => "shopify",
                "inventory_policy" => "deny",
                "attribute_data" => $variant['attributes'],
                "variant_quantity" => $variant['quantity'],
                "variant_images" => $variant['image_path']
            );
            $variantArr[] = $thisVariant;
        }
        $colorAttr = [];
        if (!empty($product['attributes'])) {
            foreach ($product['attributes'] as $attrKey => $attribute) {
                $thisAttr = [];
                if (strtolower($attribute['name']) != 'xe_is_designer') {
                    $thisAttr['name'] = $attribute['name'];
                    $thisAttr['position'] = ($attrKey + 1);
                    $thisAttr['values'] = $attribute['options'];
                    $optionArr[] = $thisAttr;
                }
                if (strtolower($attribute['name']) == 'color') {
                    $colorAttr = $attribute['options'];
                }
            }
        }

        $productArray = array(
            "product" => array(
                "title" => $this->shopify_body(addslashes($product['name'])),
                "body_html" => $this->shopify_body(addslashes($product['description'])),
                "published" => true,
                "tags" => "catalogue",
                "brand" => $product['brand'],
                "image" => array("src" => $product['images']['src'], "position" => 1),
            ),
        );


        if (!empty($optionArr) && !empty($variantArr)) {
            $productArray['product']['options'] = $optionArr;
            $productArray['product']['variants'] = $variantArr;
        }


        if (SHOPIFY_VARIANTS_PLUGIN == 1) {
            $newProductIds = $this->shopifyVariantManage($productArray, $product, $imgArr);
            return $newProductIds;
        }
        $shopifyStoreLimits = $this->shopifyStoreResourceLimit();
        $variantChunks = array_chunk($variantArr, $shopifyStoreLimits['maxProductVariants']);


        foreach ($variantChunks as $variantSplitData) {
            $optionsArray = [];
            $collectionArray = [];
            $outputArr = [];
            $varinatsArray = [];
            $duplicateColor = [];
            $imgId = '';

            $newProductId = '';
            $productArray['product']['variants'] = SHOPIFY_VARIANTS_PLUGIN == 1 ? array_unique($variantSplitData) : $variantSplitData;

            // creating a new product with single variant
            foreach ($productArray['product']['options'] as $productOptions) {
                $optionsArray[] = "{name: \"" . strtolower($productOptions['name']) . "\", position: {$productOptions['position']}, values: {name: \"{$productOptions['values'][0]}\"}}";
            }
            $optionSet = "[" . implode(",", $optionsArray) . "]";
            // addition of store categories ids
            if (!empty($storeCategories)) {
                foreach ($storeCategories as $categoriesIds) {
                    $collectionArray[] = "\"gid://shopify/Collection/$categoriesIds\"";
                }
            }
            $showIndesignerId = $this->getShowInDesignerId();
            $collectionID = "\"gid://shopify/Collection/$showIndesignerId\"";
            if (!in_array($collectionID, $collectionArray)) {
                $collectionArray[] = $collectionID;
            }

            $categorySet = !empty($collectionArray) ? "[" . implode(",", $collectionArray) . "]" : json_encode([]);


            $dupColor = [];
            foreach ($imgArr as $item) {
                $found = false;
                foreach ($colorAttr as $eachColor) {
                    if (strpos(strtolower($item['src']), strtolower(str_replace(['_', ' '], '', $eachColor))) !== false && strpos(strtolower($item['src']), '_front') !== false) {
                        if (!in_array($eachColor, $dupColor)) {
                            $dupColor[] = $eachColor;
                            $outputArr[] = "{originalSource: \"{$item['src']}\", mediaContentType : IMAGE, alt: \"{$eachColor}\"}";
                        }
                        $found = true;
                        break; // Exit inner loop once a match is found
                    }
                }
                if (!$found) {
                    $outputArr[] = "{originalSource: \"{$item['src']}\", mediaContentType : IMAGE}";
                }
            }


            $imagesInfo = "[" . implode(",", $outputArr) . "]";

            $prodTitle = (preg_match('/[\'^£$%&*()}{@#~?><>,|=_+¬-]/', $productArray['product']['title']) ? stripslashes($productArray['product']['title']) : $productArray['product']['title']);
            $prodDescription = (preg_match('/[\'^£$%&*()}{@#~?><>,|=_+¬-]/', $productArray['product']['body_html']) ? stripslashes($productArray['product']['body_html']) : $productArray['product']['body_html']);

            $createProductQuery = <<<JSON
            mutation createProduct {
                   productCreate(
                       product: {title: "{$prodTitle}" , descriptionHtml: "{$prodDescription}", tags: "{$productArray['product']['tags']}",
                               productOptions: $optionSet, collectionsToJoin: $categorySet}
                       media: $imagesInfo
                           )   {
                            product {
                                id
                            media(first: 250) {
                                edges {
                                node {
                                        id
                                    alt
                                }
                                }
                            }
                                variants(first: 1) {
                                edges {
                                    node {
                                        inventoryItem {
                                                inventoryLevels(first: 1) {
                                                edges {
                                                    node {
                                                        location {
                                                         id
                                                        }
                                                    }
                                                }
                                            }
                                          }
                                        }
                                    }
                                }
                            }
                      }
                  }
            JSON;


            $newProductQuery = $this->graphQlRequest($createProductQuery);

            $newProduct = !empty($newProductQuery['data']['productCreate']['product']) ? $newProductQuery['data']['productCreate']['product'] : null;
            $newProductId = $newProduct['id'];
            $locationId = $newProduct['variants']['edges'][0]['node']['inventoryItem']['inventoryLevels']['edges'][0]['node']['location']['id'];
            //publish the created product to Online Store
            $publishQuery = <<<JSON
            mutation starts {
                publishablePublish(
                    id: "$newProductId"
                    input: {publicationId: "{$this->getPublicationId()}"}
                ) {
                    userErrors {
                    message
                    }
                }
            }
           JSON;

            $this->graphQlRequest($publishQuery);

            //get mediaId to assign each variant
            $newProductImage = array();
            foreach ($newProduct['media']['edges'] as $img) {
                if (isset($img['node']['alt'])) {
                    array_push($newProductImage, array("id" => $img['node']['id'],  "alt" => $img['node']['alt']));
                }
            }

            //creating multiple variants in bulk
            foreach ($productArray['product']['variants'] as $eachVariantData) {
                $graphString = array();
                foreach ($eachVariantData['attribute_data'] as $attrKey => $attributeNames) {
                    $graphString[] = "{name: \"{$attributeNames}\", optionName: \"{$attrKey}\"}";
                }
                $variantSet = "[" . implode(",", $graphString) . "]";
                foreach ($newProductImage as $eachImg) {
                    if ($eachImg['alt'] != '' && ((strtolower($eachVariantData['attribute_data']['color']) == strtolower($eachImg['alt'])) || (strtolower($eachVariantData['attribute_data']['color']) == strtolower($eachImg['alt']))) &&  !in_array(strtolower($eachImg['alt']), $duplicateColor)) {
                        $imgId = $eachImg['id'];
                        $duplicateColor[] = strtolower($eachImg['alt']);
                    }
                }
                $varinatsArray[] = ($imgId != '') ? "{barcode: \"{$eachVariantData['barcode']}\", price:  \"{$eachVariantData['price']}\", inventoryPolicy: DENY, optionValues: $variantSet, inventoryItem: {tracked: true, sku: \"{$eachVariantData['sku']}\"},inventoryQuantities: {availableQuantity:{$eachVariantData['variant_quantity']} , locationId: \"{$locationId}\"},mediaId: \"{$imgId}\"}" :  "{barcode: \"{$eachVariantData['barcode']}\", price:  \"{$eachVariantData['price']}\", inventoryPolicy: DENY, optionValues: $variantSet, inventoryItem: {tracked: true, sku: \"{$eachVariantData['sku']}\"},inventoryQuantities: {availableQuantity:{$eachVariantData['variant_quantity']} , locationId: \"{$locationId}\"}}";
                $finalDataSet = "[" . implode(",", $varinatsArray) . "]";
            }

            //update options and variants of the created product
            if (!empty($newProduct)) {
                $query = <<<JSON
                mutation variantCreate {
                productVariantsBulkCreate(
                  productId: "$newProductId"
                  strategy: REMOVE_STANDALONE_VARIANT
                  variants: $finalDataSet
                    ){
                    product {
                        id
                     }
                }
              }
            JSON;
                $updateVariant = $this->graphQlRequest($query);
                //}

                if (!empty($updateVariant['data']['productVariantsBulkCreate']['product'])) {
                    $newProductIds[] = $this->getNumericData($newProductId);
                }
            }
        }
        return $newProductIds;
    }

    private function removeSPLChars($string, $removeSpace = true)
    {
        $string = preg_replace('/[^A-Za-z0-9 \-]/', '', $string); // Removes special chars.
        $string = strtolower($string);
        $string = $removeSpace === true ? str_replace(' ', '', $string) : str_replace(' ', '_', $string); // Replaces all spaces.
        return preg_replace('/-+/', '', $string); // Replaces multiple hyphens.
    }

    public function addCollection($catName)
    {
        $query = <<<JSON
                     mutation starts {
                        collectionCreate(input: {title: "$catName"}) {
                            collection {
                              id
                            }
                        }
                    }
                JSON;
        $addColArr = $this->graphQlRequest($query);
        $addCol = $addColArr['data']['collectionCreate']['collection'];
        if (!empty($addCol['id'])) {
            $storeResponse = [
                'status' => 1,
                'catatory_id' => end(explode('/', $addCol['id'])),
                'message' => message('Catagories', 'saved'),
            ];
        } else {
            $storeResponse = [
                'status' => 0,
                'message' => 'Failed to create collection',
            ];
        }
        return $storeResponse;
    }

    public function GetProductMeta($productID)
    {
        $preDecoContent = ['custom_design_id' => 0, 'is_redesign' => 0];
        $query = <<<JSON
                    query starts {
                        product(id: "$productID") {
                            metafield(key: "imprint_design_id", namespace: "Pre-Deco") {
                                value
                            }
                        }
                    }
                JSON;
        $metaFieldArr = $this->graphQlRequest($query);
        $metaFields = $metaFieldArr['data']['product']['metafield'];
        if (!empty($metaFields)) {
            $preDecoContent['custom_design_id'] = $metaFields['value'];
        }
        $query = <<<JSON
                    query starts {
                        product(id: "$productID") {
                            collections(first: 50) {
                                    nodes {
                                        handle
                                    }
                                }
                        }
                    }
                JSON;
        $allCatArr = $this->graphQlRequest($query);
        $allCats = $allCatArr['data']['product']['collections']['nodes'];
        $categories = array_column($allCats, 'handle');
        $preDecoContent['is_redesign'] = in_array('show-in-designer', $categories) ? 1 : 0;
        return $preDecoContent;
    }

    public function getShopifyProductInfo($productID)
    {
        $productQuery = <<<JSON
                                 query productdetails {
                                    product(id: "gid://shopify/Product/$productID") {
                                        id
                                        title
                                        descriptionHtml
                                        createdAt
                                        images(first: 250) {
                                        nodes {
                                            id
                                            url
                                        }
                                        }
                                        variants(first: 200) {
                                        nodes {
                                            id
                                            title
                                            price
                                            sku
                                            position
                                            inventoryPolicy
                                            createdAt
                                            updatedAt
                                            inventoryQuantity
                                            inventoryItem {
                                            tracked
                                            }
                                            image {
                                            id
                                            url
                                            }
                                            selectedOptions {
                                            name
                                            value
                                            optionValue {
                                                id
                                                name
                                            }
                                          }
                                          product {
                                                id
                                            }
                                        }
                                    }
                                    options(first: 10) {
                                        id
                                        position
                                        name
                                        values
                                    optionValues {
                                            id
                                            name
                                        }
                                    }
                                    variantsCount {
                                    count
                                }
                            }
                    }
        JSON;
        $productArr = $this->graphQlRequest($productQuery, ' ', true);
        if (!empty($productArr['data']['product'])) {
            return $productArr;
        }
    }

    /**
     * Update selected variant id inventory to out of stock
     *
     * @param $storeProductId  Product Id, $selectedVarIds Variant Id
     *
     * @author divya@imprintnext.com
     * @date  27 April 2022
     * @return true/false
     */
    public function variantStockUpdate($stockUpdateJson)
    {
        // group by product_id
        $newStockByProducts = array_reduce($stockUpdateJson, function ($accumulator, $element) {
            $accumulator[$element['productId']][] = $element;
            return $accumulator;
        }, []);
        $stockeUpdated = 0; // to mark stock is updated or not
        foreach ($newStockByProducts as $productId => $newStock) {
            $allVariantData = [];
            $newStockVariants = array_column($newStock, 'variantId');

            $productDetails = $this->getProductDetails($productId);

            $variants = $productDetails['variants']['nodes'];

            $catlogProductRel = new CatalogProductRel();
            $productStoredType = $catlogProductRel->where(['product_id' => $productId])->pluck('product_stored_type')->toArray();

            //if SHOPIFY_VARIANTS_PLUGIN is enabled then update stock and price in Imprint db
            if ($productStoredType[0] != 'store') {
                $variantRelObj = new ProductVariantRel();
                $variantIds = $variantRelObj->where(['product_id' => $productId])->pluck('variant_id')->toArray();
                $variantObj = new ProductVariants();
                foreach ($variantIds as $varId) {
                    $key = array_search($varId, $newStockVariants);
                    if ($key !== false && isset($newStock[$key]['price']) && isset($newStock[$key]['stock'])) {

                        $variantObj->where('xe_id', $varId)
                            ->update(['price' => $newStock[$key]['price'], 'inventory' => $newStock[$key]['stock']]);
                        $stockeUpdated = 1;
                    }
                }
            } else
            {
                foreach ($variants as $variant) {
                    $vId = $this->getNumericData($variant['id']);
                    $variantUpdateData = [
                        'id' => $vId,
                        'title' => $variant['title'],
                        'sku' => $variant['sku']
                    ];
                    // find the variant - then update the prices (all variant updated at a time)
                    $key = array_search($vId, $newStockVariants);
                    if ($key !== false) {
                        if (isset($newStock[$key]['price'])) {
                            $variantUpdateData['price'] = $newStock[$key]['price'];
                        }
                        if (isset($newStock[$key]['stock'])) {


                            // update the inventory
                            $variantDetails = $this->getVariantDetails($vId);
                            if (!empty($variantDetails['inventoryItem']['id'])) {
                                $inventoryItemId = $variantDetails['inventoryItem']['id'];
                                if (!empty($variantDetails['inventoryItem']['inventoryLevels']['nodes'][0]['location']['id'])) {
                                    $locationId = $variantDetails['inventoryItem']['inventoryLevels']['nodes'][0]['location']['id'];
                                    $quantity = $newStock[$key]['stock'];

                                    $query = <<<JSON
                                mutation inventorySetQuantities {
                                    inventorySetQuantities(
                                        input: {reason: "correction", name: "available", quantities: {inventoryItemId: "{$inventoryItemId}", locationId: "{$locationId}", quantity: $quantity}, ignoreCompareQuantity: true}
                                    ) {
                                        userErrors {
                                        message
                                        field
                                        }
                                        inventoryAdjustmentGroup {
                                        id
                                        changes {
                                            delta
                                            quantityAfterChange
                                            ledgerDocumentUri
                                        }
                                        }
                                    }
                                    }
                        JSON;
                                    $this->graphQlRequest($query);

                                    $stockeUpdated = 1;
                                }
                            }

                        }
                    }
                    // keep all variants and update with product at a time(price update)
                    $allVariantData[] = $variantUpdateData;
                }

                // update product variant price
                // we are not keeping track of each variant's price update status
                if ($allVariantData) {
                    //  bulk updating variants' price and SKU
                    $variantUpdates = [];
                    foreach ($allVariantData as $variantUpdate) {
                        $fields = [];
                        if (isset($variantUpdate['id'])) {
                            $fields[] = 'id: "gid://shopify/ProductVariant/' . $variantUpdate['id'] . '"';
                        }
                        if (isset($variantUpdate['price'])) {
                            $fields[] = 'price: "' . $variantUpdate['price'] . '"';
                        }
                        if (isset($variantUpdate['sku'])) {
                            $fields[] = 'inventoryItem: {sku: "' . $variantUpdate['sku'] . '"}';
                        }
                        $variantUpdates[] = '{' . implode(', ', $fields) . '}';
                    }
                    $variantsString = '[' . implode(',', $variantUpdates) . ']';
                    $variantallUpdate = <<<JSON
                mutation variantallUpadte {
                productVariantsBulkUpdate(
                    productId: "gid://shopify/Product/$productId"
                    variants: $variantsString
                    ) {
                            productVariants {
                            id
                        }
                        userErrors {
                                message
                        }
                    }
                }
         JSON;

                    $this->graphQlRequest($variantallUpdate);
                }
            }
        }
        return [
            'status' => $stockeUpdated
        ];
    }

    /**
     * get all location for product
     *
     * @param $storeProductId  Product Id, $selectedVarIds Variant Id
     *
     * @author sonali@imprintnext.com
     * @date  19 july 2022
     * @return true/false
     */
    public function getloation()
    {
        return $this->call('GET', '/admin/locations' . '.json');
    }

    /**
     * delete/archieve all abondoned cart Products from Shopify store
     *
     * @param $status,$days
     *
     * @author pansy@imprintnext.com
     * @date  06 Feb 2024
     * @return
     */
    public function deleteDuplicateProducts($params)
    {
        $response = [];
        $status = $params['status'];
        $days = $params['days'];
        $createdAfter = strtotime('-' . $days . 'days');
        $productCreated = date('Y-m-d\TH:i:sP', $createdAfter);
        $limit = 250;
        $created_at_max = $productCreated;
        $collection_id = $this->getCustomizedCollectionId();
        $query = <<<JSON
                    query starts {
                        products(first: $limit, query: "created_at:<'$created_at_max'") {
                          nodes {
                            inCollection(id: "$collection_id")
                            id
                          }
                        }
                    }
                JSON;
        $duplicateProductsArr = $this->graphQlRequest($query);
        foreach ($duplicateProductsArr['data']['products']['nodes'] as $eachCol) {
            if ($eachCol['inCollection'] == 1) {
                $duplicateProducts[] = $eachCol['id'];
            }
        }

        if (!empty($duplicateProducts)) {
            $removedProductArr = array(
                'action_performed_date' => date('Y-m-d'),
                'action_performed' => '',
                'product_id' => []
            );
            $temp = 0;
            $removedProdsJsonPath = ASSETS_PATH_W . 'products/duplicate_products.json';
            if ($status == 'delete') {
                foreach ($duplicateProducts as $eachDuplicateProduct) {
                    $query = <<<JSON
                                mutation starts {
                                    productDelete(input: {id: "$eachDuplicateProduct"}) {
                                        deletedProductId
                                    }
                                }
                                JSON;
                    $deleteStatus = $this->graphQlRequest($query);
                    if ($deleteStatus['data']['productDelete']['deletedProductId'] == null || isset($deleteStatus['error'])) {
                        $temp += 1;
                    } else {
                        $removedProductArr['action_performed'] = $status;
                        $removedProductArr['product_id'][] += end(explode('/', $eachDuplicateProduct));
                        file_put_contents($removedProdsJsonPath, json_encode($removedProductArr));
                    }
                }
                $response = $temp > 0 ? array('status' => 0, 'message' => "Some Products could'nt be deleted") : $response = array('status' => 1, 'message' => "products deleted successfully");
            } elseif ($status == 'archive') {
                foreach ($duplicateProducts as $eachDuplicateProduct) {
                    $query = <<<JSON
                            mutation starts {
                                productUpdate(
                                  input: {id: "$eachDuplicateProduct", status: ACTIVE}
                                ) {
                                  product {
                                    id
                                  }
                                }
                            }
                      JSON;
                    $archieveStatus = $this->graphQlRequest($query);
                    if ($archieveStatus['data']['productUpdate']['product'] == null || isset($archieveStatus['error'])) {
                        $temp += 1;
                    } else {
                        $removedProductArr['action_performed'] = $status;
                        $removedProductArr['product_id'][] += end(explode('/', $eachDuplicateProduct));
                        file_put_contents($removedProdsJsonPath, json_encode($removedProductArr));
                    }
                }
                $response = $temp > 0 ? array('status' => 0, 'message' => "Some Products could'nt be archived") : $response = array('status' => 1, 'message' => "products archived successfully");
            }
        } else {
            $response = array('status' => 1, 'message' => "No duplicate products found");
        }
        return $response;
    }

    public function optionStatus($productId)
    {
        $productOpstionsData = call_curl([], 'product-options/' . $productId, 'GET');
        $DATA = $productOpstionsData['data']['options'];
        $optionData = addslashes(json_encode($productOpstionsData));
        $data = json_encode($productOpstionsData['data']['options']);
        $query = <<<JSON
        query starts {
            product(id: "gid://shopify/Product/$productId") {
                metafield(key: "custom_data", namespace: "Imprintnext") {
                    value
                    id
                }
            }
        }
    JSON;
        $metaFieldArr = $this->graphQlRequest($query);

        $metaFields = $metaFieldArr['data']['product']['metafield'];
        if (!empty($metaFields)) {
            //delete metadata from product
            $deleteMetaFieldQuery = <<<JSON
                mutation metafieldDelete {
                    metafieldsDelete(
                    metafields: {namespace: "Imprintnext", key: "custom_data", ownerId: "gid://shopify/Product/$productId"}
                ) {
                    deletedMetafields {
                    ownerId
                    }
                    userErrors {
                    field
                    message
                    }
                }
                    }
            JSON;
            $result = $this->graphQlRequest($deleteMetaFieldQuery);
        }
        $query = <<<JSON
                mutation metafieldsSet {
                    metafieldsSet(
                        metafields: {ownerId: "gid://shopify/Product/$productId", key:"custom_data", value: "$optionData", type: "json", namespace: "Imprintnext"}
                    ) {
                        userErrors {
                        message
                        code
                        elementIndex
                        field
                        }
                        metafields {
                        id
                        }
                    }
                    }
                JSON;

        $updateOptionStatus = $this->graphQlRequest($query);
        $updateOption = $updateOptionStatus['data']['metafieldsSet']['userErrors'];
        if (empty($updateOption)) {
            return true;
        }
    }

    /** ************************* Product Module End **************************** **/

    /** ************************* Customer Module Start **************************** **/

    /**
     * Get list of Customer
     *
     * @author     arpita@riaxe.com
     * @date       17 dec 2024
     * @param  API filter params
     * @response   Array of all customer list
     */
    public function getAllCustomers($callParams)
    {
        $name = $callParams['searchString'];
        $sortBy = $callParams['orderby']; //id
        $sort = $callParams['order']; //asc desc
        if ($sortBy == 'id' && $sort == 'asc') {
            $sort =  "ID" . ", reverse : " . "false";
        } else if ($sortBy == 'id' && $sort == 'desc') {
            $sort =  "ID" . ", reverse : " . "true";
        } else if ($sortBy == 'name' && $sort == 'asc') {
            $sort =  "NAME" . ", reverse : " . "false";
        } else {
            $sort =  "NAME" . ", reverse : " . "true";
        }
        $users = array();
        $params['limit'] = $callParams['limit'];
        $page = empty($callParams['page']) ? 1 : $callParams['page'];
        $params['order'] = 'created_at%2Bdesc';
        $searchstring = $callParams['searchString'];
        $allcustomer = $callParams['fetch'] == 'all' ? 50 : $params['limit'];
        $customersCount = $this->storeCustomerCount();

        if (!empty($callParams['from_date']) && !empty($callParams['to_date'])) {
            $params['created_at_min'] = date('Y-m-d h:i:s', strtotime($callParams['from_date']));
            $params['created_at_max'] = date('Y-m-d h:i:s', strtotime($callParams['to_date']));
        }
        $allcustomers = <<<JSON
            query customers {
               customers(first: {$allcustomer}, sortKey: {$sort} , query: "$name") {
                   nodes {
                   id
                   firstName
                   lastName
                   email
                   createdAt
                   orders(first: 10) {
                       nodes {
                           id
                           }
                       }
                   lastOrder {
                       id
                   }
               }
               pageInfo {
                   endCursor
                   hasNextPage
                   hasPreviousPage
                   startCursor
                   }
               }
           }
       JSON;
        $getSessionData = [];
        if ($page > 1) {
            $getSessionData = $_SESSION["all_customer_session" . ($page - 1)];
            $addNextCursor = 'sortKey: ' . $sort . ' ,after: "' . $getSessionData['data']['customers']['pageInfo']['endCursor'] . '"';
            $allcustomers = str_replace('sortKey: ' . $sort, $addNextCursor, $allcustomers);
        }
        $filterCustomers = $this->graphQlRequest($allcustomers);
        $customers = $filterCustomers['data']['customers']['nodes'];
        if (!empty($customers)  &&  $searchstring == '') {
            $_SESSION["all_customer_session" . ($page)] = $filterCustomers;
        }
        foreach ($customers as $cust) {
            if (!empty($callParams['customer_no_order']) && $callParams['customer_no_order'] != 'false') {
                if (empty($cust['orders']['nodes'])) {
                    $orderCount = count(array_column($cust['orders']['nodes'], 'id'));
                    $user = array();
                    $user['id'] = $cust['id'];
                    $user['first_name'] = $cust['firstName'];
                    $user['last_name'] = $cust['lastName'];
                    $user['email'] = $cust['email'];
                    $user['total_orders'] = $orderCount;
                    $user['last_order_id'] = str_replace('#', '', $cust['lastOrder']);
                    $user['date_created'] = date('Y-m-d h:i:s', strtotime($cust['createdAt']));
                    $users['customer_list'][] = $user;
                }
            } elseif (!empty($callParams['customer_no_order']) && $callParams['customer_no_order'] == 'false') {
                if (!empty($cust['orders']['nodes'])) {
                    $orderCount = count(array_column($cust['orders']['nodes'], 'id'));

                    $orderIds = array_column($cust['orders']['nodes'], 'id');
                    $lastIndex = count($orderIds) - 1;
                    $lastOrderId = $this->getNumericData($orderIds[$lastIndex]);
                    $user = array();
                    $user['id'] = $cust['id'];
                    $user['first_name'] = $cust['firstName'];
                    $user['last_name'] = $cust['lastName'];
                    $user['email'] = $cust['email'];
                    $user['total_orders'] = $orderCount;
                    $user['last_order_id'] = str_replace('#', '', $lastOrderId);
                    $user['date_created'] = date('Y-m-d h:i:s', strtotime($cust['createdAt']));
                    $users['customer_list'][] = $user;
                }
            } else {
                $orderCount = count(array_column($cust['orders']['nodes'], 'id'));
                $orderIds = array_column($cust['orders']['nodes'], 'id');
                $lastIndex = count($orderIds) - 1;
                $lastOrderId = $this->getNumericData($orderIds[$lastIndex]);

                //print_r($cust);exit;
                $user = array();
                $user['id'] = $this->getNumericData($cust['id']);
                $user['first_name'] = $cust['firstName'];
                $user['last_name'] = $cust['lastName'];
                $user['email'] = $cust['email'];
                $user['total_orders'] = $orderCount;
                $user['last_order_id'] = str_replace('#', '', $lastOrderId);
                $user['date_created'] = date('Y-m-d h:i:s', strtotime($cust['createdAt']));
                $users['customer_list'][] = $user;
            }
        }
        $users['total_user'] = $customersCount;
        return $users;
    }



    /**
     * Get details of Customer
     *
     * @author     arpita@riaxe.com
     * @date       30 dec 2024
     * @param  $customerID selected cutomer ID
     * @response   Array single customer details
     */
    public function getCustomerDetails($customerID, $getOrders = 0, $skipFields = [])
    {
        $customer = [];
        $billingAddress = [];
        $orderDetails = [];
        $query = <<<JSON
                                     query customers {
                                        customer(id: "gid://shopify/Customer/$customerID") {
                                            id
                                            firstName
                                            lastName
                                            email
                                            phone
                                            defaultAddress {
                                                    address1
                                                    address2
                                                    city
                                                    country
                                                    zip
                                                    province
                                                    countryCodeV2
                                                    provinceCode
                                                }
                                        addresses(first: 10) {
                                            city
                                            zip
                                            province
                                            id
                                            address1
                                            city
                                            address2
                                            country
                                            firstName
                                            lastName
                                            countryCodeV2
                                            provinceCode
                                        }
                                        createdAt
                                        orders(first: 10) {
                                            nodes {
                                                id
                                                netPayment
                                                }
                                        }
                                    }
                                }
                                JSON;
        $customerDetails = $this->graphQlRequest($query);
        $customer = $customerDetails['data']['customer'];
        if (!empty($customer['defaultAddress'])) {
            $billingAddress = [
                'first_name' => $customer['firstName'],
                'last_name' => $customer['lastName'],
                'email' => $customer['email'],
                'phone' => $customer['phone'],
                'address_1' => $customer['defaultAddress']['address1'],
                'address_2' => $customer['defaultAddress']['address2'],
                'city' => $customer['defaultAddress']['city'],
                'state' => $customer['defaultAddress']['province'],
                'postcode' => $customer['defaultAddress']['zip'],
                'country' => $customer['defaultAddress']['country'],
            ];
        }
        $shop = $this->call('GET', '/admin/shop.json?fields=iana_timezone');

        if (!empty($shop['iana_timezone'])) {
            date_default_timezone_set($shop['iana_timezone']);
        }


        // Getting all order details of perticular customer
        $customerOrder = $this->getOrderDetailsByCustomer($customerID);

        if (!empty($customerOrder)) {
            foreach ($customerOrder as $orderData) {
                $order = array();
                $timestamp = strtotime($orderData['createdAt']);
                global $orderId;
                $orderId = $this->getNumericData($orderData['id']);
                $orderNumber = $orderData['name'];
                $order['id'] = $orderId;
                $customerOrderDetailas = $this->call('GET', '/admin/orders/' . $orderId . '.json?');
                $order['number'] = $orderData['poNumber'];
                $order['quantity'] =  $orderData['currentSubtotalLineItemsQuantity'];
                $order['currency'] = $orderData['currencyCode'];
                $order['total_amount'] =  $orderData['totalPriceSet']['presentmentMoney']['amount'];
                $order['created_date'] =  date('d\/M\/Y H:i:s', $timestamp);
                if ($getOrders > 0 && !empty($orderData['lineItems'])) {
                    foreach ($customerOrderDetailas['line_items'] as $lineItems) {
                        $refID = 0;
                        foreach ($lineItems['properties'] as $value) {
                            if ($value['name'] == "_refid") {
                                $refID = $value['value'];
                                break;
                            }
                        }
                        if ($refID == 0 && $lineItems['vendor'] == "imprintNext") {
                            $productData = $this->call('GET', '/admin/products/' . $lineItems['product_id'] . '.json');
                            $tags = $productData['tags'];
                            $tags = explode('IMP_REF_ID_', $tags);
                            $refID = $tags[1];
                        }
                        if ($refID > 0 && !empty($lineItems['variant_id'])) {
                            $OriginalVarID = $this->getParentVariantID($lineItems['variant_id']);
                            $realProductData = $this->shopifyParentProductID($OriginalVarID);
                            $variant = $this->call('GET', '/admin/variants/' . $OriginalVarID . '.json');
                            $realProdID =  json_decode($realProductData, true);
                            $colorPos = $this->getAttributePostion($this->colorAttrName, $realProdID['pid']);
                            $sizePos = $this->getAttributePostion($this->sizeAttrName, $realProdID['pid']);
                            if (strtolower($lineItems['name']) != 'custom price') {
                                $customPriceIndex = array_search('Custom price', array_column($lineItems['properties'], 'name'));
                                $price = $customPriceIndex !== false ? $lineItems['price'] + $lineItems['properties'][$customPriceIndex]['value'] : $lineItems['price'];
                                $lineItems = [
                                    //'id' => $this->getNumericData($lineItems['admin_graphql_api_id']),
                                    'id' => $this->getNumericData($lineItems['id']),
                                    'product_id' => $realProdID['pid'],
                                    'variant_id' => $OriginalVarID,
                                    'name' => $lineItems['name'],
                                    'price' => (float)round($price, 2),
                                    'quantity' => $lineItems['quantity'],
                                    'total' => (float)round($price, 2),
                                    'sku' => $lineItems['sku'],
                                    'custom_design_id' => (isset($refID) && $refID != '') ? $refID : '',
                                    'size' => isset($variant['option' . $sizePos]) ? $variant['option' . $sizePos] : '',
                                    'color' => isset($variant['option' . $colorPos]) ? $variant['option' . $colorPos] : '',
                                    'images' => $this->getStoreProductImages($refID, $lineItems['variant_id']),
                                ];
                            }
                            if (isset($lineItems)) {
                                $order['lineItems'][] = $lineItems;
                            }
                        }
                    }
                }
                if (!empty($order['lineItems'])) {
                    $orderDetails[] = $order;
                }
            }
        }
        if (!empty($customer['orders']['nodes'])) {
            $orderCount = count(array_column($customer['orders']['nodes'], 'id'));
            $totalAmount = array_sum(array_column($customer['orders']['nodes'], 'netPayment'));
            $result = [
                "id" => $this->getNumericData($customer['id']),
                "first_name" => $customer['firstName'],
                "last_name" => $customer['lastName'],
                "email" => $customer['email'],
                "profile_pic" => '',
                "phone" => ($customer['phone'] != '') ? $customer['phone'] : '',
                "total_orders" =>  $orderCount,
                "total_order_amount" => (float)round($totalAmount, 2),
                "last_order_id" => $orderId,
                "average_order_amount" => (float)(
                    ($orderCount > 0)
                    ? strval(round(($totalAmount / $orderCount), 2)) : '0:00'
                ),
                "date_created" => date('Y-m-d h:i:s', strtotime($customer['createdAt'])),
                "billing_address" => $billingAddress,
                "last_order" => $orderDetails[0]['created_date'],
                "orders" => $orderDetails
            ];
        }
        if (empty($customer['orders']['nodes'])) {
            $orderCount = count(array_column($customer['orders']['nodes'], 'id'));
            $totalAmount = array_sum(array_column($customer['orders']['nodes'], 'netPayment'));
            $result = [
                "id" => $this->getNumericData($customer['id']),
                "first_name" => $customer['firstName'],
                "last_name" => $customer['lastName'],
                "email" => $customer['email'],
                "profile_pic" => '',
                "phone" => ($customer['phone'] != '') ? $customer['phone'] : '',
                "total_orders" =>  $orderCount,
                "total_order_amount" => (float)round($totalAmount, 2),
                "average_order_amount" => (float)(
                    ($orderCount > 0)
                    ? strval(round(($totalAmount / $orderCount), 2)) : '0:00'
                ),
                "date_created" => date('Y-m-d h:i:s', strtotime($customer['createdAt'])),
                "billing_address" => $billingAddress,
                "last_order" => $orderDetails[0]['created_date'],
                "orders" => $orderDetails
            ];
        }
        $shippingAddress = [];
        $skipFields = [];
        if (!empty($customer['addresses'])) {
            foreach ($customer['addresses'] as $key => $address) {
                $shippingAddress[] = [
                    'id' => $this->getNumericData($address['id']),
                    'firstName' => $address['firstName'],
                    'lastName' => $address['lastName'],
                    'email' => $customer['email'],
                    'phone' => $customer['phone'],
                    'address_1' => $address['address1'],
                    'address_2' => $address['address2'],
                    'city' => $address['city'],
                    'state_name' => $address['province'],
                    'postcode' => $address['zip'],
                    'country_name' => $address['country'],
                    'country' => $address['countryCodeV2'],
                    'state' => $address['provinceCode'],
                ];
            }
        } else {
            $shippingAddress = array($billingAddress);
        }
        $result['shipping_address'] = $shippingAddress;
        return $result;
    }

    /**
     * Get count of all available Customer
     *
     * @author     arpita@riaxe.com
     * @date       19 dec 2024
     * @param
     * @response   An integer value
     */

    public function storeCustomerCount()
    {
        $storeCustomerCount = <<<JSON
                                 query {
                                     customersCount {
                                     count
                                 }
                             }
                     JSON;
        $totalStoreCustomerCountData = $this->graphQlRequest($storeCustomerCount);
        $totalStoreCustomerCount = $totalStoreCustomerCountData['data']['customersCount']['count'];
        return $totalStoreCustomerCount;
    }

    public function getShopCountries()
    {
        $countries = $this->call('GET', '/admin/countries.json');
        $allCountries = array();
        foreach ($countries as $country) {
            if ($country['code'] != "*") {
                $allCountries[] = array('countries_code' => $country['code'], 'countries_name' => $country['name']);
            }
        }
        return $allCountries;
    }

    public function getProvibce($countryCode)
    {
        $countries = $this->call('GET', '/admin/countries.json');
        $states = array();
        foreach ($countries as $country) {
            if ($country['code'] == $countryCode) {
                foreach ($country['provinces'] as $key => $state) {
                    $states[$key]['state_code'] = $state['code'];
                    $states[$key]['state_name'] = $state['name'];
                }
            }
        }
        return $states;
    }

    public function deleteShopCustomer($customerID)
    {
        $response = array();
        foreach ($customerID as $cusID) {
            $query = <<<JSON
                            mutation {
                                customerDelete(input: {id: "gid://shopify/Customer/$cusID"}) {
                                    deletedCustomerId
                                    userErrors {
                                        field
                                        message
                                        }
                                }
                            }
                    JSON;
            $deleteStatus = $this->graphQlRequest($query);

            if ($deleteStatus['data']['productDelete']['deletedProductId'] == null) {
                $response = array('status' => 1, 'message' => "customer deleted");
            } else {
                $response = array('status' => 0, 'message' => $deleteStatus['errors']);
            }
        }
        return $response;
    }

    public function newShopCustomer($custData)
    {
        $customerArr = array();
        $email = $custData['user_email'];
        $phone = $custData['billing_phone'];
        $data = empty($custData) ? $email : $phone;
        $query = <<<JSON
        query customers {
            customers(first: 1, query:  "$data") {
                nodes {
                    id
                    }

                }
            }
        JSON;
        $customerDetails = $this->graphQlRequest($query);
        $searchCustomer = $customerDetails['data']['customers']['nodes'];
        if (empty($searchCustomer) && empty($searchnum)) {
            if (!empty($custData)) {
                $customerInfo['first_name'] = $custData['first_name'];
                $customerInfo['last_name'] = $custData['last_name'];
                $customerInfo['password'] = $custData['user_password'];
                $customerInfo['password_confirmation'] = $custData['user_password'];
                $customerInfo['send_email_welcome'] = false;
                $customerInfo['email'] = $custData['user_email'];
                $customerInfo['phone'] = $custData['billing_phone'];
                $customerInfo['verified_email'] = true;
                $customerInfo['addresses'] = array(array(
                    'address1' => $custData['billing_address_1'],
                    'address2' => $custData['billing_address_2'],
                    'city' => $custData['billing_city'],
                    'province' => $custData['billing_state_code'],
                    'phone' => $custData['billing_phone'],
                    'zip' => $custData['billing_postcode'],
                    'last_name' => $custData['last_name'],
                    'first_name' => $custData['first_name'],
                    'country' => $custData['billing_country_code']
                ), array(
                    'address1' => $custData['shipping_address_1'],
                    'address2' => $custData['shipping_address_2'],
                    'city' => $custData['shipping_city'],
                    'province' => $custData['shipping_state_code'],
                    'phone' => $custData['shipping_phone'],
                    'zip' => $custData['shipping_postcode'],
                    'last_name' => $custData['last_name'],
                    'first_name' => $custData['first_name'],
                    'country' => $custData['shipping_country_code']
                ));
            }
            $customerArr['customer'] = $customerInfo;
            $customerAddress = $customerInfo['addresses'];
            $firstName = $customerInfo['first_name'];
            $lastName = $customerInfo['last_name'];
            $email = $customerInfo['email'];
            $phone = $customerInfo['phone'];
            $outputArray = array();
            foreach ($customerAddress as $address) {
                $address1 = $address['address1'];
                $address2 = $address['address2'];
                $city = $address['city'];
                $zip = $address['zip'];
                $country = $address['country'];
                $province = $address['province'];
                $outputArray[] = "{city: \"{$city}\" , zip: \"{$zip}\" , provinceCode: \"{$province}\", countryCode: $country, address1: \"{$address1}\",  address2: \"{$address2}\"}";
            }
            $rules = "[" . implode(",", $outputArray) . "]";
            $query = <<<JSON
            mutation customerCreate {
                customerCreate(
                    input: {email: "$email", firstName: " $firstName", lastName: "$lastName", phone: "$phone", addresses: $rules}
                    ) {
                        userErrors {
                        message
                        field
                        }
                        customer {
                        id
                        }
                    }
                }
            JSON;
            $creatCustomer = $this->graphQlRequest($query);
            if (!empty($creatCustomer['data']['customerCreate']['customer'])) {
                $createdCustomer = $creatCustomer['data']['customerCreate']['customer'];
            }
            return $createdCustomer;
        } else {
            return array();
        }
    }


    public function changeDefaultAddress($newAddress)
    {
        if (!empty($newAddress)) {
            $id = $newAddress['user_id'];
            $firstName = $newAddress['first_name'];
            $lastName = $newAddress['last_name'];
            $phone = $newAddress['mobile_no'];
            $address1 = $newAddress['address_1'];
            $address2 = $newAddress['address_2'];
            $city = $newAddress['city'];
            $company = $newAddress['company'];
            $zip = $newAddress['post_code'];
            $country = $newAddress["country"];
            $state = $newAddress["state"];
            $newAdd = array("id" => $id, "firstName" => $firstName, "lastName" => $lastName, "company" => $company, "phone" => $phone, "address_1" => $address1, "address_2" => $address2, "city" => $city, "postcode" => $zip, "country_name" => $country, "state_name" => $state);
            $getCuatomderDetails = $this->getCustomerDetails($id);
            $shippingAdd = $getCuatomderDetails['shipping_address'];
            $shippingAdd[] = $newAdd;
            $outputArray = array();
            foreach ($shippingAdd as $add) {
                $firstName = $add['firstName'];
                $lastName = $add['lastName'];
                $email = $add['email'];
                $phone = $add['phone'];
                $address1 = $add['address_1'];
                $address2 = $add['address_2'];
                $city = $add['city'];
                $stateName = $add['state_name'];
                $postcode = $add['postcode'];
                $countryName = $add['country_name'];
                $outputArray[] = "{firstName: \"{$firstName}\" ,lastName: \"{$lastName}\" ,phone: \"{$phone}\" ,province: \"{$stateName}\" ,country: \"{$countryName}\" ,city: \"{$city}\" , zip: \"{$postcode}\" , countryCode: IN, address1: \"{$address1}\",  address2: \"{$address2}\"}";
            }
            $rules = "[" . implode(",", $outputArray) . "]";
            $query = <<<JSON
            mutation changeDefaultAddress {
                customerUpdate(
                    input: {addresses: $rules,id: "gid://shopify/Customer/$id"}
                    ) {
                        customer {
                            id
                            firstName
                            lastName
                            phone
                            defaultAddress {
                                address1
                                address2
                                city
                                province
                                country
                                zip
                                provinceCode
                                countryCode
                                id
                            }
                            }
                            userErrors {
                                message
                                field
                            }
                            }
                        }
            JSON;
            $addedAddress = $this->graphQlRequest($query);
            $addAddress = $addedAddress['data']['customerUpdate']['customer'];
            $id = $this->getNumericData($addAddress['id']);
            $addressId = $this->getNumericData($addAddress['defaultAddress']['id']);
            $firstName = $addAddress['firstName'];
            $lastName = $addAddress['lastName'];
            $phone = $addAddress['phone'];
            $data = array("id" => $addressId, "customer_id" => $id, "firstName" => $firstName, "lastName" => $lastName, "phone" => $phone);
            if ($addAddress['defaultAddress']['id']) {
                unset($updatedAddress['defaultAddress']['id']);
            }
            $address = $addAddress['defaultAddress']; //remove the key id in defaultAddress
            $status = array_merge($data, $address);
            $status['company'] = '';
            $status['name'] = '';
            $status['country_name'] = '';
            $status['default'] = '';
        }
        return $status;
    }

    public function customerShortData($customerId, $isAddress = false)
    {
        $customer = [];
        $billingAddress = [];
        $query = <<<JSON
        query customerData {
            customer(id: "gid://shopify/Customer/$customerId") {
                firstName
                lastName
                email
                phone
                defaultAddress {
                    address1
                    address2
                    city
                    province
                    zip
                    country
                    }
                    addresses {
                    address1
                    address2
                    city
                    province
                    zip
                    country
                    countryCodeV2
                    provinceCode
                    id
                    firstName
                    lastName
                    phone
                    }
                }
                }
        JSON;
        $customerData = $this->graphQlRequest($query);
        $customer = $customerData['data']['customer'];
        $customerDetails = [
            "id" => $customerId,
            "email" => $customer['email'],
            "name" => $customer['firstName'] . ' ' . $customer['lastName'],
            "phone" => ($customer['phone'] != '') ? $customer['phone'] : '',
        ];
        if ($isAddress && !empty($customer['defaultAddress']) && !empty($customer['addresses'])) {
            $billingAddress = [
                'first_name' => $customer['firstName'],
                'last_name' => $customer['lastName'],
                'email' => $customer['email'],
                'phone' => $customer['phone'],
                'address_1' => $customer['defaultAddress']['address1'],
                'address_2' => $customer['defaultAddress']['address2'],
                'city' => $customer['defaultAddress']['city'],
                'state' => $customer['defaultAddress']['province'],
                'postcode' => $customer['defaultAddress']['zip'],
                'country' => $customer['defaultAddress']['country'],
            ];

            if (!empty($customer['addresses'])) {
                foreach ($customer['addresses'] as $key => $address) {
                    if ($key == 0) {
                        continue;
                    }
                    $shippingAddress[] = [
                        'id' => $this->getNumericData($address['id']),
                        'first_name' => $address['firstName'],
                        'last_name' => $address['lastName'],
                        'email' => $customer['email'],
                        'phone' => $customer['phone'],
                        'address_1' => $address['address1'],
                        'address_2' => $address['address2'],
                        'city' => $address['city'],
                        'state_name' => $address['province'],
                        'postcode' => $address['zip'],
                        'country_name' => $address['country'],
                        'country' => $address['countryCodeV2'],
                        'state' => $address['provinceCode'],

                    ];
                }
            } else {
                $shippingAddress = array($billingAddress);
            }
            $customerDetails['billing_address'] = $billingAddress;
            $customerDetails['shipping_address'] = $shippingAddress;
        }
        return array('customer' => $customerDetails);
    }
    public function updateCustomerAddressInShop($allPostPutVars, $id)
    {
        if (!empty($allPostPutVars)) {
            $userId = $allPostPutVars['user_id'];
            $getCuatomderDetails = $this->getCustomerDetails($userId);
            $shippingAdd = $getCuatomderDetails['shipping_address']; //previous saved addresses
            $outputArray = array();
            foreach ($shippingAdd as $add) {
                if ($add['id'] == $id) {
                    $firstName = $allPostPutVars['first_name'];
                    $lastName = $allPostPutVars['last_name'];
                    $company = $allPostPutVars['company'];
                    $phone = $allPostPutVars['mobile_no'];
                    $address1 = $allPostPutVars['address_1'];
                    $address2 = $allPostPutVars['address_2'];
                    $city = $allPostPutVars['city'];
                    $zip = $allPostPutVars['post_code'];
                    $country = $allPostPutVars['country'];
                    $state = $allPostPutVars['state'];
                    $outputArray[] = "{firstName: \"{$firstName}\" ,lastName: \"{$lastName}\" ,phone: \"{$phone}\" ,province: \"{$state}\" ,country: \"{$country}\" ,city: \"{$city}\" , zip: \"{$zip}\" , address1: \"{$address1}\",  address2: \"{$address2}\"}";
                } else {
                    $fName = $add['firstName'];
                    $lName = $add['lastName'];
                    $mobile = $add['phone'];
                    $address_1 = $add['address_1'];
                    $address_2 = $add['address_2'];
                    $city = $add['city'];
                    $state_Name = $add['state_name'];
                    $zip = $add['postcode'];
                    $country_Name = $add['country_name'];
                    $countryCode = $add['country'];
                    $provinceCode = $add['state'];
                    $outputArray[] = "{firstName: \"{$fName}\" ,lastName: \"{$lName}\" ,phone: \"{$mobile}\" ,province: \"{$state_Name}\" ,country: \"{$country_Name}\" ,provinceCode: \"{$provinceCode}\" ,city: \"{$city}\" , zip: \"{$zip}\" , address1: \"{$address_1}\",  address2: \"{$address_2}\"}";
                }
            }
            $updateAdd = "[" . implode(",", $outputArray) . "]";
            $query = <<<JSON
            mutation changeDefaultAddress {
                customerUpdate(
                    input: {addresses: $updateAdd,id: "gid://shopify/Customer/$userId"}
                    ) {
                        customer {
                            id
                            firstName
                            lastName
                            phone
                            defaultAddress {
                                address1
                                address2
                                city
                                province
                                country
                                zip
                                provinceCode
                                countryCode
                                id
                            }
                            }
                            userErrors {
                                message
                                field
                            }
                            }
                        }
            JSON;
            $updateAddress = $this->graphQlRequest($query);
            $updatedAddress = $updateAddress['data']['customerUpdate']['customer'];
            $id = $this->getNumericData($updatedAddress['id']);
            $addressId = $this->getNumericData($updatedAddress['defaultAddress']['id']);
            $firstName = $updatedAddress['firstName'];
            $lastName = $updatedAddress['lastName'];
            $phone = $updatedAddress['phone'];
            $data = array("id" => $addressId, "customer_id" => $id, "firstName" => $firstName, "lastName" => $lastName, "phone" => $phone);
            if ($updatedAddress['defaultAddress']['id']) {
                unset($updatedAddress['defaultAddress']['id']);
            }

            $address = $updatedAddress['defaultAddress']; //remove the key id in defaultAddress
            $status = array_merge($data, $address);
            $status['company'] = '';
            $status['name'] = '';
            $status['country_name'] =  $address['country'];
            $status['default'] = '';
        }

        if (empty($updateAddress['data']['customerUpdate']['userErrors'])) {
            return array("status" => 1, "message" => "address updated");
        } else {
            return array();
        }
    }
    /**
     * get customer saved search as groups
     *
     * @author     debashisd@riaxe.com
     * @date       3 June 2021
     * @param  query filter Array
     * @response   Array of customer groups
     */
    public function getCustomerSavedSearches($filters)
    {
        if (!empty($filters['savedSearchID'])) {
            $savedSearchID = $filters['savedSearchID'];
            $query = <<<JSON
            query getCompanyNmae {
                segment(id: "gid://shopify/Segment/$savedSearchID") {
                    name
                }
                }
            JSON;
            $companyDetils = $this->graphQlRequest($query);
            $companyName = $companyDetils['data']['segment']['name'];
            return $companyName;
        }
        $page = empty($filters['page']) ? 1 : $filters['page'];
        $allSegmanets = <<<JSON
        query segments {
            segments(first: {$filters['perpage']}) {
                nodes {
                id
                name
                }
                pageInfo {
                    endCursor
                    hasNextPage
                    hasPreviousPage
                    startCursor
                    }
                }
            }
        JSON;
        $getSessionData = [];
        if ($page > 1) {

            $getSessionData = $_SESSION["customer_group_session_page_" . ($page - 1)];
            $addNextCursor = 'first: ' . $filters['perpage'] . ', after: "' . $getSessionData['data']['segments']['pageInfo']['endCursor'] . '"';
            $allSegmanets = str_replace('first: ' . $filters['perpage'], $addNextCursor, $allSegmanets);
        }
        $segmentDetails = $this->graphQlRequest($allSegmanets);
        $segments = $segmentDetails['data']['segments']['nodes'];
        if (!empty($segments)) {
            $_SESSION["customer_group_session_page_" . ($page)] = $segmentDetails;
        }
        $getSessionData = $_SESSION["customer_group_session_page_" . ($page)];
        $customerGroups = array();
        foreach ($segments as $seg) {

            $name = $seg['name'];
            $id = $this->getNumericData($seg['id']);
            $thisGroup = array("id_group" => $id, 'name' => $name);
            // print_r($thisGroup);exit;
            $customerGroups[] = $thisGroup;
        }
        $query = <<<JSON
        query segmentsCount {
            segmentsCount {
                count
            }
            }
        JSON;
        $segmentCount = $this->graphQlRequest($query);
        $totalSegments = $segmentCount['data']['segmentsCount']['count'];
        return array("data" => $customerGroups, "total_records" => $totalSegments);
        // session_unset();
        // session_destroy();
    }


    public function getStoreCustomerByGroupId($savedSearchID, $returnCount = false)
    {
        $query = <<<JSON
        query customerSegmentMembers {
            customerSegmentMembers(
                first: 200
                segmentId: "gid://shopify/Segment/$savedSearchID"
            ) {
                edges {
                node {
                    id
                    firstName
                    lastName
                    defaultEmailAddress {
                    emailAddress
                    }
                    defaultAddress {
                        company
                        address1
                        address2
                        city
                        country
                        phone
                        }
                    }
                }
                totalCount
            }
        }
        JSON;
        $segmentmembers = $this->graphQlRequest($query);
        $segmentmember = $segmentmembers['data']['customerSegmentMembers']['edges'];
        $totalCustomers = $segmentmembers['data']['customerSegmentMembers']['totalCount'];
        if ($returnCount) {
            return $totalCustomers;
        } else {
            $thisGroupCustomers = array();
            if (!empty($segmentmember)) {
                foreach ($segmentmember as $members) {
                    $id = $this->getNumericData($members['node']['id']);
                    $first_name = $members['node']['firstName'];
                    $last_name = $members['node']['lastName'];
                    $email = $members['node']['defaultEmailAddress']['emailAddress'];
                    $thisGroupCustomers[] = array('id' => $id, 'name' => $first_name . " " . $last_name, 'email' => $email);
                }
            }
            return $thisGroupCustomers;
        }
    }

    public function updateCustomerSavedSearch($updateData)
    {
        $returnData = array('status' => 0, 'message' => 'Shopify terminated the request');
        $customerGroupID = $updateData['id'];
        $groupName = $updateData['name'];
        $tagFilter = "tag:" . $groupName;
        $companyquery = "customer_tags CONTAINS '$groupName'";
        $getCustomerquery = <<<JSON
        query customerSegmentMembers {
            customerSegmentMembers(
                first: 10
                segmentId: "gid://shopify/Segment/$customerGroupID"
            ) {
                edges {
                node {
                    id
                }
                }
            }
            }
        JSON;
        $getSegmentMembers = $this->graphQlRequest($getCustomerquery);
        $SegmentMembers = $getSegmentMembers['data']['customerSegmentMembers']['edges'];
        foreach ($SegmentMembers as $members) {
            $groupCustomer = $this->getNumericData($members['node']['id']);
            $updateCustomerquery = <<<JSON
            mutation customerTagsUpdate {
                customerUpdate(
                    input: {id: "gid://shopify/Customer/$groupCustomer", tags: " "}
                ) {
                   customer {
                       tags
                       }
                    userErrors {
                    field
                    message
                    }
                }
                }
            JSON;
            $emptyTag = $this->graphQlRequest($updateCustomerquery);
            $updateqry = $emptyTag['data']['customerUpdate']['customer']['tags'];
        }
        if (empty($updateqry)) {
            foreach ($updateData['customer_id'] as $cust) {
                $updateCustomerquerys = <<<JSON
                   mutation customerTagsUpdate {
                       customerUpdate(
                           input: {id: "gid://shopify/Customer/$cust", tags: "$groupName"}
                       ) {
                          customer {
                              tags
                              }
                           userErrors {
                           field
                           message
                           }
                       }
                       }
                   JSON;
                $updateCustomer = $this->graphQlRequest($updateCustomerquerys);
                $updateqrys = $updateCustomer['data']['customerUpdate']['customer']['tags'];
            }
        }
        foreach ($updateData['customer_id'] as $cust) {
            $query = <<<JSON
            mutation segmentUpdate {
                segmentUpdate(id: "gid://shopify/Segment/$customerGroupID", name: "$groupName", query: "$companyquery") {
                    segment {
                    query
                    name
                    id
                    }
                    userErrors {
                    field
                    message
                    }
                }
                }
            JSON;
            $updateSegment = $this->graphQlRequest($query);
            $updateGroup = $updateSegment['data']['segmentUpdate']['userErrors'];
        }
        if (empty($updateGroup)) {
            $this->updateTagsToCustomers($updateData);
            $returnData = array('status' => 1, 'message' => 'CustomerGroup is updated in Shopify store');
        } else {
            return $returnData;
        }
        return $returnData;
    }


    private function updateTagsToCustomers($updateData)
    {
        $customers = $updateData['customer_id'];
        $customerGroupID = $updateData['id'];
        $groupName = $updateData['name'];
        foreach ($customers as $customerID) {
            $query = <<<JSON
            mutation customerTagsUpdate {
              customerUpdate(
                  input: {id: "gid://shopify/Customer/$customerID", tags: "$groupName"}
              ) {
                  userErrors {
                  field
                  message
                  }
              }
              }
          JSON;
        }
    }


    public function createcustomerSavedSearch($name, $customers)
    {
        $query = <<<JSON
        mutation segmentCreate {
            segmentCreate(name:"$name", query: "companies IS NOT NULL ") {
                segment {
                id
                name
                }
            }
            }
        JSON;
        $segmentCreate = $this->graphQlRequest($query);
        $segments = $segmentCreate['data']['segmentCreate']['segment'];
        $customerGroupID = $this->getNumericData($segments['id']);
        $customerGroupNm = $segments['name'];
        foreach ($customers as $cust) {
            $updateCustomerquery = <<<JSON
             mutation customerTagsUpdate {
                 customerUpdate(
                     input: {id: "gid://shopify/Customer/$cust", tags: "$customerGroupNm"}
                 ) {
                    customer {
                        tags
                        }
                     userErrors {
                     field
                     message
                     }
                 }
                 }
             JSON;
            $ucq = $this->graphQlRequest($updateCustomerquery);
            $updateqry = $ucq['data']['customerUpdate']['customer']['tags'];
        }
        $UpdateQuery = <<<JSON
        mutation segmentUpdate {
            segmentUpdate(id: "gid://shopify/Segment/$customerGroupID", query: "customer_tags CONTAINS '$customerGroupNm'") {
                segment {
                query
                name
                id
                }
                userErrors {
                field
                message
                }
            }
            }
        JSON;
        $segmentQueryUpdate = $this->graphQlRequest($UpdateQuery);
        $updatedSegment = $segmentQueryUpdate['data']['segmentUpdate']['segment'];
        $updatedGrpId = $this->getNumericData($updatedSegment['id']);
        $updateCustomers = array('customer_id' => $customers, 'id' => $updatedGrpId, 'name' => $name);
        $this->updateTagsToCustomers($updateCustomers);
        return $updatedGrpId;
    }

    public function deleteCustomerSavedSearch($customerGroupId)
    {
        $groupDeleted = false;
        $query = <<<JSON
        mutation segmentDelete {
            segmentDelete(id: "gid://shopify/Segment/$customerGroupId") {
                deletedSegmentId
                userErrors {
                field
                message
                }
            }
            }
        JSON;

        $deleteStatus = $this->graphQlRequest($query);
        if ($deleteStatus['data']['segmentDelete']['deletedSegmentId'] == null) {
            $groupDeleted = true;
        }
        return $groupDeleted;
    }

    public function savedSearchIDFromCustID($customerID)
    {
        $tagQuery = <<<JSON
       query getCustomerTag {
        customer(id: "gid://shopify/Customer/$customerID") {
            tags
        }
        }
       JSON;
        $getCustomerTags = $this->graphQlRequest($tagQuery);
        $tags = $getCustomerTags['data']['customer']['tags'];
        $groupName = implode(" ", $tags);

        $getIdQuery = <<<JSON
        query getsegments {
            segments(query: "$groupName", first: 1) {
                nodes {
                id
                }
            }
            }
        JSON;
        $getCustomerGrpId = $this->graphQlRequest($getIdQuery);
        $customerGrpId = $getCustomerGrpId['data']['segments']['nodes'];
        foreach ($customerGrpId as $grpId) {
            $groupId = $this->getNumericData(implode(" ", $grpId));
        }
        return $groupId;
    }



    /*     * ************************* Customer Module  End **************************** */

    /*     * ***************************** Order Module Start ***************************** */
    /**
     * creat order quote request
     *
     * @author     debashisd@riaxe.com
     * @modiified by pansy@imprintnext.com
     * @date       11 Aug 2019
     * @param  quotation data Array
     * @response   Array of new order id
     */
    public function createShopOrder($quoteData)
    {
        $lineItems = array();
        foreach ($quoteData['product_data'] as $item) {
            $isStickerProduct = $item['is_sticker_product'];
            $sheetName = $item['sheet_name'];
            if ($item['variant_id'] == 0) {
                $productData = $this->getProductDetails($item['product_id']);
                $variantId = $this->getNumericData($productData['variants']['nodes'][0]['id']);
            }

            if (isset($isStickerProduct) && $isStickerProduct == 1) {
                $option = "{name: \"Sheets\", values: {name: \"{$sheetName}\"}}";
                $variantID = $variantId;
                $variant = $this->getVariantDetails($variantID);
                $newPrice = $item['updated_price'];

                $productQuery = <<<JSON
                        mutation productcreate {
                            productCreate(
                                input: {title: {$productData['title']}, vendor: "imprintNext", templateSuffix: "imprint_dummy_product", productOptions:  $option}
                            ) {
                                product {
                                    id
                                    variants(first: 10) {
                                        nodes {
                                        id
                                        }
                                    }
                                }
                            }
                        }
                JSON;
                $product = $this->graphQlRequest($productQuery);

                if (!empty($product['data']['productCreate']['product'])) {
                    $publicationId = $this->getPublicationId();
                    //publish the created product to Online Store
                    $publishQuery = <<<JSON
                        mutation publish {
                            publishablePublish(
                                id: {$product['data']['productCreate']['product']['id']}
                                input: {publicationId: "$publicationId"}
                            ) {
                                userErrors {
                                message
                                }
                            }
                        }
                    JSON;
                    $this->graphQlRequest($publishQuery);
                    //update the variant
                    $newVariant = $product['data']['productCreate']['product']['variants']['nodes'][0];
                    $variantUpdate = <<<JSON
                        mutation variantUpadte {
                            productVariantsBulkUpdate(
                                productId: "{$product['data']['productCreate']['product']['id']}"
                                variants: {id: "{$newVariant['id']}", inventoryItem: {sku: "{$newVariant['id']}" , measurement: {weight: {value: {$variant['weight']}, unit: {$variant['weight_unit']}}}},  price: $newPrice, inventoryPolicy: {$variant['inventory_policy']}, taxable: {$variant['taxable']}}
                            ) {
                                productVariants {
                                id
                                }
                                userErrors {
                                message
                                }
                            }
                        }
                    JSON;

                    $this->graphQlRequest($variantUpdate);
                }
            }
            if ($item['design_cost'] > 0 || ($item['unit_price'] !== $item['updated_price'])) {
                $product_data = array(
                    "product_id" => $item['product_id'],
                    "variant_id" => ($item['variant_id'] == 0) ? $variantId : $item['variant_id'],
                    "options" => array(),
                    "custom_price" => $item['design_cost'],
                    "ref_id" => $item['custom_design_id'],
                    "qty" => ($item['quantity'] != 0) ? $item['quantity'] : $item['overall_quantity'],
                    "product_price" => $item['updated_price']
                );

                $dupItem = $this->addCustomProduct($product_data);
                $thisItem['variant_id'] =  $dupItem['new_variant_id'];
                $thisItem['quantity'] =  !empty($item['quantity']) ? $item['quantity'] : $item['overall_quantity'];
            } else {
                $thisItem['variant_id'] =  ($item['variant_id'] == 0) ? $variantId : $item['variant_id'];
                $thisItem['quantity'] =  ($item['quantity'] != 0) ? $item['quantity'] : $item['overall_quantity'];
            }
            $thisItem['properties'] = array();
            if ($item['custom_design_id'] > 0 && !empty($item['custom_design_id'])) {
                $thisItem['properties'][] = array("name" => "_refid", "value" => $item['custom_design_id']);
            } else {
                $thisItem['properties'][] = array("name" => "_refid", "value" => -1);
                foreach ($item['files'] as $key => $file) {
                    $side = $key + 1;
                    $thisItem['properties'][] = array("name" => "design_url_" . $side, "value" => $file['decoration_area'][0]['upload_design_url']);
                    $thisItem['properties'][] = array("name" => "preview_url_" . $side, "value" => $file['decoration_area'][0]['upload_preview_url']);
                }
            }
            $lineItems[] = $thisItem;
        }

        //for multisticker product creation
        $thisItem['variant_id'] =  $newVariant['id'];
        $thisItem['quantity'] =  $item['quantity'];
        $thisItem['price'] = $newVariant['price'];


        $customer = $this->call('GET', '/admin/customers/' . $quoteData['customer_id'] . '.json');
        $customerAddress = $this->call('GET', '/admin/customers/' . $quoteData['customer_id'] . '/addresses/' . $quoteData['shipping_id'] . '.json');
        $customerInfo = array('first_name' => $customer['first_name'], 'last_name' => $customer['last_name'], 'email' => $customer['email']);
        $address = array(
            'first_name' => $customerAddress['first_name'],
            'last_name' => $customerAddress['last_name'],
            'address1' => $customerAddress['address1'],
            'address2' => $customerAddress['address2'],
            'phone' => $customerAddress['phone'],
            'city' => $customerAddress['city'],
            'province' => $customerAddress['province'],
            'country' => $customerAddress['country'],
            'zip' => $customerAddress['zip']
        );
        $discount = $shipping = $tax = array();
        $orderAmount = $quoteData['design_total'];
        if ($quoteData['discount_amount'] > 0) {
            $discount = array(
                'type' => "script",
                'description' => "Discount set during quptation in ImprintNext",
                'value' => $quoteData['discount_amount'],
                'value_type' => ($quoteData['discount_type'] == "flat" ? "fixed_amount" : "percentage"),
                'allocation_method' => "across",
                'target_selection' => "all",
                'target_type' => "line_item",
            );
            $discountAmnt = ($quoteData['discount_type'] == "flat" ? $quoteData['discount_amount'] : ($quoteData['discount_amount'] / 100) * $quoteData['design_total']);
            $orderAmount = $quoteData['design_total'] - $discountAmnt;
        }
        if ($quoteData['shipping_amount'] > 0) {
            $shipping = array(
                'price' => $quoteData['shipping_amount'],
                'title' => "manual",
            );
        }
        if ($quoteData['tax_amount'] > 0) {
            $tax[] = array(
                'price' => ($quoteData['tax_amount'] / 100) * $orderAmount,
                'rate' => $quoteData['tax_amount'] / 100,
                'title' => "OrderTax"
            );
            $tax[] = array(
                'price' => ($quoteData['rush_type'] == "flat" ? $quoteData['rush_amount'] : ($quoteData['rush_amount'] / 100) * $quoteData['design_total']),
                'rate' => $quoteData['shipping_amount'],
                'title' => "Rush charge"
            );
        }

        $tax1 = (($quoteData['tax_amount'] / 100) * $orderAmount);
        $tax2 = ($quoteData['rush_type'] == "flat" ? $quoteData['rush_amount'] : ($quoteData['rush_amount'] / 100) * $orderAmount);
        $totalTax =  $tax1 + $tax2;


        // order details
        $thisOrder['email'] = $customer['email'];
        $thisOrder['taxes_included'] = false;
        $thisOrder['total_tax'] = $totalTax;
        $thisOrder['total_discounts'] = ($quoteData['discount_type'] == "flat" ? $quoteData['discount_amount'] : (($quoteData['discount_amount'] / 100) * $quoteData['design_total']));
        $thisOrder['send_receipt'] = true;
        $thisOrder['send_fulfillment_receipt'] = true;
        $thisOrder['tags'] = "Quotation, " . $quoteData['quote_id'];
        $thisOrder['line_items'] = $lineItems;
        $thisOrder['customer'] = $customerInfo;
        $thisOrder['billing_address'] = $address;
        $thisOrder['shipping_address'] = $address;
        $thisOrder['note'] = ($quoteData['note']) ? $quoteData['note'] : "";
        if (!empty($tax)) {
            $thisOrder['tax_lines'] = $tax;
        }
        if (!empty($discount)) {
            $thisOrder['discount_applications'] = $discount;
        }
        if (!empty($shipping)) {
            $thisOrder['shipping_lines'] = array($shipping);
        }
        // $thisOrder['transactions'] = $address;
        // $thisOrder['financial_status'] = $address;
        $orderData['order'] = $thisOrder;
        $addOrder = $this->call('POST', '/admin/orders.json', $orderData);
        return array("id" => $addOrder['id'], "order_number" => $addOrder['order_number']);
    }
    /**
     * Get Order w.r.t Customer
     *
     * @author     debashrib@riaxe.com
     * @date       17 dec 2019
     * @param  customer id
     * @response   Array of order details
     */
    public function getOrderDetailsByCustomer($customerID)
    {
        if ($customerID != '') {
            $query = <<<JSON
            query getCustomerOrderDetails {
                customer(id: "gid://shopify/Customer/$customerID") {
                  orders(first: 10) {
                    nodes {
                      id
                      name
                      currentSubtotalLineItemsQuantity
                      currencyCode
                      poNumber
                      createdAt
                      totalPriceSet {
                        presentmentMoney {
                          currencyCode
                          amount
                        }
                      }
                      lineItems(first: 10) {
                        nodes {
                          vendor
                          name
                          quantity
                          sku
                          originalUnitPriceSet {
                            presentmentMoney {
                                amount
                            }
                        }
                          variant {
                            id
                          }
                          product {
                            id
                            tags
                            createdAt
                          }
                        }
                      }
                    }
                  }
                }
            }
        JSON;
            $customerDetails = $this->graphQlRequest($query);
            $customerOrderDetails = $customerDetails['data']['customer']['orders']['nodes'];
        }
        return $customerOrderDetails;
    }

    /**
     * retrieve orders from store
     *
     * @author debashrib@riaxe.com
     * @date  18 dec 2019
     * @param array $callParams
     * @param string lastOrderId
     * @param int store
     * @param int range
     * @param date fromDate
     * @param date toDate
     * @return json
     */
    public function ordersAll($callParams)
    {
        $sortOrder = $callParams['order'];
        $sortOrderBy = $callParams['orderby'];
        $customerID = $callParams['customer_id'];

        // set server timezone
        $shop = $this->call('GET', '/admin/shop.json?fields=iana_timezone');
        if (!empty($shop['iana_timezone'])) {
            date_default_timezone_set($shop['iana_timezone']);
        }

        // geting orders with filter
        if (!empty($customerID)) {
            $orders = $this->call('GET', '/admin/customers/' . $customerID . '/orders.json?status=any');
        } else {
            $orders = $this->orders_get($callParams);
        }
        $cancelIDs = [];
        $closedIDs = [];
        $canceledOrders = $this->call('GET', '/admin/orders.json?status=cancelled');
        $cancelIDs = array_column($canceledOrders, 'id');

        $archivedOrders = $this->call('GET', '/admin/orders.json?status=closed');
        $closedIDs = array_column($archivedOrders, 'id');

        // Get total order count
        $ordersCount = (!empty($orders)) ? count($orders) : 0;

        $finalResult = [];
        $result = [];
        // Get total order count
        if ($ordersCount > 0) {
            foreach ($orders as $order) {
                $res = [];
                if (in_array($order['id'], $cancelIDs)) {
                    $status = "Canceled";
                } elseif (in_array($order['id'], $closedIDs)) {
                    $status = "Archived";
                } else {
                    $status = self::shopify_order_status($order);
                }
                $res = [
                    "id" => $order['id'],
                    "order_number" => $order['order_number'],
                    "customer_id" => $order['customer']['id'],
                    "customer_first_name" => $order['customer']['first_name'],
                    "customer_last_name" => $order['customer']['last_name'],
                    "created_date" => date('Y-m-d H:i:s', strtotime($order['created_at'])),
                    "total_amount" => (float)round($order['total_price'], 2),
                    "currency" => $order['currency'],
                    "order_total_quantity" => array_sum(array_column($order['line_items'], 'quantity')),
                    "production" => '',
                    "is_customize" => $order['is_customize'],
                    "status" => $status
                ];
                $result[] = $res;
            }
            // Sorting Order result
            if (isset($sortOrder) && isset($sortOrderBy) && $sortOrder != '' && $sortOrderBy != '') {
                // sort by price
                if ($sortOrderBy == 'price') {
                    if ($sortOrder == 'desc') {
                        $finalResult = $this->array_sort_by_column($result, 'total_amount', SORT_DESC);
                    } else {
                        $finalResult = $this->array_sort_by_column($result, 'total_amount', SORT_ASC);
                    }
                    // sort by customer
                } elseif ($sortOrderBy == 'name') {
                    if ($sortOrder == 'desc') {
                        $finalResult = $this->array_sort_by_column($result, 'customer_first_name', SORT_DESC);
                    } else {
                        $finalResult = $this->array_sort_by_column($result, 'customer_first_name', SORT_ASC);
                    }
                    // sort by date
                } elseif ($sortOrderBy == 'date') {
                    if ($sortOrder == 'desc') {
                        $finalResult = $this->array_sort_by_column($result, 'created_date', SORT_DESC);
                    } else {
                        $finalResult = $this->array_sort_by_column($result, 'created_date', SORT_ASC);
                    }
                } else {
                    $finalResult = $result;
                }
            } else {
                $finalResult = $result;
            }
        }

        return $finalResult;
    }

    /**
     * retrieve order details from store
     *
     * @param array $callParams
     * @param string orderIncrementId
     * @param int store
     * @return json
     */
    public function orderDetails($args)
    {
        $order_id = $args['id'];
        $order = $this->call('GET', '/admin/orders/' . $order_id . '.json');
        $billingAddress = [];
        $shippingAddress = [];
        $lineItems = [];
        $colorPos = "";
        $sizePos = "";

        // set server timezone
        $shop = $this->call('GET', '/admin/shop.json?fields=iana_timezone');
        if (!empty($shop['iana_timezone'])) {
            date_default_timezone_set($shop['iana_timezone']);
        }

        // Getting Billing Address of perticular order
        $billingAddress = [
            'first_name' => $order['billing_address']['first_name'],
            'last_name' => ($order['billing_address']['last_name'] != '') ? $order['billing_address']['last_name'] : '',
            'email' => $order['email'],
            'phone' => ($order['billing_address']['phone'] != '') ? $order['billing_address']['phone'] : '',
            'address_1' => ($order['billing_address']['address1'] != '') ? $order['billing_address']['address1'] : '',
            'address_2' => ($order['billing_address']['address2'] != '') ? $order['billing_address']['address2'] : '',
            'country' => $order['billing_address']['country'],
            'state' => $order['billing_address']['province'],
            'city' => $order['billing_address']['city'],
            'postcode' => $order['billing_address']['zip'],
            'company' => ($order['billing_address']['company'] != '') ? $order['billing_address']['company'] : '',
            'country_code' => $order['billing_address']['country_code'],
            'state_code' => $order['billing_address']['province_code'],
        ];

        // Getting Shipping Address of perticular order
        $shippingAddress = [
            'first_name' => $order['shipping_address']['first_name'],
            'last_name' => $order['shipping_address']['last_name'],
            'email' => $order['email'],
            'phone' => ($order['shipping_address']['phone'] != '') ? $order['shipping_address']['phone'] : '',
            'address_1' => ($order['shipping_address']['address1'] != '') ? $order['shipping_address']['address1'] : '',
            'address_2' => ($order['shipping_address']['address2'] != '') ? $order['shipping_address']['address2'] : '',
            'country' => $order['shipping_address']['country'],
            'state' => $order['shipping_address']['province'],
            'city' => $order['shipping_address']['city'],
            'postcode' => $order['shipping_address']['zip'],
            'company' => ($order['shipping_address']['company'] != '') ? $order['shipping_address']['company'] : '',
            'country_code' => $order['shipping_address']['country_code'],
            'state_code' => $order['shipping_address']['province_code'],
        ];


        // Getting line items of perticular order
        $orderItems = [];
        if (isset($args['ui'])) {
            if (!empty($order['line_items'])) {
                foreach ($order['line_items'] as $lineItems) {

                    $refID = '';
                    foreach ($lineItems['properties'] as $value) {
                        if ($value['name'] == "_refid") {
                            $refID = $value['value'];
                            break;
                        }
                    }

                    if ($refID == 0 && $lineItems['vendor'] == "imprintNext") {
                        $productQuery = <<<JSON
                                        {
                                          product(id: "gid://shopify/Product/{$lineItems['product_id']}") {
                                                id
                                                tags
                                               }
                                        }
                                    JSON;
                        $productData = $this->graphQlRequest($productQuery);
                        foreach ($productData['data']['product']['tags'] as $tagValues) {
                            if (strpos($tagValues, 'IMP_REF_ID_') !== false) {
                                $tags = explode('IMP_REF_ID_', $tagValues);
                            }
                        }
                        $tags = $tags[1];
                        $tags = explode(',', $tags);
                        $refID = $tags[0];
                    }

                    $customDesignId = (isset($refID) && $refID != '') ? $refID : '';

                    $tag = (explode(", ", $order['tags']));
                    if (in_array("Quotation", $tag)) {
                        $quote = 1;
                    }

                    //$variant = $this->call('GET', '/admin/variants/' . $lineItems['variant_id'] . '.json');
                    $variantQuery = <<<JSON
                                                {
                                                productVariant(id: "gid://shopify/ProductVariant/{$lineItems['variant_id']}") {
                                                    id
                                                    selectedOptions {
                                                        name
                                                        value
                                                     }
                                                     inventoryItem {
                                                        measurement {
                                                            weight {
                                                            unit
                                                            value
                                                            }
                                                        }
                                                      }
                                                   }
                                                }
                                             JSON;

                    $variantQueryResult = $this->graphQlRequest($variantQuery);
                    $variant = $variantQueryResult['data']['productVariant'];
                    if (!empty($variant['selectedOptions'])) {
                        foreach ($variant['selectedOptions'] as $variantData) {

                            if (strtolower($this->sizeAttrName) == strtolower($variantData['name'])) {
                                $sizeValue = $variantData['name'];
                            }
                            if (strtolower($this->colorAttrName) == strtolower($variantData['name'])) {
                                $colorValue = $variantData['name'];
                            }
                            if ('stitch_color' == strtolower($variantData['name'])) {
                                $stitchValue = $variantData['name'];
                            }
                        }
                    }
                    // $stitchColorPos = $this->getAttributePostion('stitch_color', $lineItems['product_id']);
                    $orgVarId = $this->getParentVariantID($lineItems['variant_id']);
                    $realProdData = json_decode($this->shopifyParentProductID($orgVarId), true);
                    if (strtolower($lineItems['name']) != 'custom price') {
                        $customPriceIndex = array_search('Custom price', array_column($lineItems['properties'], 'name'));
                        $price = ($customPriceIndex !== false)  ? (int)$lineItems['price'] + (int)$lineItems['properties'][$customPriceIndex]['value'] : $lineItems['price'];
                        $thisLineItem =  [
                            'id' => $lineItems['id'],
                            'product_id' => $lineItems['product_id'],
                            'variant_id' => $lineItems['variant_id'],
                            'parent_prod_id' => $realProdData['pid'],
                            'parent_var_id' => $realProdData['vid'],
                            'name' => $lineItems['title'] == "Sticker" ? $lineItems['title'] : $lineItems['name'],
                            'price' =>  (float)round($price, 2),
                            'quantity' => $lineItems['quantity'],
                            'total' => (float)round(($price * $lineItems['quantity']), 2),
                            'sku' => $lineItems['sku'],
                            'custom_design_id' => $customDesignId,
                            'size' => $sizeValue,
                            'color' => $colorValue,
                            'stitch_color' => $stitchValue,
                            'images' => $refID > 0 ? $this->getStoreProductImages($refID, $lineItems['variant_id']) : $this->getQuoteImages($lineItems['properties'], $lineItems['variant_id']),
                            'productDecorationSettingData' => '',
                            'weight' => $variant['inventoryItem']['measurement']['weight']['value'],
                            'weight_unit' => $variant['inventoryItem']['measurement']['weight']['unit'],
                            'is_quote_order' => isset($quote) ? $quote : 0
                        ];
                    }


                    if (isset($thisLineItem) && empty($thisLineItem['images'])) {
                        $rawVariant = $this->getVariantDetails($lineItems['variant_id']);
                        $thisProductID = $this->getNumericData($rawVariant['product']['id']);
                        $rawProduct = $this->getProductDetails($thisProductID);

                        if (!empty($rawVariant['image'])) {
                            $thisLineItem['images'][] = array(
                                "src" => $rawVariant['image']['url'],
                                "thumbnail" => $rawVariant['image']['url']
                            );
                        } else {
                            foreach ($rawProduct['images']['nodes'] as $eachProdimg) {
                                $thisLineItem['images'][] = array(
                                    "src" => $eachProdimg['url'],
                                    "thumbnail" => $eachProdimg['url']
                                );
                            }
                        }
                    }

                    if (isset($thisLineItem)) {
                        $orderItems[$customDesignId]['line_items'][] = $thisLineItem;
                    }
                }
                $orderItems = array_values($orderItems);
            }
        } else {
            if (!empty($order['line_items'])) {
                foreach ($order['line_items'] as $lineItems) {
                    $refID = '';
                    foreach ($lineItems['properties'] as $value) {
                        if ($value['name'] == "_refid") {
                            $refID = $value['value'];
                            break;
                        }
                    }
                    if ($refID == 0 && $lineItems['vendor'] == "imprintNext") {
                        $productQuery = <<<JSON
                                        {
                                          product(id: "gid://shopify/Product/{$lineItems['product_id']}") {
                                                id
                                                tags
                                               }
                                        }
                                    JSON;
                        $productData = $this->graphQlRequest($productQuery);
                        foreach ($productData['data']['product']['tags'] as $tagValues) {
                            if (strpos($tagValues, 'IMP_REF_ID_') !== false) {
                                $tags = explode('IMP_REF_ID_', $tagValues);
                            }
                        }
                        $refID = $tags[1];
                    }
                    $tag = (explode(", ", $order['tags']));
                    if (in_array("Quotation", $tag)) {
                        $quote = 1;
                    }

                    $variantQuery = <<<JSON
                                    {
                                      productVariant(id: "gid://shopify/ProductVariant/{$lineItems['variant_id']}") {
                                            id
                                            selectedOptions {
                                                   name
                                                   value
                                              }
                                            inventoryItem {
                                                measurement {
                                                  weight {
                                                     unit
                                                     value
                                                   }
                                                }
                                              }
                                          }
                                      }
                            JSON;

                    $variantQueryResult = $this->graphQlRequest($variantQuery);
                    $variant = $variantQueryResult['data']['productVariant'];

                    if (!empty($variant['selectedOptions'])) {
                        foreach ($variant['selectedOptions'] as $variantData) {

                            if (strtolower($this->sizeAttrName) == strtolower($variantData['name'])) {
                                $sizeValue = $variantData['name'];
                            }
                            if (strtolower($this->colorAttrName) == strtolower($variantData['name'])) {
                                $colorValue = $variantData['name'];
                            }
                            if ('stitch_color' == strtolower($variantData['name'])) {
                                $stitchValue = $variantData['name'];
                            }
                        }
                    }
                    if (strtolower($lineItems['name']) != 'custom price') {
                        $customPriceIndex = array_search('Custom price', array_column($lineItems['properties'], 'name'));
                        $price = $customPriceIndex !== false ? $lineItems['price'] + $lineItems['properties'][$customPriceIndex]['value'] : $lineItems['price'];
                        $thisLineItem = [
                            'id' => $lineItems['id'],
                            'product_id' => $lineItems['product_id'],
                            'variant_id' => $lineItems['variant_id'],
                            'name' => $lineItems['name'],
                            'price' => (float)round($price, 2),
                            'quantity' => $lineItems['quantity'],
                            'total' => (float)round(($price * $lineItems['quantity']), 2),
                            'sku' => $lineItems['sku'],
                            'custom_design_id' => (isset($refID) && $refID != '') ? $refID : '',
                            'size' => !empty($sizeValue) ? $sizeValue : '',
                            'color' => !empty($colorValue) ? $colorValue : '',
                            'stitch_color' => !empty($stitchValue) ? $stitchValue : '',
                            'images' => $refID > 0 ? $this->getStoreProductImages($refID, $lineItems['variant_id']) : $this->getQuoteImages($lineItems['properties'], $lineItems['variant_id']),
                            'productDecorationSettingData' => '',
                            'weight' => $variant['inventoryItem']['measurement']['weight']['value'],
                            'weight_unit' => $variant['inventoryItem']['measurement']['weight']['unit'],
                            'is_quote_order' => isset($quote) ? $quote : 0
                        ];
                    }
                    if (isset($thisLineItem) && empty($thisLineItem['images'])) {
                        $rawVariant = $this->getVariantDetails($lineItems['variant_id']);
                        $thisProductID = $this->getNumericData($rawVariant['product']['id']);
                        $rawProduct = $this->getProductDetails($thisProductID);

                        if (!empty($rawVariant['image'])) {
                            $thisLineItem['images'][] = array(
                                "src" => $rawVariant['image']['url'],
                                "thumbnail" => $rawVariant['image']['url']
                            );
                        } else {
                            foreach ($rawProduct['images']['nodes'] as $eachProdimg) {
                                $thisLineItem['images'][] = array(
                                    "src" => $eachProdimg['url'],
                                    "thumbnail" => $eachProdimg['url']
                                );
                            }
                        }
                    }
                    if (isset($thisLineItem)) {
                        $orderItems[] = $thisLineItem;
                    }
                }
            }
        }

        return [
            "id" => $order['id'],
            "order_number" => $order['order_number'],
            "customer_first_name" => $order['customer']['first_name'],
            "customer_last_name" => $order['customer']['last_name'],
            "customer_email" => $order['email'],
            "customer_id" => $order['customer']['id'],
            "created_date" => date('Y-m-d H:i:s', strtotime($order['created_at'])),
            "total_amount" => (float)($order['taxes_included'] ? round(($order['total_line_items_price'] - $order['total_tax']), 2) : round($order['total_line_items_price'], 2)),
            "total_tax" => (float)round($order['total_tax'], 2),
            "total_shipping" => (float)round($order['shipping_lines'][0]['price'], 2),
            "total_discounts" => (float)round($order['total_discounts'], 2),
            "currency" => $order['currency'],
            "note" => ($order['note'] != '') ? $order['note'] : '',
            "production" => '',
            "status" => self::shopify_order_status($order),
            "total_orders" => $order['customer']['orders_count'],
            "billing" => $billingAddress,
            "shipping" => $shippingAddress,
            "payment" => $order['gateway'] . " gateway",
            "store_url" => "https://{$this->shopDomain}/",
            "orders" => $orderItems
        ];
    }

    private function getQuoteImages($properties, $variantID = "")
    {
        $images = array();
        $propNames = array_column($properties, "name");
        if (empty($properties) || !in_array("_refid", $propNames)) {
            $variantImageQuery = <<<JSON
                                    query variantDetails {
                                    productVariant(id: "gid://shopify/ProductVariant/$variantID") {
                                        image {
                                              id
                                          }
                                          product {
                                              id
                                            }
                                        }
                                      }
                                 JSON;
            $variantImages = $this->graphQlRequest($variantImageQuery);
            $variantImageData = $variantImages['data']['productVariant'];
            if (!empty($variantImageData['image'])) {
                $productImageQuery = <<<JSON
                                        query productdetails {
                                        product(id: "{$variantImageData['product']['id']}") {
                                            images(first: 50) {
                                                edges {
                                                    node {
                                                      id
                                                      url
                                                    }
                                                  }
                                                }
                                            }
                                    }
                            JSON;
                $productImagesData = $this->graphQlRequest($productImageQuery);
                $productImages = $productImagesData['data']['product']['images']['edges'];
                foreach ($productImages as $imagesData) {
                    if ($this->getNumericData($imagesData['node']['id']) == $this->getNumericData($variantImageData['image']['id'])) {
                        $images[] =  array("src" => $imagesData['node']['url'], "thumbnail" => $imagesData['node']['url']);
                        break;
                    }
                }
            } else {
                $productImageQuery = <<<JSON
                                        query productdetails {
                                        product(id: "{$variantImageData['product']['id']}") {
                                            images(first: 20) {
                                                edges {
                                                    node {
                                                    id
                                                    url
                                                    }
                                                }
                                              }
                                            }
                                         }
                                    JSON;
                $productImages = $this->graphQlRequest($productImageQuery);
                $productData = $productImages['data']['product']['images'];
                $images[] =  array("src" => $productData['edges'][0]['node']['url'], "thumbnail" => $productData['edges'][0]['node']['url']);
            }
        } else {
            foreach ($properties as $prop) {
                if (strpos($prop['name'], 'preview_url_') !== false) {
                    $images[] =  array("src" => $prop['value'], "thumbnail" => $prop['value']);
                }
            }
        }

        return $images;
    }

    /**
     * GET: Shopify order details
     *
     * @param $orderID requested order ID
     * @return Array order details
     */
    public function orderInfo($orderID)
    {
        $order = $this->call('GET', '/admin/orders/' . $orderID . '.json');
        $orderDetails = $orderItems = [];
        $lineItems = [];
        foreach ($order['line_items'] as $lineItems) {
            foreach ($lineItems['properties'] as $value) {
                if ($value['name'] == "_refid") {
                    $refID = $value['value'];
                    break;
                } else {
                    $refID = '';
                }
            }
            if ($refID == 0 && $lineItems['vendor'] == "imprintNext") {
                // get prod data $lineItems['product_id']
                $productData = $this->call('GET', '/admin/products/' . $lineItems['product_id'] . '.json');
                $tags = $productData['tags'];
                $tags = explode('IMP_REF_ID_', $tags);
                $tags = $tags[1];
                $tags = explode(',', $tags);
                $refID = $tags[0];
            }
            if (strtolower($lineItems['name']) != 'custom price') {
                $thisLineItem = [
                    'item_id' => $lineItems['id'],
                    'print_status' => "",
                    'product_id' => $lineItems['product_id'],
                    'variant_id' => $lineItems['variant_id'],
                    'product_sku' => $lineItems['sku'],
                    'product_name' => $lineItems['title'],
                    'quantity' => $lineItems['quantity'],
                    'images' => $refID > 0 ? $this->getStoreProductImages($refID, $lineItems['variant_id']) : $this->getQuoteImages($lineItems['properties'], $lineItems['variant_id']),
                    'categories' => array_column($this->getProductCategories($lineItems['product_id']), 'id'),
                    'ref_id' => (isset($refID) && $refID != '') ? $refID : ''
                ];
            }
            try {
                $this->adjustProductInventory($lineItems['variant_id'], $lineItems['quantity'], 0);
            } catch (\Exception $e) {
                $thisLineItem['inventory_update'] = "failed";
            }
            if (isset($thisLineItem)) {
                $orderItems[] = $thisLineItem;
            }
        }
        $orderDetails['order_details'] = [
            "order_id" => $order['id'],
            "customer_id" => $order['customer']['id'],
            "store_id" => 1,
            "order_incremental_id" => $order['order_number'],
            "order_items" => $orderItems
        ];
        return json_encode($orderDetails);
    }

    /**
     * Adjust inventory of items after the order is placed with duplicate products.
     *
     * @param params order item variant id and item quantity
     */
    private function adjustProductInventory($dupVariantID, $quantity, $isUpdate)
    {
        $status = 0;
        $VariantID = $this->getParentVariantID($dupVariantID);
        $variantDetails = <<<JSON
                                query variantsData {
                                productVariant(id: "gid://shopify/ProductVariant/$VariantID") {
                                    id
                                    inventoryQuantity
                                    inventoryItem {
                                    id
                                    inventoryLevels(first: 10) {
                                        edges {
                                        node {
                                            location {
                                            id
                                            isActive
                                            }
                                        }
                                      }
                                    }
                                  }
                               }
                            }

                        JSON;

        $variantInfo = $this->graphQlRequest($variantDetails);
        $variant = $variantInfo['data']['productVariant'];
        if (!empty($variant['inventoryItem']['inventoryLevels']['edges'])) {
            $adjustQuantity = ($isUpdate == 1) ? $quantity : -$quantity;
            $updateInventory = <<<JSON
                           mutation {
                             inventoryAdjustQuantities(
                                 input: {changes: {delta: {$adjustQuantity}, inventoryItemId: "{$variant['inventoryItem']['id']}", locationId: "{$variant['inventoryItem']['inventoryLevels']['edges'][0]['node']['location']['id']}"}, name: "available", reason: "correction"}
                             ) {
                                 userErrors {
                                    message
                                 }
                              }
                         }
                    JSON;
            $this->graphQlRequest($updateInventory);
            $status = 1;
        } else {
            $invLevels = $this->call('GET', '/admin/inventory_levels.json?inventory_item_ids=' . $variant['inventory_item_id']);
            if (!empty($invLevels)) {
                $newInventory = array(
                    "location_id" => $invLevels[0]['location_id'],
                    "inventory_item_id" => $variant['inventory_item_id'],
                    "available_adjustment" => ($isUpdate == 1) ? $quantity : -$quantity,
                );
                $this->call('POST', '/admin/inventory_levels/adjust.json', $newInventory);
                $status = 1;
            }
        }

        return $status;
    }

    /**
     * get orders from store
     *
     * @param params order filter parameters
     */
    private function orders_get($params)
    {
        $ordersData = [];
        $orders = [];
        $finalOrder = [];
        $QRYparams['limit'] = $params['per_page'];
        $customize = $params['is_customize'];
        $fromDate = ($params['fromDate'] != '') ? date("Y-m-d\TH:i:s", strtotime($params['fromDate'])) : '';
        $toDate = ($params['toDate'] != '') ? date("Y-m-d\TH:i:s", strtotime($params['toDate'] . ' +1 day')) : '';
        $sku = ($params['sku'] != '') ? $params['sku'] : '';
        $orderStatus = $params['order_status'];
        $QRYparams['status'] = (!empty($orderStatus) && $orderStatus == 'archive') ? "closed" : "open";
        if ($fromDate && $toDate) {
            $QRYparams['created_at_min'] = $fromDate;
            $QRYparams['created_at_max'] = $toDate;
        }
        if ($params['search'] != '') {
            $QRYparams['name'] = $params['search'];
        }
        $orderCount = 0;
        $ordersData = 0;
        if (empty($QRYparams['limit'])) {
            $QRYparams['limit'] = 250;
            $params['page'] = 1;
        }
        $maxloop = 0;
        do {
            $maxloop++;
            if ($orderCount == 0 && $ordersData == 0 && $params['page'] == 1) {
                $ordersData = $this->call('GET', '/admin/orders.json', $QRYparams, "orders");
            } elseif ($params['page'] == 0) {
                $cursorURL = substr($_SESSION['orders']['previous'], strpos($_SESSION['orders']['previous'], "/admin"));
                $ordersData = $this->call('GET', $cursorURL, array(), "orders");
            } else {
                $cursorURL = substr($_SESSION['orders']['next'], strpos($_SESSION['orders']['next'], "/admin"));
                $ordersData = $this->call('GET', $cursorURL, array(), "orders");
            }
            // return data based on customize filter
            $dataCount = (!empty($ordersData)) ? count($ordersData) : 0;
            if ($dataCount > 0) {
                foreach ($ordersData as $order) {
                    $getProp = array();
                    foreach ($order['line_items'] as $lt) {
                        $refID = '';
                        foreach ($lt['properties'] as $vaalue) {
                            if ($vaalue['name'] == "_refid") {
                                $refID = $lt['properties'][0]['value'];
                                break;
                            }
                        }
                        if ($refID == '' && $lt['vendor'] == "imprintNext") {
                            // get prod data $lineItems['product_id']
                            $productData = $this->getProductDetails($lt['product_id']);
                            $tags = $productData['tags'];
                            foreach ($tags as $tag) {
                                if (preg_match('/IMP_REF_ID_(\d+)/', $tag, $matches)) {
                                    $refID = $matches[1];
                                    break;
                                }
                            }
                        }
                        if ($refID) {
                            $getProp[] = $refID;
                        }
                    }
                    if (!empty($getProp)) {
                        $order['is_customize'] = 1;
                        $customOrders[] = $order;
                    } else {
                        $order['is_customize'] = 0;
                        $blankOrders[] = $order;
                    }
                    $allOrders[] = $order;
                }
            }
            if (isset($customize) && $customize == 1) {
                $orders = $customOrders;
            } else {
                $orders = $allOrders;
            }
            if (isset($sku) && $sku != '') {
                if (!empty($orders)) {
                    foreach ($orders as $skuOrder) {
                        $getSKU = array();
                        if (!empty($getSKU)) {
                            $finalOrder[] = $skuOrder;
                        }
                    }
                }
            } else {
                $finalOrder = $orders;
            }
            $orderCount = (!empty($finalOrder)) ? count($finalOrder) : 0;
        } while ($orderCount < $params['per_page'] && $dataCount == $params['per_page']  && $maxloop < 8);
        return $finalOrder;
    }

    /**
     * get order status from store
     *
     * @param array $order
     */
    private function shopify_order_status($order)
    {
        if ($order['financial_status'] == "refunded") {
            return "Refunded";
        }
        if ($order['fulfillment_status'] && $order['financial_status'] != "refunded") {
            if ($order['fulfillment_status'] == "partial") {
                return "Processing";
            } else {
                return "Complete";
            }
        }
        return "Pending";
    }

    /**
     * GET: Shopify store images
     *
     * @param $productId selected product ID
     * @return Array product details
     */
    public function getStoreProductImages($refID, $variantID)
    {
        $parentVarID = $this->getParentVariantID($variantID);
        $stateDesignPath = path('abs', 'design_state') . 'carts/' . $refID . '.json';
        $productImages = [];
        if (!file_exists($stateDesignPath)) {
            $stateDesignPath = path('abs', 'design_state') . 'predecorators/' . $refID . '.json';
        }
        if (!file_exists($stateDesignPath)) {
            $stateDesignPath = path('abs', 'design_state') . 'quotes/' . $refID . '.json';
        }
        if (!file_exists($stateDesignPath)) {
            $stateDesignPath = path('abs', 'design_state') . 'artworks/' . $refID . '.json';
        }
        if (file_exists($stateDesignPath)) {
            $jsonData = json_clean_decode(file_get_contents($stateDesignPath), true);
            if (!empty($jsonData)) {
                foreach ($jsonData['design_product_data'] as $designProductData) {
                    if ((is_array($designProductData)
                            && in_array($parentVarID, $designProductData['variant_id']))
                        || $designProductData['variant_id'] == $variantID
                    ) {
                        $customImageUrl = $designProductData['design_urls'];
                        break;
                    }
                }
                if (empty($customImageUrl)) {
                    $customImageUrl = $jsonData['design_product_data'][0]['design_urls'];
                }
                foreach ($customImageUrl as $key => $customImage) {
                    $img = [
                        "id" => ($key + 1),
                        "src" => $customImage,
                        "thumbnail" => $customImage,
                    ];
                    $productImages[] = $img;
                }
            }
        }
        return $productImages;
    }

    /**
     * retrieve attribute position
     *
     * @param int product id
     * @param string attribute
     * @return attribute position
     */
    public function getAttributePostion($attribute, $productId)
    {
        $query = <<<JSON
        query starts {
            product(id: "gid://shopify/Product/$productId") {
              options {
                position
                name
              }
            }
        }
        JSON;
        $productArr = $this->graphQlRequest($query, '/product/' . $productId . '.json');
        $product = $productArr['data']['product'];
        $pos = "";
        foreach ($product['options'] as $option) {
            if (strtolower($option['name']) == strtolower($attribute)) {
                $pos = $option['position'];
            }
        }
        return $pos;
    }

    /**
     * retrieve sorted array
     *
     * @param array
     * @param string array column name short by
     * @param string asc/desc
     * @return sortted array
     */
    public function array_sort_by_column($arr, $col, $dir)
    {
        $sortCol = array();
        $sortCol = array_column($arr, $col);
        array_multisort($sortCol, $dir, SORT_NATURAL | SORT_FLAG_CASE, $arr);
        return $arr;
    }

    /**
     * hide or delete duplicate products
     *
     * @param product id
     * @param string delete_status
     * @return status
     */
    public function editCustomCartProduct($call_params)
    {
        $dupVariantID = $call_params['variant_id'];
        $quantity = $call_params['isQuantity'];
        if (!empty($quantity) && !empty($dupVariantID)) {
            $this->adjustProductInventory($dupVariantID, $quantity, 1);
        }
        $isCustom = false;
        //check if product is not the custom product
        $getProductHandle = <<<JSON
         query productHandle {
                 product(id: "gid://shopify/Product/{$call_params['product_id']}") {
                     handle
                 }
            }
        JSON;
        $checkProdHandle = $this->graphQlRequest($getProductHandle);
        if (!empty($checkProdHandle['data']['product']) && strtolower($checkProdHandle['data']['product']['handle']) != 'custom-price') {
            $getCollectionQuery = <<<JSON
                    query getCollectionQuery {
                        product(id: "gid://shopify/Product/{$call_params['product_id']}") {
                            collections(first: 10) {
                            nodes {
                                handle
                            }
                            }
                        }
                    }
                JSON;
            $checkProdArr = $this->graphQlRequest($getCollectionQuery);
            $checkProd = $checkProdArr['data']['product']['collections']['nodes'];
            if (!empty($checkProd) || isset($checkProd['Tags'])) {
                foreach ($checkProd as $prod) {
                    if ($prod['handle'] == "customized") {
                        $isCustom = true;
                    }
                }
            }
        }
        if ($call_params['isDelete'] == 0 && $isCustom) {
            $publicationId = $this->getPublicationId();
            $unpublishQuery = <<<JSON
                            mutation productUnpublish {
                                publishableUnpublish(
                                    id: "gid://shopify/Product/{$call_params['product_id']}"
                                    input: {publicationId: "$publicationId"}
                                ) {
                                    publishable {
                                        ... on Product {
                                            id
                                        }
                                    }
                                }
                            }
                     JSON;
            return $this->graphQlRequest($unpublishQuery);
        } elseif ($call_params['isDelete'] == 1 && $isCustom) {
            $deleteProduct = <<<JSON
                            mutation deleteProduct {
                                productDelete(input: {id: "gid://shopify/Product/{$call_params['product_id']}"}) {
                                    deletedProductId
                                }
                             }
                        JSON;
            return $this->graphQlRequest($deleteProduct);
        }
    }
    /**
     * retrieve order logs
     *
     * @param string orderID
     * @return array of order log from Shopify
     */
    public function getOrderLog($orderId)
    {
        $order = $this->call('GET', '/admin/orders/' . $orderId . '.json');
        $orderLogs = [];
        $storeLogs = [];
        if ($order['cancelled_at'] && $order['cancelled_at'] != "") {
            $storeLogs[] = array("log_type" => "order_status", "message" => "Order cancelled because " . $order['cancel_reason'] . " .", "created_at" => date("Y-m-d h:i:s", strtotime($order['cancelled_at'])), "updated_at" => date("Y-m-d h:i:s", strtotime($order['cancelled_at'])));
        }
        if ($order['fulfillment_status'] && $order['cancelled_at'] != "") {
            $storeLogs[] = array("log_type" => "order_status", "message" => "Order Fulfilled.", "created_at" => date("Y-m-d h:i:s", strtotime($order['cancelled_at'])), "updated_at" => date("Y-m-d h:i:s", strtotime($order['cancelled_at'])));
        }
        $storeLogs[] = array("log_type" => "order_status", "message" => "Order confirmation sent at " . $order['email'] . ".", "created_at" => date("Y-m-d h:i:s", strtotime($order['created_at'])), "updated_at" => date("Y-m-d h:i:s", strtotime($order['updated_at'])));
        $storeLogs[] = array("log_type" => "payment_status", "message" => $order['total_price'] . " " . $order['currency'] . " through " . $order['gateway'] . " is " . $order['financial_status'] . ".", "created_at" => date("Y-m-d h:i:s", strtotime($order['created_at'])), "updated_at" => date("Y-m-d h:i:s", strtotime($order['updated_at'])));
        $storeLogs[] = array("log_type" => "order_status", "message" => "Order placed through " . $order['source_name'] . " channel.", "created_at" => date("Y-m-d h:i:s", strtotime($order['created_at'])), "updated_at" => date("Y-m-d h:i:s", strtotime($order['updated_at'])));
        foreach ($storeLogs as $log) {
            if (is_array($log) && !empty($log)) {
                $log['agent_type'] = "admin";
                $log['agent_id'] = "";
                $log['status'] = "new";
                $orderLogs[] = $log;
            }
        }

        return json_encode($orderLogs);
    }

    /**
     * update order status
     *
     * @param string orderID
     * @return boolean status
     */
    public function updateOrderStatuses($orderId, $orderData)
    {
        $orderStatus = $orderData['statusKey'];
        switch ($orderStatus) {
            case 'closed':
                $orderResponse = $this->call('POST', '/admin/orders/' . $orderId . '/close.json');
                break;
            case 'cancelled':
                $orderResponse = $this->call('POST', '/admin/orders/' . $orderId . '/cancel.json');
                break;
            case 'refunded':
                $orderResponse = $this->call('POST', '/admin/orders/' . $orderId . '/cancel.json');
                break;
            case 'reopened':
                $orderResponse = $this->call('POST', '/admin/orders/' . $orderId . '/open.json');
                break;
            default:
                $orderResponse = array("id" => $orderId);
                break;
        }
        return array('id' => $orderResponse['id']);
    }

    public function archiveShopOrders($params)
    {
        $orderIDs = explode(",", str_replace(array('[', ']'), '', $params['order_id']));
        foreach ($orderIDs as $orderID) {
            $this->call('POST', '/admin/orders/' . $orderID . '/close.json');
        }
        return array("status" => 1);
    }

    public function getOrderLineItemData($orderID, $orderItemId, $is_customer, $flag = 0)
    {
        $order = $this->call('GET', '/admin/orders/' . $orderID . '.json');
        $orderData = array();
        $orderData['order_id'] = $order['id'];
        $orderData['order_number'] = $order['order_number'];
        $orderData['item_id'] = $orderItemId;
        foreach ($order['line_items'] as $item) {
            if (!empty($item['properties'])) {
                foreach ($item['properties'] as $value) {
                    if ($value['name'] == "_refid") {
                        $refID = $value['value'];
                    } else {
                        continue;
                    }
                }
            }

            if ($item['id'] == $orderItemId && $item['title'] != 'Custom Price') {
                $parentProdID = $this->shopifyParentProductID($item['variant_id']);
                $parentProdIDs = json_decode($parentProdID, true);
                $orderData['product_id'] = $parentProdIDs['pid'];
                $orderData['variant_id'] = $parentProdIDs['vid'];
                $orderData['name'] = $item['title'];
                $orderData['quantity'] = $item['quantity'];
                $orderData['sku'] = $item['sku'];
                $orderData['price'] = $item['price'];
                $orderData['total'] = $item['price_set']['shop_money']['amount'];
                if (!$flag) {
                    $images = $refID > 0 ? $this->getStoreProductImages($refID, $item['variant_id']) : $this->getQuoteImages($item['properties'], $parentProdIDs['vid']);
                } else {
                    $images = $this->getShopProductImages($orderData['product_id']);
                }
                $orderData['images'] = $images;
                $orderData['categories'] = $this->getProductCategories($parentProdID);
                $orderData['attributes'] = [];
                $orderData['custom_design_id'] = (isset($refID) && $refID != '') ? $refID : '';
                $orderData['customer_id'] = $item['customer']['id'];
                $orderData['customer_email'] = $item['customer']['email'];
                $orderData['customer_first_name'] = $item['customer']['first_name'];
                $orderData['customer_last_name'] = $item['customer']['last_name'];
                $orderData['billing'] = array(
                    'first_name' => $order['billing_address']['first_name'],
                    'last_name' => $order['billing_address']['last_name'],
                    'company' => $order['billing_address']['company'],
                    'address_1' => $order['billing_address']['address1'],
                    'address_2' => $order['billing_address']['address2'],
                    'city' => $order['billing_address']['city'],
                    'state' => $order['billing_address']['province'],
                    'country' => $order['billing_address']['country'],
                    'postcode' => $order['billing_address']['zip']
                );
                $orderData['shipping'] = array(
                    'first_name' => $order['billing_address']['first_name'],
                    'last_name' => $order['shipping_address']['last_name'],
                    'company' => $order['shipping_address']['company'],
                    'address_1' => $order['shipping_address']['address1'],
                    'address_2' => $order['shipping_address']['address2'],
                    'city' => $order['shipping_address']['city'],
                    'state' => $order['shipping_address']['province'],
                    'country' => $order['shipping_address']['country'],
                    'postcode' => $order['shipping_address']['zip']
                );
                $orderData['country'] = $order['shipping_address']['country'];
                $orderData['postcode'] = $order['shipping_address']['zip'];
            }
        }

        return $orderData;
    }
    /**
     * Get Order short info for purchase order
     *
     * @author     sonali@imprintnext.com
     * @date       08 nov 2022
     * @param  customer id
     * @response   Array of order details
     */

    public function getOrderShotInfo($orderIds, $storeId)
    {
        foreach ($orderIds as $orderId) {
            $orderDetails = $this->call('GET', '/admin/orders/' . $orderId . '.json');
            $shop = $this->call('GET', '/admin/shop.json?fields=iana_timezone');
            if (!empty($shop['iana_timezone'])) {
                date_default_timezone_set($shop['iana_timezone']);
            }
            $orderData[] = [
                "id" => $orderDetails['id'],
                "order_number" => $orderDetails['order_number'],
                "order_total_quantity" => !empty($orderDetails['line_items']) ? array_sum(array_column($orderDetails['line_items'], 'quantity')) : "",
                "customer_first_name" => $orderDetails['billing_address']['first_name'],
                "customer_last_name" => $orderDetails['billing_address']['last_name'],
                "created_date" => date('Y-m-d H:i:s', strtotime($orderDetails['created_at'])),
                "status" => self::shopify_order_status($orderDetails),
            ];
        }
        return $orderData;
    }

    public function createStoreReorder($OrderID)
    {
        $newCartItems = array();
        $orderDetails = $this->call('GET', '/admin/orders/' . $OrderID . '.json?fields=line_items');
        foreach ($orderDetails['line_items'] as $lineItem) {
            //calling product API again to check if exists as order api response is not reliable
            $thisProdData = $this->getProductDetails($lineItem['product_id']);
            $productExists = (!empty($thisProdData)) ? true : false;
            $customProduct = $this->checkCustomLineItem($lineItem['properties']);
            //if custom/non custom product exists, good to go
            //if product is not there but custom one then create on the fly
            if ($productExists && !$customProduct['is_custom']) {
                $newCartItems[] = $customProduct['custom_design_id'] . '-' . $lineItem['variant_id'] . '-' . $lineItem['quantity'] . '-' . "0";
            } elseif ($customProduct['is_custom']) { //
                $thisCustomDesignID = $customProduct['custom_design_id'];
                $parentVariantID = $customProduct['orig_variant_id'];
                //create a duplicate prod
                // prepare cart addition array for duplication
                $variant = $this->getVariantDetails($parentVariantID);
                $parentProdID = $this->getNumericData($variant['product']['id']);
                $cartItemArray = array();
                if (is_numeric($parentProdID)) {
                    $cartItemArray[] = array(
                        "product_id" => $parentProdID,
                        "qty" => $lineItem['quantity'],
                        "variant_id" => $parentVariantID,
                        "options" => [],
                        "added_price" => $customProduct['custom_price_per_unit'],
                        "custom_design_id" => $thisCustomDesignID,
                    );
                }
                $cartItemArr = $this->createAddToCartLink($cartItemArray, $thisCustomDesignID);
                $newCartItems[] = $cartItemArr[0];
            } else {
                continue;
            }
        }
        //send for add to cart
        if (!empty($newCartItems)) {
            $getShopDomain = $this->shopDomain();
            $thisShopDomain = !empty($getShopDomain['domain']) ? $getShopDomain['domain'] : SHOPIFY_SHOP . ".myshopify.com";
            $CartURL = 'https://' . $thisShopDomain . '/cart?view=refitem&ref=' . implode('--', $newCartItems);
            $response = array(
                "status" => 1,
                "cart_link" => $CartURL,
            );
        } else {
            $response = array(
                "status" => 0,
                "message" => "Items of the selected Orders are not available",
            );
        }
        return $response;
    }

    private function checkCustomLineItem($properties)
    {
        $customData = array(
            'is_custom' => false,
            'custom_design_id' => 0
        );
        foreach ($properties as $prop) {
            if ($prop['name'] == "_refid") {
                $customData = array(
                    'is_custom' => true,
                    'custom_design_id' => $prop['value']
                );
            }
            if ($prop['name'] == "_parent_var_id") {
                $customDataProd = explode("||", $prop['value']);
                $customData['orig_variant_id'] = $customDataProd[0];
                $customData['custom_price_per_unit'] = $customDataProd[1];
            }
        }
        return $customData;
    }

    public function updateOrderNote($orderID, $orderNum)
    {
        $orderNote = array(
            "order" => array(
                "id" => $orderID,
                "note_attributes" => array(
                    "name" => "Printfiles by Imprintnext",
                    "value" => BASE_URL . "order-download?is_download_store=true&store_id=1&token=" . encryption("+" . $orderID . "@" . $orderNum . "@0+")
                ),
            )
        );
        $this->call('PUT', '/admin/orders/' . $orderID . '.json', $orderNote);
    }

    /*     * ***************************** Order Module End ***************************** */
    /*     * ***************************** Cart Module Start ***************************** */
    /**
     * Previously used for add to cart but now only for quote order creation.
     *
     * @author inkXE
     * @date 20 Dec 2018
     * @param product details
     * @return Cart link
     */
    public function addCustomProduct($callParams)
    {
        $pid = $callParams['product_id'];
        $variantID = $callParams['variant_id'];
        $quantity = $callParams['qty'];
        $productUpdatedPrice = $callParams['product_price'];
        $tierPriceData = array();
        $product = $this->getProductDetails($pid);
        if ($variantID == $pid) {
            $variantID = $this->getNumericData($product['variants']['nodes'][0]['id']);
        }
        $variant = $this->getVariantDetails($variantID);
        // get store location id. Currently set for main store location.

        $variantPrice = $variant['price'];
        $inventoryQty = $variant['inventoryQuantity'];
        // get option array for new product
        $optionArr = array();
        foreach ($variant['selectedOptions'] as $key => $attribute) {
            $position[$key] = $attribute['name'];
            $option = [
                "name" => $attribute['name'],
                "position" => $key,
                "values" => isset($attribute['value']) ?  $attribute['value'] : null,
            ];
            $optionArr[] = $option;
            $key++;
            // // change price in case of tier pricing
            // if (strtolower($attribute['name']) == "quantity") {
            //     $tierPriceData = $this->getTierPrice($product);
            //     $isTier = true;
            // }
        }
        foreach ($optionArr as $eachOpt) {
            $optRes[] = "{name: \"{$eachOpt['name']}\", position: {$eachOpt['position']}, values: {name: \"{$eachOpt['values']}\"}}";
        }
        $optionArr = "[" . implode(", ", $optRes) . "]";

        $tierPriceData = array();
        $commonTierPrice = array();
        $variantTierPrice = array();
        $sameforAllVariants = $isTier = false;
        $shopifyDiscountPath = ASSETS_PATH_W . 'products/discount/';
        $thisProdDiscountFile = $shopifyDiscountPath . $pid . ".json";

        if (file_exists($thisProdDiscountFile)) {
            $tierPriceData = json_clean_decode(file_get_contents($thisProdDiscountFile));
            $isTier = true;
            // little confusion with the key here but was done as sent from admin form field
            if ($tierPriceData['pricing_per_variants'] == 'true') {
                $sameforAllVariants = true;
                foreach ($tierPriceData['price_rules'][0]['discounts'] as $discount) {
                    $commonTierPrice[] = array(
                        "upper_limit" => $discount['upper_limit'],
                        "lower_limit" => $discount['lower_limit'],
                        "discount" => $discount['discount'],
                        "discountType" => $tierPriceData['discount_type']
                    );
                }
            } else {
                foreach ($tierPriceData['price_rules'] as $variantRule) {
                    foreach ($variantRule['discounts'] as $discount) {
                        $variantTierPrice[$variantRule['id']][] = array(
                            "upper_limit" => $discount['upper_limit'],
                            "lower_limit" => $discount['lower_limit'],
                            "discount" => $discount['discount'],
                            "discountType" => $tierPriceData['discount_type']
                        );
                    }
                }
            }
        }

        if ($isTier) {
            $variantPrice = ($sameforAllVariants === true ? $this->getPriceAfterTierDiscount($commonTierPrice, $variant['price'], $quantity) : $this->getPriceAfterTierDiscount($variantTierPrice[$callParams['variant_id']], $variant['price'], $quantity));
        }
        if ($callParams['is_variable_decoration']) {
            $newPrice = $callParams['custom_price'];
        } else {
            $newPrice = !empty($productUpdatedPrice) ? $productUpdatedPrice + $callParams['custom_price'] : $variantPrice + $callParams['custom_price'];
        }
        $refID = $callParams['ref_id'];
        // fetch the png image url from server //
        $imgPngArr = $this->getDesignPreviewImages($variantID, $pid, $refID, "artworks");
        $pngArr = array();
        if (is_countable($imgPngArr)) {
            $kount = 1;
            foreach ($imgPngArr as $pngUrl) {
                $pngArr[] = array("originalSource" => $pngUrl, "mediaContentType" => "IMAGE");
                $kount++;
            }
        }
        $outputArray = [];
        foreach ($pngArr as $item) {
            $outputArray[] = "{originalSource: \"{$item['originalSource']}\", mediaContentType: {$item['mediaContentType']}}";
        }
        $imagesInfo = "[" . implode(",", $outputArray) . "]";

        $prodTitle = (preg_match('/[\'^£$%&*()}{@#~?><>,|=_+¬-]/', $product['title']) ? stripslashes($product['title']) : $product['title']);
        $productQuery = <<<JSON
                    mutation productcreate {
                                productCreate(
                                    input: {title: "{$prodTitle}", vendor: "imprintNext",tags: "customized",status: ACTIVE, productOptions:  $optionArr}
                                    media: $imagesInfo
                                    ) {
                                      product {
                                       id
                                      variants(first: 10) {
                                         nodes {
                                           id
                                      }
                                  }
                              }
                         }
                    }
        JSON;
        $productCreate = $this->graphQlRequest($productQuery);
        $newProduct = !empty($productCreate['data']['productCreate']['product']) ? $productCreate['data']['productCreate']['product'] : null;
        $prodId = end(explode('/', $newProduct['id']));
        $publicationId = $this->getPublicationId();
        //publish the created product to Online Store
        $query = <<<JSON
                    mutation starts {
                        publishablePublish(
                            id: "gid://shopify/Product/$prodId"
                            input: {publicationId: "$publicationId"}
                        ) {
                            userErrors {
                            message
                            }
                        }
                    }
                JSON;
        $this->graphQlRequest($query);

        //update the variant
        $newVariant = $newProduct['variants']['nodes'][0];
        $sku = end(explode('/', $variant['id'])) . "_" . $variant['sku'];
        if ($variant['weight'] != '' && $variant['weight_unit'] != '' && $variant['taxable'] != '') {
            $input = "{id: \"{$newVariant['id']}\", inventoryItem: {sku: \"$sku\", measurement: {weight: {value: {$variant['weight']}, unit: {$variant['weight_unit']}}}}, price: $newPrice , inventoryPolicy: {$variant['inventoryPolicy']}, taxable: {$variant['taxable']}}";
        } else {
            $input = "{id: \"{$newVariant['id']}\", inventoryItem: {sku: \"$sku\"}, price: $newPrice , inventoryPolicy: {$variant['inventoryPolicy']}}";
        }
        $variantUpdate = <<<JSON
                mutation variantUpadte {
                productVariantsBulkUpdate(
                    productId: "gid://shopify/Product/$prodId"
                    variants: $input
                    ) {
                                productVariants {
                            id
                            inventoryItem {
                                id
                                inventoryLevels(first: 100) {
                                    nodes {
                                        location {
                                            id
                                        }
                                    }
                                }
                            }
                        }
                        userErrors {
                                message
                        }
                    }
                }
         JSON;
        $newVariantDets = $this->graphQlRequest($variantUpdate);


        if (!empty($var = $newVariantDets['data']['productVariantsBulkUpdate']['productVariants'])) {
            foreach ($var as $eachVar) {
                //update inventory levels
                $query = <<<JSON
                            mutation updateInventory {
                                inventoryAdjustQuantities(
                                    input: {changes: {delta: $inventoryQty, inventoryItemId: "{$eachVar['inventoryItem']['id']}", locationId: "{$eachVar['inventoryItem']['inventoryLevels']['nodes'][0]['location']['id']}"}, name: "available", reason: "correction"}
                                ) {
                                    inventoryAdjustmentGroup {
                                    id
                                    }
                                    userErrors {
                                    message
                                    }
                                }
                            }
                        JSON;
                $this->graphQlRequest($query);
            }
        }

        $thisVarId = $this->getNumericData($newVariant['id']);
        $thisProdId = $this->getNumericData($newProduct['id']);
        return array('new_product_id' => $thisProdId, 'new_variant_id' => $thisVarId);
    }

    /**
     * new addtocart api for fast response.
     *
     * @author inkXE
     * @date 20 Dec 2018
     * @param product details
     * @return Cart link
     */
    public function createAddToCartLink($cartProduct, $designID)
    {

        $pid = $cartProduct[0]['product_id'];
        $tierPriceData = array();
        $productQuery = <<<JSON
                          query productData {
                                product(id: "gid://shopify/Product/$pid") {
                                    tags
                                    title
                                    variants(first: 1) {
                                    edges {
                                        node {
                                        id
                                        }
                                      }
                                    }
                                    images(first: 10) {
                                    edges {
                                        node {
                                        url
                                        }
                                    }
                                  }
                                }
                            }
                         JSON;
        $productData = $this->graphQlRequest($productQuery, '/product/' . $pid . '.json'); //read from product saved cache
        $product = $productData['data']['product'];

        $cartItemsArr = $metaDataInfo = array();

        //do not create duplicate product for blank product add to cart
        if ($designID > 0) {
            $imgPngArr = $this->getDesignPreviewImages($cartProduct[0]['variant_id'], $cartProduct[0]['product_id'], $designID);
        } else {
            foreach ($cartProduct as $blankItem) {
                $cartItemsArr[] = $designID . '-' . $blankItem['variant_id'] . '-' . $blankItem['qty'] . '-' . "00";
            }
            return $cartItemsArr;
        }

        // Get tier price details
        $tierPriceData = array();
        $commonTierPrice = array();
        $variantTierPrice = array();
        $sameforAllVariants = $isTier = false;
        $shopifyDiscountPath = ASSETS_PATH_W . 'products/discount/';
        $thisProdDiscountFile = $shopifyDiscountPath . $pid . ".json";

        if (file_exists($thisProdDiscountFile)) {
            $tierPriceData = json_clean_decode(file_get_contents($thisProdDiscountFile));
            $isTier = true;


            // little confusion with the key here but was done as sent from admin form field
            if ($tierPriceData['pricing_per_variants'] == 'true') {
                $sameforAllVariants = true;
                foreach ($tierPriceData['price_rules'][0]['discounts'] as $discount) {
                    $commonTierPrice[] = array(
                        "upper_limit" => $discount['upper_limit'],
                        "lower_limit" => $discount['lower_limit'],
                        "discount" => $discount['discount'],
                        "discountType" => $tierPriceData['discount_type']
                    );
                }
            } else {
                foreach ($tierPriceData['price_rules'] as $variantRule) {
                    foreach ($variantRule['discounts'] as $discount) {
                        $variantTierPrice[$variantRule['id']][] = array(
                            "upper_limit" => $discount['upper_limit'],
                            "lower_limit" => $discount['lower_limit'],
                            "discount" => $discount['discount'],
                            "discountType" => $tierPriceData['discount_type']
                        );
                    }
                }
            }
        }
        // get option array for new product
        $optionArr = array();
        $parentAttributes = $cartProduct[0]['options'];
        $isSticker = $cartProduct[0]['is_sticker_product'];
        if (!empty($parentAttributes)) {
            $position = 0;
            foreach ($parentAttributes as $key => $opt) {
                if (!strpos($key, "_id")) {
                    $position++;
                    array_push($optionArr, array("name" => $key, "position" => $position, "value" => $opt));
                }
            }
        }

        $sheetData = array_column($cartProduct, 'sheet_name');
        if ($isSticker == 1 && !empty($sheetData)) {
            $optionArr = [
                "name" => "Sheets",
                "values" => $sheetData,
                "position" => 1

            ];
        }

        // prepare variant array
        foreach ($cartProduct as $key => $cartVariant) {
            $variantOpt = $cartVariant['options'];
            $variantID = $cartVariant['variant_id'];
            $quantity = $cartVariant['qty'];
            if ($cartVariant['total_qty'] > 0) {
                $quantity = $cartVariant['total_qty'];
            }
            if ($variantID == $pid) {
                $variantID = $this->getNumericData($product['variants']['edges'][0]['node']['id']);
            }

            if (SHOPIFY_VARIANTS_PLUGIN != 1) {
                $variantQuery = <<<JSON
                             query prodVar {
                                    productVariant(id: "gid://shopify/ProductVariant/$variantID") {
                                        price
                                        inventoryQuantity
                                        sku
                                        taxable
                                        inventoryPolicy
                                        inventoryItem {
                                        tracked
                                        measurement {
                                            weight {
                                            unit
                                            value
                                            }
                                         }
                                        tracked
                                      }
                                    }
                                 }

                             JSON;
                $variantData = $this->graphQlRequest($variantQuery);
                $variant = $variantData['data']['productVariant'];
            } else {
                $variant = $product['variants']['nodes'][$variantID - 1];
            }

            $variantPrice = $variant['price'];
            if ($isTier) {
                $variantPrice = ($sameforAllVariants === true ? $this->getPriceAfterTierDiscount($commonTierPrice, $variant['price'], $quantity) : $this->getPriceAfterTierDiscount($variantTierPrice[$variantID], $variant['price'], $quantity));
            }
            //adding condition here as per is_variable_decoration and is_sticker_product
            if (($cartVariant['is_variable_decoration'] == 1) && ($cartVariant['is_sticker_product'] == 1)) {
                $newPrice = $cartVariant['added_price'];
            } else {
                $newPrice = (float)($variantPrice + $cartVariant['added_price']);
            }

            // get variant details
            $thisVariant = array(
                "sku" => $variant['sku'],
                "price" => $newPrice,
                "Sheets" => $cartVariant['sheet_name'],
                "taxable" => !empty($variant['taxable']) ? "true" : "false",
                "weight" => isset($variant['inventoryItem']['measurement']['weight']['value']) ? $variant['inventoryItem']['measurement']['weight']['value'] : $variant['weight'],
                "weight_unit" => isset($variant['inventoryItem']['measurement']['weight']['unit']) ? $variant['inventoryItem']['measurement']['weight']['unit'] : "GRAMS",
                "inventory_management" => $variant['inventoryItem']['tracked'],
                "inventory_policy" => $variant['inventoryPolicy'],
            );
            $parentVarInvItemIds[] = $variant['inventoryItem']['id'];
            $parentItemQty[] = $variant['inventoryQuantity'];
            if (!empty($variantOpt)) {

                foreach ($variantOpt as $key => $opt) {
                    if (!strpos($key, "_id")) {

                        $thisV[$key] = addslashes($opt);
                    }
                }
            }
            $thisVariant['optionVal'] = $thisV;
            $variantArr[] = $thisVariant;
        }
        $productArray = array(
            "product" => array(
                "title" => (preg_match('/[\'^£$%&*()}{@#~?><>,|=_+¬-]/', $product['title']) ? stripslashes($product['title']) : $product['title']),
                "vendor" => "imprintNext",
                "tags" => $product['tags'] . ", " . ($isTier ? "customized, imp_" . $pid . ",volumediscount, IMP_REF_ID_" . $designID : "customized, imp_" . $pid . ", IMP_REF_ID_" . $designID),
                "published" => true,
                "published_scope" => "web",
                "template_suffix" => "imprint_dummy_product, imp_noindex",
                "options" => $optionArr,
                "variants" => $variantArr,
                "images" => !empty($imgPngArr[0]) ? array(array("src" => $imgPngArr[0], "position" => 1)) : array(array("src" => $product['images']['edges'][0]['node']['url'], "position" => 1)),
                "image" => !empty($imgPngArr[0]) ? array($imgPngArr[0]) : array($product['images']['edges'][0]['node']['url']),
            ),
        );

        // creating a new product with single variant
        $optionsArray = array();
        if ($isSticker == 1 && !empty($sheetData)) {
            $optionsArray[] = "{name: \"" . $productArray['product']['options']['name'] . "\", position: {$productArray['product']['options']['position']}, values: {name: \"{$productArray['product']['options']['values'][0]}\"}}";
        } else {
            foreach ($productArray['product']['options'] as $productOptions) {
                $optionsArray[] = "{name: \"" . strtolower($productOptions['name']) . "\", position: {$productOptions['position']}, values: {name: \"{$productOptions['value']}\"}}";
            }
        }
        if (!empty($optionsArray)) {
            $optionSet = "[" . implode(",", $optionsArray) . "]";
        }


        foreach ($productArray['product']['images'] as $image) {
            $imageArray[] = "{originalSource: \"{$image['src']}\", mediaContentType: IMAGE}";
        }

        $imageSet = !empty($imageArray) ? "[" . implode(",", $imageArray) . "]" : json_encode([]);
        if (!empty($optionsArray)) {
            $productInput = "{title: \"{$productArray['product']['title']}\" , vendor: \"{$productArray['product']['vendor']}\", tags: \"{$productArray['product']['tags']}\",
                              templateSuffix:\"imprint_dummy_product, imp_noindex\", productOptions: $optionSet}";
        } else {
            $productInput =   "{title: \"{$productArray['product']['title']}\" , vendor: \"{$productArray['product']['vendor']}\", tags: \"{$productArray['product']['tags']}\",
            templateSuffix:\"imprint_dummy_product, imp_noindex\"}";
        }

        $createProductQuery = <<<JSON
            mutation createProduct {
                   productCreate(
                       input: $productInput
                       media: $imageSet
                           )   {
                            product {
                                id
                            }
                            userErrors {
                                field
                                message
                            }
                      }
                  }
            JSON;

        $newProductQuery = $this->graphQlRequest($createProductQuery);

        $addProduct = $newProductQuery['data']['productCreate']['product'];
        $newProductId = $addProduct['id'];


        //creating multiple variants in bulk
        foreach ($productArray['product']['variants'] as $eachVariantData) {
            $barcode = !empty($eachVariantData['barcode']) ? $eachVariantData['barcode'] : "";
            $graphString = array();
            if ($isSticker == 1 && isset($eachVariantData['Sheets']) && !empty($eachVariantData['Sheets'])) {
                $graphString[] = "{name: \"{$eachVariantData['Sheets']}\", optionName: \"Sheets\"}";
            } else {
                foreach ($eachVariantData['optionVal'] as $attrKey => $attributeNames) {
                    $graphString[] = "{name: \"{$attributeNames}\", optionName: \"{$attrKey}\"}";
                }
            }
            $variantSet = "[" . implode(",", $graphString) . "]";
            $varinatsArray[] = "{barcode: \"{$barcode}\", price:  \"{$eachVariantData['price']}\", taxable: {$eachVariantData['taxable']}, inventoryPolicy: DENY, optionValues: $variantSet,
                                    inventoryItem: {sku: \"{$eachVariantData['sku']}\", tracked: false, measurement: {weight: {value: {$eachVariantData['weight']}, unit: {$eachVariantData['weight_unit']}}}}}";
            $finalDataSet = "[" . implode(",", $varinatsArray) . "]";
        }

        $variantBulkQuery = <<<JSON
            mutation variantsBulk {
                productVariantsBulkCreate(
                  productId: "$newProductId"
                  strategy: REMOVE_STANDALONE_VARIANT
                  variants: $finalDataSet
                ) {
                    product {
                        id
                    }
                    productVariants {
                        price
                    }
                    userErrors {
                        field
                        message
                    }
                }
              }

            JSON;

        $this->graphQlRequest($variantBulkQuery);

        //publish the created product to Online Store
        $query = <<<JSON
                  mutation starts {
                            publishablePublish(
                                id: "gid://shopify/Product/{$this->getNumericData($newProductId)}"
                                input: {publicationId: "{$this->getPublicationId()}"}
                            ) {
                                userErrors {
                                message
                                }
                            }
                        }
                JSON;
        $this->graphQlRequest($query);

        // getting product variants location details
        $getProductInvQuery = <<<JSON
       query getProduct {
            product(id: "$newProductId") {
                variants(first: 100) {
                    nodes {
                        id
                        inventoryQuantity
                        inventoryItem {
                            id
                            sku
                            inventoryLevels(first: 100) {
                                nodes {
                                location {
                                    id
                                }
                              }
                            }
                        }
                    }
                }
            }
        }
      JSON;
        $getProductVariantsData = $this->graphQlRequest($getProductInvQuery);
        $getProductVariantsData = $getProductVariantsData['data']['product']['variants'];
        if (!empty($getProductVariantsData['nodes'])) {
            foreach ($getProductVariantsData['nodes'] as $createdVariantData) {
                $query = <<<JSON
            mutation updateInventory {
                inventoryAdjustQuantities(
                    input: {changes: {delta: {$createdVariantData['inventoryQuantity']}, inventoryItemId: "{$createdVariantData['inventoryItem']['id']}", locationId: "{$createdVariantData['inventoryItem']['inventoryLevels']['nodes'][0]['location']['id']}"}, name: "available", reason: "correction"}
                ) {
                    inventoryAdjustmentGroup {
                    id
                    }
                    userErrors {
                    message
                    }
                }
            }
           JSON;
                $this->graphQlRequest($query);
            }
        }

        $cartItemsArr = $metaDataInfo = array();
        foreach ($getProductVariantsData['nodes'] as $key => $newVariant) {
            $newVariantId = $this->getNumericData($newVariant['id']);
            $cartItemsArr[] = $designID . '-' . $newVariantId . '-' . $cartProduct[$key]['qty'] . '-' . $cartProduct[$key]['variant_id'] . '||' . sprintf("%.2f", $cartProduct[$key]['added_price']) . '||' . $cartProduct[$key]['custom_element'];
            $relationOfIDs[$newVariantId] = $cartProduct[$key]['variant_id'];
        }
        $relationOfIDs['product_type'] = ($pid == $relationOfIDs[$newVariantId]) ? "simple" : "variable";


        if (!empty($relationOfIDs)) {
            $value = addslashes(json_encode($relationOfIDs));
            $metaQuery = <<<JSON
                                mutation prodMeta {
                                        productUpdate(
                                            input: {id: "{$newProductId}", metafields: [{key: "imprint_prod_rel", namespace: "imprintnext", value: "{$value}", type: "json"},
                                            {key: "hidden", namespace: "seo", value: "1", type: "number_integer"}]}
                                        ) {
                                            userErrors {
                                            field
                                            message
                                            }
                                         }
                                    }
                             JSON;
            $this->graphQlRequest($metaQuery);
        }

        return $cartItemsArr;
    }

    private function getPriceAfterTierDiscount($tierPriceRule, $price, $quantity)
    {
        $newPrice = $price;
        if (!empty($tierPriceRule)) {
            $upperLimits = max(array_column($tierPriceRule, 'upper_limit'));
            if ($quantity > $upperLimits) {
                $quantity = $upperLimits;
            }
            foreach ($tierPriceRule as $tier) {
                if ($quantity >= $tier['lower_limit'] && $quantity <= $tier['upper_limit']) {
                    $newPrice = ($tier['discountType'] == "flat" ? ($price - $tier['discount']) : ($price - (($tier['discount'] / 100) * $price)));
                    break;
                }
            }
        }
        return $newPrice;
    }

    /**
     * GET custom preview images of cart items
     *
     * @author inkXE
     * @date 20 Dec 2018
     * @param $refids design reference ID
     * @return Cart link
     */
    public function getDesignPreviewImages($variantID, $pid, $refids = 0, $source = "carts")
    {
        try {
            if ($refids) {
                $regidArr = explode(',', $refids);
                $jsonData = '';
                $desStateDIR = path('abs', 'design_state') . $source;
                $baseImagePath = $desStateDIR . SEPARATOR;
                foreach ($regidArr as $values) {
                    $stateDesignFile = $baseImagePath . $values . '.json';
                    $jsonData = json_decode(file_get_contents($stateDesignFile), true);
                    if ($jsonData != '') {
                        foreach ($jsonData['design_product_data'] as $capture) {
                            if ($capture['variant_id'][0] == $variantID || $pid == $variantID) {
                                $images = $capture['design_urls'];
                                break;
                            } else {
                                $images = $capture['design_urls'];
                            }
                        }
                    } else {
                        $msg = array("status" => "nodata");
                        return json_encode($msg);
                    }
                }
                return $images;
            }
        } catch (\Exception $e) {
            $result = array('Caught exception:' => $e->getMessage());
            return json_encode($result);
        }
    }
    public function shopDomain()
    {
        return $this->call('GET', '/admin/shop.json?fields=domain');
    }


    /**
     * Shopify GraphQl API curl function
     *
     * @param $method  GraphQl API call method (POST)
     * @param $payload  Shopify API parameters if any
     *
     * @author dan@imprintnext.com
     * @date   28-10-2022
     * @return Curlresponse
     */
    private function graphQlRequest($query, $path = ' ', $fetchRaw = false)
    {
        $response = array();
        //check if product and variant details be fetched from cache
        if ((strpos($path, 'product') !== false || strpos($path, 'variant') !== false) && !$fetchRaw) {
            $response = $this->getAPIDataFromCache($path);
        }
        if (empty($response)) {
            $method = 'POST';
            $apiUrl = "https://{$this->shopDomain}/" . "admin/api/" . $this->apiVersion . "/graphql.json";
            $cleanQRY = trim(preg_replace('/\s\s+/', ' ', str_replace("\n", " ", $query)));
            $payload = json_encode(["query" => $cleanQRY]);
            $requestHeaders = [
                'Content-Type: application/json',
                'X-Shopify-Access-Token: ' . $this->token
            ];
            $curl = curl_init();

            curl_setopt_array($curl, array(
                CURLOPT_URL => $apiUrl,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_ENCODING => '',
                CURLOPT_MAXREDIRS => 10,
                CURLOPT_TIMEOUT => 0,
                CURLOPT_FOLLOWLOCATION => true,
                CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
                CURLOPT_CUSTOMREQUEST => $method,
                CURLOPT_POSTFIELDS => $payload,
                CURLOPT_HTTPHEADER => $requestHeaders,
            ));
            $response = curl_exec($curl);
            $errno = curl_errno($curl);
            $error = curl_error($curl);
            curl_close($curl);
            if ($errno) {
                create_log('clipart', 'error', [
                    'message' => 'Shopify GraphQl Request Error!',
                    'extra' => ['errno' => $errno, 'error' => $error]
                ]);
                return $error;
            }
        }
        $respData = preg_split("/\r\n\r\n|\n\n|\r\r/", $response, 2);
        if (count($respData) >= 2) {
            return json_clean_decode($respData[1], true);
        } else {
            return json_clean_decode($response, true);
        }
    }

    /**
     * Copy old product delivery profile to new product.
     *
     * @param $newProductId
     *
     * @author dan@imprintnext.com
     * @date   28-10-2022
     * @return Integer : Delivery update count
     */
    public function copyDeliveryProfile($varIDs)
    {
        // get the delivery profile of the product variants
        $payload = '{"query":"{productVariant(id: \"gid:\/\/shopify\/ProductVariant\/' .
            $varIDs['oldVarID'] . '\") {deliveryProfile {id}}}"}';

        $result =  $this->graphQlRequest($payload);

        // update the delivery profile for the new product crated
        if (
            isset($result['data'], $result['data']['productVariant']) &&
            !empty($result['data']['productVariant']['deliveryProfile'])
        ) {
            $deliveryProfileId = $result['data']['productVariant']['deliveryProfile']['id'];

            // update delivery profile using the graphQl
            $payload = '{"query":"mutation deliveryProfileUpdate {deliveryProfileUpdate(id:\"' .
                $deliveryProfileId . '\", profile: {variantsToAssociate:[\"gid:\/\/shopify\/ProductVariant\/' .
                $varIDs['newVarID'] . '\"]}) {profile {id} userErrors {field message}}}"}';

            $result =  $this->graphQlRequest($payload);
        }

        return $result;
    }

    public function addVariantToShopProd($prodData)
    {
        $productData = $this->getShopifyProductInfo($prodData['productID']);
        $variantOptionExists = true;
        $requestedVarID = "";
        $productArray = array(
            "product" => array(
                "status" => "active",
                "tags" => $productData['tags'] . ", imprint_options",
            ),
        );
        if (count($productData['options']) > 1 || $productData['options'][0]['name'] != "variant") {
            $variantOptionExists = false;
            $productArray['product']['options'] = array(
                'name' => "variant",
                'values' => !empty($productData['options'][0]['values']) ? array_push($optValues, $prodData['variantName']) : array($prodData['variantName']),
                'position' => 1
            );
            // foreach ($productData['variants'] as $variant) {
            //     $this->call('DELETE', '/admin/products/'. $prodData['productID'] .'/variants/'.$variant['id'].'.json');
            // }
        }
        $oldTags = explode(', ', $productData['tags']);
        if (!$variantOptionExists || !in_array("imprint_options", $oldTags) || empty($productData['published_at'])) {

            $updateProd = $this->call('PUT', '/admin/products/' . $prodData['productID'] . '.json', $productArray);
        }
        foreach ($productData['variants'] as $variant) {
            if ($variant['option1'] == $prodData['variantName']) {
                $requestedVarID = $variant['id'];
                break;
            }
        }

        if (empty($requestedVarID)) {
            $variantArray = array(
                "variant" => array(
                    "product_id" => $prodData['productID'],
                    "option1" => $prodData['variantName'],
                    "price" => $prodData['variantPrice']
                ),
            );
            $variant = $this->call('POST', '/admin/products/' . $prodData['productID'] . '/variants.json', $variantArray);
            $requestedVarID = $variant['id'];
        }
        // update inventory for this variant
        if ($variant['inventory_quantity'] != $prodData['inventory'] && $variant['inventory_management'] == 'shopify') {
            $inventoryItemID = $variant['inventory_item_id'];
            $invLevels = $this->call('GET', '/admin/inventory_levels.json?inventory_item_ids=' . $inventoryItemID);
            foreach ($invLevels as $level) {
                $locationData = $this->call('GET', '/admin/locations/' . $level['location_id'] . '.json');
                if (!$locationData['legacy']) {
                    $newInventory = array("location_id" => $level['location_id'], "inventory_item_id" => $inventoryItemID, "available" => $prodData['inventory']);
                    $this->call('POST', '/admin/inventory_levels/set.json', $newInventory);
                }
            }
        }
        return $requestedVarID;
    }

    public function tierPriceOfDuplicateProduct($price, $itemDetails)
    {
        $jsonResponse = [
            'status' => 0,
            'message' => "Product tierPrice couldn't updated in store.",
        ];
        $success = 0;

        foreach ($itemDetails as $key => $item) {
            // $variantDetails = $this->call('GET', '/admin/variants/' . $item['variant_id'] . '.json');

            $updateVariantPrice = [
                "variant" => [
                    "id" => $item['variant_id'],
                    "price" => $price[$key]
                ]
            ];
            $this->call('PUT', '/admin/variants/' . $item['variant_id'] . '.json', $updateVariantPrice);
            $success++;
        }
        if ($success > 0) {
            $jsonResponse = [
                'status' => 1,
                'message' => "Product tierPrice updated in store.",
            ];
        }
        return $jsonResponse;
    }

    /**
     * Save metafields to shopify shop.
     *
     * @param cart settings data from admin
     *
     * @author divya@imprintnext.com
     * @date   11th September 2024
     * @return JSON response
     */
    public function saveMetafieldsToShop($cartShopData)
    {
        $removeCartData = ($cartShopData['remove_cart_button']['is_enabled']) ? $cartShopData['remove_cart_button']['is_enabled'] : 0;
        $directCartValue = ($cartShopData['direct_add_to_cart']['is_enabled']) ? $cartShopData['direct_add_to_cart']['is_enabled'] : 0;
        $query = <<<JSON
                    query {
                       shop {
                         id
                       }
                  }
        JSON;
        $getShopId = $this->graphQlRequest($query);
        $shopId = $getShopId['data']['shop']['id']; //Getting shopify current store id
        $saveMetaDataQuery = <<<JSON
                        mutation setMetafieldsToShop{
                        metafieldsSet(
                            metafields: [{ownerId: "$shopId", key: "remove_cart_button", namespace: "shopify_cart_settings", type: "boolean", value: "{$removeCartData}"},
                                         {ownerId: "$shopId", key: "direct_add_to_cart", namespace: "shopify_cart_settings", type: "boolean", value: "{$directCartValue}"}]
                            ) {
                               userErrors {
                                  field
                                  message
                            }
                        }
                    }
        JSON;

        return $this->graphQlRequest($saveMetaDataQuery); //Setting metafields value to shop
    }

    /*     * ***************************** Cart Module End ***************************** */
    public function shopifyVariantManage($productArray, $product, $imgArr)
    {

        $price = $productArray['product']['variants'][0]['price'];
        $productArray['product']['options'] = [];
        $productArray['product']['variants'] = [];
        $showIndesignerId = $this->getShowInDesignerId();
        $collectionID = "gid://shopify/Collection/" . $showIndesignerId;
        $prodTitle = (preg_match('/[\'^£$%&*()}{@#~?><>,|=_+¬-]/', $productArray['product']['title']) ? stripslashes($productArray['product']['title']) : $productArray['product']['title']);
        $prodDescription = (preg_match('/[\'^£$%&*()}{@#~?><>,|=_+¬-]/', $productArray['product']['body_html']) ? stripslashes($productArray['product']['body_html']) : $productArray['product']['body_html']);
        $productQuery = <<<JSON
                        mutation createProduct {
                            productCreate(
                                input: {title: "{$prodTitle}", descriptionHtml: "{$prodDescription}", collectionsToJoin: "{$collectionID}", tags:"{$productArray['product']['tags']}"}
                                media: {originalSource: "{$productArray['product']['image']['src']}", mediaContentType: IMAGE}
                            ) {
                                product {
                                id
                                variants(first: 5) {
                                    nodes {
                                    id
                                    }
                                  }
                                }
                                userErrors {
                                field
                                message
                                }
                              }
                            }
                      JSON;
        $newProductInfo = $this->graphQlRequest($productQuery);
        $newProductData = $newProductInfo['data']['productCreate']['product'];
        $newProductId = $newProductData['id'];
        $newVariantId = $newProductData['variants']['nodes'][0]['id'];
        $variantUpdateQuery = <<<JSON
                                mutation variantUpdate {
                                    productVariantsBulkUpdate(productId: "{$newProductId}", variants: {id: "{$newVariantId}", price: "{$price}"}) {
                                        userErrors {
                                        field
                                        message
                                        }
                                    }
                                 }
                            JSON;
        $this->graphQlRequest($variantUpdateQuery);

        $getNewVarintInventoryQuery = <<<JSON
                                    query getProduct {
                                        product(id: "{$newProductId}") {
                                            variants(first: 100) {
                                            nodes {
                                                id
                                                inventoryItem {
                                                id
                                                sku
                                                inventoryLevels(first: 100) {
                                                    nodes {
                                                    location {
                                                        id
                                                      }
                                                    }
                                                  }
                                                }
                                              }
                                            }
                                          }
                                       }
                               JSON;
        $inventoryDetails = $this->graphQlRequest($getNewVarintInventoryQuery);
        $inventoryData =  $inventoryDetails['data']['product']['variants'];

        foreach ($inventoryData['nodes'] as $variant) {
            $query = <<<JSON
                  mutation updateInventory {
                    inventoryAdjustQuantities(
                    input: {changes: {delta: 100, inventoryItemId: "{$variant['inventoryItem']['id']}", locationId: "{$variant['inventoryItem']['inventoryLevels']['nodes'][0]['location']['id']}"}, name: "available", reason: "correction"}
                   ) {
                        inventoryAdjustmentGroup {
                        id
                        }
                        userErrors {
                        message
                        }
                    }
                 }
            JSON;
            $this->graphQlRequest($query);
        }
        $this->saveVariantToDB($product, $this->getNumericData($newProductId));
        $newProductIds[] = $this->getNumericData($newProductId);
        return $newProductIds;
    }

    private function saveVariantToDB($productInfo, $productId)
    {
        $allAttributes = $productInfo['attributes'];

        $getAttr = array_column($allAttributes, 'name');
        foreach ($allAttributes as $key => $singleAtt) {
            $productOptionObj = new ProductOptions();
            $getOptionObj = $productOptionObj->where(['name' => $singleAtt['name']]);
            if ($getOptionObj->count()) {
                $productOptionObj = $getOptionObj->get()->first();
            } else {
                $productOptionObj->fill($singleAtt);
                // skip if unable to save
                if (!$productOptionObj->save()) {
                    continue;
                }
            }
            if (!empty($singleAtt['options'])) {

                $optionRelData = [
                    'product_id' => strval($productId),
                    'option_values' => $singleAtt['options'],
                    'position' => $key
                ];

                $optionRelObj = new ProductOptionRel();
                $checkOptionRel = $optionRelObj->where(['option_id' => $productOptionObj->xe_id, 'product_id' => $productId]);
                if ($checkOptionRel->count()) {
                    $optionRelObj = $checkOptionRel->get()->first();
                } else {
                    $optionRelData['option_id'] = $productOptionObj->xe_id;
                }
                $optionRelObj->fill($optionRelData);
                $optionRelObj->save();
            }
        }
        $getAllVariants = $productInfo['variations'];
        $uniqueVar = [];
        foreach ($getAllVariants as $singleVar) {
            $option1 = strtolower($getAttr[0]);
            $option2 = strtolower($getAttr[1]);
            $imagename = $singleVar['attributes'][$option1];
            $addedImage = [
                'name' => $imagename,
                'is_disable' => 0,
                'store_id' => 1,
                'cloud_storage' => 0,
                'is_catalog' => 1
            ];
            $getImageObj = new ProductImage($addedImage);
            $getImageObj->save();
            foreach ($singleVar['image_path'] as $imgKey => $imgValue) {
                $addedSideImage = [
                    'product_image_id' => $getImageObj->xe_id,
                    'side_name' => $singleVar['side_name'][$imgKey],
                    'sort_order' => $imgKey,
                    'file_name' => $imgValue
                ];
                $newSideImage = new ProductImageSides($addedSideImage);
                $newSideImage->save();
            }
            $title = str_replace('/', '', $singleVar['attributes'][$option1]) . '/' . $singleVar['attributes'][$option2];
            $key = $singleVar['attributes'][$option1] . '/' . $singleVar['attributes'][$option2];
            if (!in_array($key, $uniqueVar)) {
                $uniqueVar[] = $key;
                $addedVariants = [
                    'title' => $title,
                    'price' => $singleVar['piece_price'],
                    'sku' => $singleVar['sku'],
                    'image_id' => $getImageObj->xe_id,
                    'inventory' => $singleVar['quantity'],
                    'barcode' => $singleVar['gtin'],
                    'weight' => $singleVar['unit_weight'],
                ];
                $newProductVar = new ProductVariants($addedVariants);
                $newProductVar->save();
                $varRel = [
                    'product_id' => strval($productId),
                    'variant_id' => $newProductVar->xe_id
                ];
                $newProductVarRel = new ProductVariantRel($varRel);
                $newProductVarRel->save();
            }
        }
    }

    /** private functions to get product and variant details
     *@author pansy@imprintnext.com
     */

    private function getProductDetails($productId)
    {
        $productQuery = <<<JSON
        query productdetails {
            product(id: "gid://shopify/Product/$productId") {
              id
              title
              tags
              images(first: 250) {
                    nodes {
                         id
                         url
                     }
               }
              variants(first: 250) {
                  nodes {
                    id
                    title
                    price
                    sku
                  }
              }
              options(first: 10) {
                    id
                    position
                    name
                    values
                    optionValues {
                        id
                        name
                       }

                }
             }
          }
        JSON;

        $productData = $this->graphQlRequest($productQuery, '/product/' . $productId . '.json'); //read from product saved cache
        $product = $productData['data']['product'];
        if (!empty($product)) {
            return $product;
        }
    }

    public function getVariantDetails($varId)
    {
        $productVar = [];
        $varianttQuery = <<<JSON
                    query varianttQuery {
                        productVariant(id: "gid://shopify/ProductVariant/$varId") {
                            sku
                            taxable
                            inventoryQuantity
                            inventoryPolicy
                            price
                            inventoryItem {
                                tracked
                                id
                                measurement {
                                    weight {
                                    unit
                                    value
                                    }
                                }

                                inventoryLevels(first: 250){
                                    nodes {
                                        location {
                                            id
                                        }
                                    }
                                }
                            }
                            selectedOptions {
                                name
                                value
                                optionValue {
                                    id
                                    name
                                }
                            }
                            image {
                                id
                                url
                            }
                            product {
                                id
                            }
                        }
                    }
            JSON;
        $variantData = $this->graphQlRequest($varianttQuery, '/variant/' . $varId . '.json'); //read from product saved cache
        $productVar = isset($variantData['data']['productVariant']) ? $variantData['data']['productVariant'] : $variantData;
        if (!empty($productVar) && $productVar['price'] != null) {
            return $productVar;
        } else {
            return  $productVar;
        }
    }
    /**
     * creating a custom product to be added to cart when custom price is available with 'direct add-to-cart' enabled
     *
     * @param $method  GraphQl API call method (POST)
     * @param $payload  Shopify API parameters if any
     *
     * @author pansy@imprintnext.com
     * @date   10-09-2024
     * @return Curlresponse
     */

    public function createCustomProduct($shopifyCartSettings)
    {
        $getCustomProductId = $this->getCustomProduct();
        if (!empty($shopifyCartSettings) && !empty($shopifyCartSettings['direct_add_to_cart']) && $shopifyCartSettings['direct_add_to_cart']['is_enabled'] == true && $getCustomProductId == '') {
            $productCreate = <<<JSON
                             mutation createCustomProduct {
                                 productCreate(
                                     input: {title: "Custom Price", status: ACTIVE, vendor: "imprintNext", tags: "customized", templateSuffix: "imprint_dummy_product", handle: "custom-price",descriptionHtml: "<p>*** This is a hidden product used by ImprintNext. Please do not modify or delete! ***</p> <p>To add Custom Price to the cart, this product must be <strong>Visible </strong>in the Store Admin and set to <strong>Don't Track Inventory</strong>. <span style=\"color: #ff0000;\">Modifying these settings may prevent shoppers from checking out.</span></p>"}
                                 ) {
                                     product {
                                     id
                                     }
                                 }
                             }
                     JSON;
            $product = $this->graphQlRequest($productCreate);

            if (!empty($product['data']['productCreate']['product']['id'])) {
                $prodId = $product['data']['productCreate']['product']['id'];
                //get publication Id of channel Online Store
                $publicationId = $this->getPublicationId();
                //publish the created product to Online Store
                $query = <<<JSON
                                 mutation starts {
                                     publishablePublish(
                                         id: "$prodId"
                                         input: {publicationId: "$publicationId"}
                                     ) {
                                         userErrors {
                                         message
                                         }
                                     }
                                 }
                             JSON;
                $this->graphQlRequest($query);
                //inventory and price update
                $productUpdate = <<<JSON
                                mutation variantcreate {
                                     productVariantsBulkCreate(
                                         productId: "$prodId"
                                         variants: {price: "0.01", inventoryPolicy: CONTINUE, inventoryItem: {tracked: true, requiresShipping: false}, optionValues: {name: "Default Title", optionName: "Title"}}
                                         strategy: REMOVE_STANDALONE_VARIANT
                                     ) {
                                         productVariants {
                                             id
                                         }
                                         userErrors {
                                         message
                                         field
                                         }
                                     }
                                 }
                         JSON;
                $variantUpdate = $this->graphQlRequest($productUpdate);

                if (!empty($variantUpdate['data']['productVariantsBulkCreate']['productVariants'])) {
                    $variantId = $this->getNumericData($variantUpdate['data']['productVariantsBulkCreate']['productVariants'][0]['id']);
                }

                //update shopify_cart_settings metafield with custom_variant_id and add a metafield to hide the product in search engine

                $shopQuery = <<<JSON
                     query {
                        shop {
                          id
                        }
                   }
                 JSON;
                $getShopId = $this->graphQlRequest($shopQuery);
                $shopId = $getShopId['data']['shop']['id']; //Getting shopify current store id
                $saveMetaDataQuery = <<<JSON
                         mutation setMetafieldsToShop{
                             metafieldsSet(
                                 metafields: [{ownerId: "$shopId", key: "custom_variant_id", namespace: "shopify_cart_settings", type: "number_integer", value: "{$variantId}"},
                                 {ownerId: "$prodId",key: "hidden", namespace: "seo", value: "1", type: "number_integer"}]
                                 ) {
                                 userErrors {
                                     field
                                     message
                                 }
                             }
                         }
                     JSON;
                $this->graphQlRequest($saveMetaDataQuery); //Setting metafields value to shop

            }
        }
    }

    //to get the custom Product Id
    private function getCustomProduct()
    {
        $customProdId = '';
        $getCustomProduct = <<<JSON
                query MyQuery {
                    productByHandle(handle: "custom-price") {
                        variants(first: 10) {
                            nodes {
                                id
                            }
                        }
                    }
                }
            JSON;
        $customProduct = $this->graphQlRequest($getCustomProduct);
        if (!empty($customProduct['data']['productByHandle'])) {
            $customProdId = $customProduct['data']['productByHandle']['variants']['nodes'][0]['id'];
        }
        return $customProdId;
    }

    //to get the default variant ID if both product and variant Id is same
    public function updateVariantId($cartData)
    {
        $variantId = 0;
        if ($cartData['variant_id'] == $cartData['product_id']) {
            $productDetsQuery = <<<JSON
            query productdetails {
                product(id: "gid://shopify/Product/{$cartData['product_id']}") {
                  variants(first: 1) {
                      nodes {
                        id
                     }
                    }
                }
            }
            JSON;
            $productData = $this->graphQlRequest($productDetsQuery);
            if (!empty($productData['data']['product']['variants'])) {
                $variantId = $this->getNumericData($productData['data']['product']['variants']['nodes'][0]['id']);
            }
        }
        return $variantId;
    }

    public function getShopProductImages($productId)
    {
        $image = [];
        $productQuery = <<<JSON
        query productdetails {
            product(id: "gid://shopify/Product/$productId") {
              id
              images(first: 10) {
                    nodes {
                         id
                         url
                     }
               }
             }
          }
        JSON;

        $productData = $this->graphQlRequest($productQuery);
        $product = $productData['data']['product'];
        if (!empty($product)) {
            $image[] = [
                'src' => $product['images']['nodes'][0]['url'],
                'thumbnail' => $product['images']['nodes'][0]['url']
            ];
            return $image;
        }
    }
}
