<?php

/**
 * @category  Webkul
 * @package   Webkul_GoogleShoppingFeed
 * @author    Webkul Software Private Limited
 * @copyright Copyright (c) Webkul Software Private Limited (https://webkul.com)
 * @license   https://store.webkul.com/license.html
 */

namespace Webkul\GoogleShoppingFeed\Helper;

use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
use Magento\Directory\Model\CurrencyFactory;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Stdlib\DateTime\DateTime;
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
use Magento\InventoryCatalogAdminUi\Model\GetSourceItemsDataBySku;
use Magento\Store\Model\StoreManagerInterface;
use Webkul\GoogleShoppingFeed\Helper\Data as HelperData;
use Webkul\GoogleShoppingFeed\Logger\Logger;

class GoogleFeed extends \Magento\Framework\App\Helper\AbstractHelper
{
    /**
     * @var Magento\Store\Model\StoreManagerInterface
     */
    private $storeManager;

    /**
     * @var Webkul\GoogleShoppingFeed\Helper\Data
     */
    public $helperData;

    /**
     * @var Webkul\GoogleShoppingFeed\Logger\Logger
     */
    private $logger;

    /**
     * Init
     *
     * @param \Magento\Framework\App\Helper\Context $context
     * @param TimezoneInterface                     $dateTimeZone
     * @param DateTime                              $dateTime
     * @param StoreManagerInterface                 $storeManager
     * @param CurrencyFactory                       $currencyFactory
     * @param \Magento\Framework\Escaper            $escaper
     * @param Configurable                          $configProTypeModel
     * @param GetSourceItemsDataBySku               $sourceDataBySku
     * @param ProductRepositoryInterface            $productRepository
     * @param HelperData                            $helperData
     * @param Logger                                $logger
     */
    public function __construct(
        \Magento\Framework\App\Helper\Context $context,
        TimezoneInterface $dateTimeZone,
        DateTime $dateTime,
        StoreManagerInterface $storeManager,
        CurrencyFactory $currencyFactory,
        \Magento\Framework\Escaper $escaper,
        Configurable $configProTypeModel,
        GetSourceItemsDataBySku $sourceDataBySku,
        ProductRepositoryInterface $productRepository,
        HelperData $helperData,
        Logger $logger
    ) {
        parent::__construct($context);
        $this->dateTimeZone = $dateTimeZone;
        $this->escaper = $escaper;
        $this->dateTime = $dateTime;
        $this->storeManager = $storeManager;
        $this->currencyFactory = $currencyFactory;
        $this->configProTypeModel = $configProTypeModel;
        $this->sourceDataBySku = $sourceDataBySku;
        $this->productRepository = $productRepository;
        $this->helperData = $helperData;
        $this->logger = $logger;
        $this->helperData->getAccessToken();
    }

    /**
     * Insert FeedToGoogleShop
     *
     * @param  Google_Service_ShoppingContent_Product $productFeed
     * @return Google_Service_ShoppingContent_Product
     */
    public function insertFeedToGoogleShop($productFeed)
    {
        try {
            $accessToken = $this->helperData->getAccessToken();
            if ($accessToken) {
                $config = $this->helperData->getConfigDetails();
                $client = new \Google_Client();
                $client->setAccessToken($config['oauth2_access_token']);
                $serviceShoppingContent = new \Google_Service_ShoppingContent($client);
                $product = $serviceShoppingContent->products->insert($config['merchant_id'], $productFeed);
                return ['error' => 0, 'product' => $product];
            } else {
                return ['error' => 1, 'product' => null, 'message' => __('Google feed account not authenticated.')];
            }
        } catch (\Exception $e) {
            $this->logger->error('postShopData : ' . $e->getMessage());
            return ['error' => 1, 'product' => null, 'message' => $e->getMessage()];
        }
    }

    /**
     * Get StoreDetailForFeed
     *
     * @param  int $store
     * @return array
     */
    public function getStoreDetailForFeed($store = false)
    {
        try {
            $store = $store === false ? $this->storeManager->getStore() : $store;
            $locale = $this->scopeConfig->getValue(
                'general/locale/code',
                \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
                $store->getStoreId()
            );
            $locale = explode('_', $locale);
            $storeDetails = [
                'base_media_url' => $store->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA),
                'base_currency' => $store->getBaseCurrencyCode(),
                'language' => $locale[0],
                'country' => $locale[1],
                'store_id' => $store->getId(),
                'currency_code' => $this->scopeConfig->getValue(
                    'currency/options/default',
                    \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
                    $store->getStoreId()
                ),
            ];
            return $storeDetails;
        } catch (\Exception $e) {
            throw new LocalizedException(__($e->getMessage()));
        }
    }
    /**
     * Get PriceForConfigProduct
     *
     * @param  Magento\Catalog\Model\product $product
     * @param  array                         $storeDetail
     * @return float
     */
    private function getPriceForFeed($product, $storeDetail)
    {
        try {
            $price = $product->getPrice();
            if (in_array($product->getTypeId(), ['configurable', 'bundle', 'grouped'])) {
                $price = $product->getPriceInfo()->getPrice('final_price')->getMinimalPrice()->getValue();
            }
            $rate = $this->currencyFactory->create()->load($storeDetail['base_currency'])
                ->getAnyRate($storeDetail['currency_code']);
            return $price * $rate;
        } catch (\Exception $e) {
            throw new LocalizedException(__($e->getMessage()));
        }
    }

    /**
     * Get SalePriceForFeed
     *
     * @param  Magento\Catalog\Model\product $product
     * @param  array                         $storeDetail
     * @return float
     */
    private function getSalePriceForFeed($product, $storeDetail)
    {
        try {
            $price = $product->getPriceInfo()->getPrice('special_price')->getValue();
            if (in_array($product->getTypeId(), ['configurable', 'bundle', 'grouped'])) {
                $price = $product->getFinalPrice();
            }
            $rate = $this->currencyFactory->create()->load($storeDetail['base_currency'])
                ->getAnyRate($storeDetail['currency_code']);
            return $price * $rate;
        } catch (\Exception $e) {
            throw new LocalizedException(__($e->getMessage()));
        }
    }

    /**
     * Get ProductForFeed
     *
     * @param  Magento\Catalog\Model\product $product
     * @param  array                         $storeDetail
     * @param  Magento\Catalog\Model\product $groupItem
     * @param  array                         $configProOptions
     * @return \Google_Service_ShoppingContent_Product
     */
    public function getProductForFeed($product, $storeDetail, $groupItem = false, $configProOptions = [])
    {
        try {
            $this->logger->info('getproductfeedcalled in helper line 197');
            $googleProductCategory = $this->helperData->getMappedCategory($product->getCategoryIds());
            $cost = $this->getPriceForFeed($product, $storeDetail);
            $salePrice = $this->getSalePriceForFeed($product, $storeDetail);
            $store = $this->storeManager->getStore($storeDetail['store_id']);
            $productData = $this->helperData->getProductDataAsFieldMap($product, $configProOptions);
            if (isset($productData['description']) && \str_contains($productData['description'], '</style>')) {
                $productData['description'] = explode('</style>', $productData['description'])[1];
            }
            $feedProduct = new \Google_Service_ShoppingContent_Product();
            // $this->logger->info('googleFeedProduct: '. print_r(get_class_methods($feedProduct)));
            $feedProduct->setChannel("online");
            $feedProduct->setContentLanguage($storeDetail['language']);
            $feedProduct->setOfferId($productData['offerId']);
            $feedProduct->setTargetCountry($storeDetail['country']);
            $feedProduct->setTitle($productData['title']);
            $feedProduct->setDescription($productData['description']);
            $availability = $product->getQuantityAndStockStatus();
            $availability = isset($availability['qty']) && $availability['qty'] ? "in stock" : "out of stock";
            $feedProduct->setAvailability($availability);
            //$link = $store->getBaseUrl().$product->getUrlKey().'.html';
            //$link = $product->setStoreId($storeDetail['store_id'])->getUrlModel()
            //->getUrlInStore($product, ['_escape' => true]);
            $feedProduct->setLink($product->getProductUrl());
            if (isset($productData['brand']) && $productData['brand']) {
                $feedProduct->setBrand($productData['brand']);
            }
            if (isset($productData['color']) && $productData['color']) {
                $feedProduct->setColor($productData['color']);
            }
            if ($groupItem) {
                $feedProduct->setItemGroupId($groupItem->getSku());
                $link = $store->getBaseUrl() . trim($groupItem->getUrlKey()) . '.html';
                $feedProduct->setLink($link);
            }
            $feedProduct->setGender($productData['gender']);
            $customProduct = $product->getGfCustomProduct();
            if (isset($productData['gtin']) && !$customProduct) {
                $feedProduct->setGtin($productData['gtin']);
             
            } else {
                $feedProduct->setIdentifierExists(false);
            }
            $feedProduct->setAgeGroup($productData['ageGroup']);
            if (isset($productData['sizes'])) {
                $feedProduct->setSizes($productData['sizes']);
            }
            if (isset($productData['sizeType'])) {
                $feedProduct->setSizes($productData['sizeType']);
            }
            if (isset($productData['sizeSystem'])) {
                $feedProduct->setSizeSystem($productData['sizeSystem']);
            }

            $imageLink = isset($productData['imageLink']) && $productData['imageLink'] == 'no_selection' ?
            '/placeholder/image.jpg' : $productData['imageLink'];
            $feedProduct->setImageLink($storeDetail['base_media_url'] . 'catalog/product' . $imageLink);
            $feedProduct->setCondition($productData['condition']);
            $feedProduct->setTitle($product->getName());

            $taxShip = $productData['taxShip'] == 'Yes' ? true : false;
            $shipTaxGlobal = $this->scopeConfig->getValue('googleshoppingfeed/default_config/tax_on_ship');
            $shipApplied = $taxShip || ($productData['taxShip'] != 'No' && $shipTaxGlobal) ? true : false;
            $tax = new \Google_Service_ShoppingContent_ProductTax();
            $tax->setCountry($storeDetail['country']);
            $productData['taxRate'] = $productData['taxRate'] ? $productData['taxRate'] :
            $this->scopeConfig->getValue('googleshoppingfeed/default_config/tax_rate');
            $tax->setRate($productData['taxRate']);
            $tax->setTaxShip($shipApplied);
            $feedProduct->setTaxes([$tax]);
            if ($googleProductCategory) {
                $feedProduct->setGoogleProductCategory($googleProductCategory);
                /**
 * $feedProduct->setProductTypes($googleProductCategory);
*/
            }
            if (isset($productData['shippingWeight']) && $productData['shippingWeight']) {
                $shippingWeight = new \Google_Service_ShoppingContent_ProductShippingWeight();
                $shippingWeight->setValue($productData['shippingWeight']);
                $shippingWeight->setUnit($this->scopeConfig->getValue('googleshoppingfeed/default_config/weight_unit'));
                $feedProduct->setShippingWeight($shippingWeight);
            }

            $price = new \Google_Service_ShoppingContent_Price();
            $price->setCurrency($storeDetail['currency_code']);
            $price->setValue($cost);
            $feedProduct->setPrice($price);
            if ($salePrice > 0) {
                $salePriceCost = new \Google_Service_ShoppingContent_Price();
                $salePriceCost->setCurrency($storeDetail['currency_code']);
                $salePriceCost->setValue($salePrice);
                $feedProduct->setSalePrice($salePriceCost);
                $date = $this->dateTimeZone->date(new \DateTime($product->getSpecialFromDate()??''))
                ->format("Y-m-d") . "/"
                . $this->dateTimeZone->date(new \DateTime($product->getSpecialToDate()??''))->format("Y-m-d");
                $feedProduct->setSalePriceEffectiveDate($date);
            }
            return $feedProduct;
        } catch (\Exception $e) {
            throw new LocalizedException(__($e->getMessage()));
        }
    }

        /**
         * Delete FeedFromGoogleShop
         *
         * @param mixed $feedCollection
         * @param array $shopConfig
         */
    public function deleteFeedFromGoogleShop($feedCollection, $shopConfig = null)
    {
        try {
            $config = $shopConfig ? $shopConfig : $this->helperData->getConfigDetails();
            $deleteProducts = [];
          
            foreach ($feedCollection->getItems() as $item) {
                $feedId = $item->getFeedId();
                $product = $this->productRepository->getById($item->getMageProId());
                if ($product->getTypeId() != 'configurable') {
                    $client = new \Google_Client();
                    $client->setAccessToken($config['oauth2_access_token']);
                      
                    $deleteProducts[] = [
                    "batchId" => rand(1, 999).rand(1, 999),
                    "merchantId" => $config['merchant_id'],
                    "method" => "delete",
                    "productId" => $item->getFeedId()
                    ];
                }

                if ($product->getTypeId() == 'configurable') {
                    $associatePro = $product->getTypeInstance()->getUsedProducts($product);
                    $feedId = explode(":", $feedId);
                    foreach ($associatePro as $pro) {
                        $feedId[count($feedId)-1] = $pro->getSku();
                        $deleteProducts[] = [
                            "batchId" => rand(1, 999).rand(1, 999),
                            "merchantId" => $config['merchant_id'],
                            "method" => "delete",
                            "productId" => implode(":", $feedId)
                        ];
                    }
                 
                }
            }
                $feedProduct = new \Google_Service_ShoppingContent_ProductsCustomBatchRequest();
                $feedProduct->setEntries($deleteProducts);
                $product = $this->insertFeedToGoogleShopInBatch($feedProduct);
           
            return $product;
        } catch (\Exception $e) {
            throw new LocalizedException(__($e->getMessage()));
        }
    }

    /**
     * Process ConfigForExport
     *
     * @param  \Magento\Catalog\Model\Product                 $product
     * @param  \Webkul\GoogleShoppingFeed\Model\GoogleFeedMap $googleFeedMap
     * @param  array                                          $storeDetailForFeed
     * @return array
     */
    public function processConfigForExport($product, $googleFeedMap, $storeDetailForFeed)
    {
        try {
            $optionsDataList = $product->getTypeInstance(true)->getConfigurableAttributesAsArray($product);
            $associatePro = $this->configProTypeModel->getChildrenIds($product->getEntityId());
            if (isset($associatePro[0]) && !empty($associatePro[0])) {
                foreach ($associatePro[0] as $associateProId) {
                    $associateProduct = $this->productRepository->getById($associateProId);
                    $feedProduct = $this->getProductForFeed(
                        $associateProduct,
                        $storeDetailForFeed,
                        $product,
                        $optionsDataList
                    );
                    $items = $this->insertFeedToGoogleShop($feedProduct);
                    $expireDate = $this->dateTime->gmtDate('Y-m-d H:i:s', strtotime("+30 days"));
                    $syncsFeeds = [
                        'feed_id' => $items['product']['id'],
                        'mage_pro_id' => $product->getEntityId(),
                        'expired_at' => $expireDate,
                        'store_id' => $storeDetailForFeed['store_id'],
                    ];
                    if (($items['error'] == 0) && $googleFeedMap->getEntityId()) {
                        $googleFeedMap->setExpiredAt($expireDate);
                        $googleFeedMap->setFeedId($items['product']['id']);
                    } else {
                        $googleFeedMap->setData($syncsFeeds)->save();
                    }
                    $googleFeedMap->save();
                }
            }
            $result = ['error' => 0, 'total' => 1];
        } catch (\Exception $e) {
            $this->logger->error('processConfigForExport: ' . $e->getMessage());
            $result = ['error' => 1, 'message' => $e->getMessage(), 'total' => 0];
        }
        return $result;
    }

    /**
     * Get ProductForFeed
     *
     * @param  mixed                         $productsList
     * @param  array                         $storeDetail
     * @param  Magento\Catalog\Model\product $groupItem
     * @param  array                         $configProOptions
     * @return \Google_Service_ShoppingContent_Product
     */
    public function getProductBatchForFeed($productsList, $storeDetail, $groupItem = false, $configProOptions = [])
    {
        try {
            $entries = [];
            $syncsFeeds = [];
            $config = $this->helperData->getConfigDetails();
            $store = $this->storeManager->getStore($storeDetail['store_id']);
            $productCount = 0;
            foreach ($productsList as $product) {
                $this->logger->info($product->getId());
                if ($product->getTypeId() == 'configurable') {
                    $optionsDataList = $product->getTypeInstance(true)->getConfigurableAttributesAsArray($product);
                    $associatePro = $this->configProTypeModel->getChildrenIds($product->getEntityId());
                    if (isset($associatePro[0]) && !empty($associatePro[0])) {
                        foreach ($associatePro[0] as $associateProId) {
                            $associateProduct = $this->productRepository->getById($associateProId);
                            if ($associateProduct->getStatus() == 1) {
                                $productData = $this->getProductDataForGoogleBatch(
                                    $associateProduct,
                                    $storeDetail,
                                    $configProOptions
                                );
                                $productData['itemGroupId'] = $product->getSku();
                                $productData['link'] = $store->getBaseUrl().trim($product->getUrlKey()).'.html';
                                $entries[] = [
                                    'batchId' => rand(1, 9999).rand(1, 9999),
                                    'merchantId' => $config['merchant_id'],
                                    'method' => 'insert',
                                    'product' => $productData
                                ];
                            }
                        }
                        $syncsFeeds[] = [
                            'feed_id' => 'online:'.$storeDetail['language'].':'.$storeDetail['country'].':'
                            .$product->getSku(),
                            'mage_pro_id' => $product->getEntityId()
                        ];
                        $productCount++;
                    }
                } else {
                    if ($product->getStatus() == 1) {
                        $entries[] = [
                            'batchId' => rand(1, 9999).rand(1, 9999),
                            'merchantId' => $config['merchant_id'],
                            'method' => 'insert',
                            'product' => $this->getProductDataForGoogleBatch($product, $storeDetail, $configProOptions)
                        ];
                        $productCount++;
                        $syncsFeeds[] = [
                            'feed_id' => 'online:'.$storeDetail['language'].':'
                            .$storeDetail['country'].':'.$product->getSku(),
                            'mage_pro_id' => $product->getEntityId()
                        ];
                    }
                }
            }
            $feedProduct = new \Google_Service_ShoppingContent_ProductsCustomBatchRequest();
            $feedProduct->setEntries($entries);
            $result = $this->insertFeedToGoogleShopInBatch($feedProduct);
            $result['syncsFeeds'] = $syncsFeeds;
            $result['total'] = $productCount;
            return $result;
        } catch (\Exception $e) {
            throw new LocalizedException(__($e->getMessage()));
        }
    }

      /**
       * Get data for batch
       *
       * @param mixed $product
       * @param mixed $storeDetail
       * @param mixed $configProOptions
       * @return void
       */
    public function getProductDataForGoogleBatch($product, $storeDetail, $configProOptions)
    {
        //$productWebsId = $product->getWebsiteIds();

        $googleProductCategory = $this->helperData->getMappedCategory($product->getCategoryIds());
        $cost = $this->getPriceForFeed($product, $storeDetail);
        $salePrice  = $this->getSalePriceForFeed($product, $storeDetail);
        //$store = $this->storeManager->getStore($storeDetail['store_id']);
        $productData = $this->helperData->getProductDataAsFieldMap($product, $configProOptions);

        $imageLink =  isset($productData['imageLink']) && $productData['imageLink'] == 'no_selection' ?
                            '/placeholder/image.jpg' : $productData['imageLink'];
        $productData['imageLink'] = $storeDetail['base_media_url'] . 'catalog/product' . $imageLink;

        $productData['price'] = [
          "value" => $cost,
          "currency" => "INR"
        ];
        if ($salePrice > 0) {
            $productData['salePrice'] = [
              "value" => $salePrice,
              "currency" => "INR"
            ];
            $dateFrom = $product->getSpecialFromDate() ? $product->getSpecialFromDate() : '';
            $dateTo = $product->getSpecialToDate() ? $product->getSpecialToDate() : '';
            $productData['salePriceEffectiveDate'] = $this->dateTimeZone
            ->date(new \DateTime($dateFrom))->format("Y-m-d")."/"
                  .$this->dateTimeZone->date(new \DateTime($dateTo))->format("Y-m-d");
        }
        $taxShip = $productData['taxShip'] == 'Yes'  ? true : false;
        $shipTaxGlobal = $this->scopeConfig->getValue('googleshoppingfeed/default_config/tax_on_ship');
        $shipApplied = $taxShip || ($productData['taxShip'] != 'No' && $shipTaxGlobal) ? true : false;
        $productData['taxRate'] = $productData['taxRate'] ? $productData['taxRate'] :
            $this->scopeConfig->getValue('googleshoppingfeed/default_config/tax_rate');
        $productData['taxes'] = [
            [
                'country' => $storeDetail['country'],
                'rate' => $productData['taxRate'],
                'taxShip' => $shipApplied
            ]
        ];
        unset($productData['taxRate']);
        if (isset($productData['shippingWeight']) && $productData['shippingWeight']) {
            $productData['shippingWeight'] = [
                'value' => $productData['shippingWeight'],
                'unit' => $this->scopeConfig->getValue('googleshoppingfeed/default_config/weight_unit')
            ];
        }
        unset($productData['taxShip']);
        $availability = 0;
        if ($this->sourceDataBySku) {
            $inventorySourceList = $this->sourceDataBySku->execute($product->getSku());
            if (is_array($inventorySourceList) && !empty($inventorySourceList)) {
                foreach ($inventorySourceList as $key => $inventorySource) {
                    $availability += (float)$inventorySource['quantity'];
                }
            }
        } else {
            $availability = $this->getProductQty($product->getId(), $product->getStore()->getWebsiteId());
        }
        $availability = $availability > 0 ? "in stock" : "out of stock";
        $productData['availability'] = $availability;
        $productData['channel']="online";
        $productData['contentLanguage']=$storeDetail["language"];
        $productData['targetCountry']=$storeDetail['country'];
        return $productData;
    }

      /**
       * Insert FeedToGoogleShop
       *
       * @param  Google_Service_ShoppingContent_Product $productFeeds
       * @return Google_Service_ShoppingContent_Product
       */
    public function insertFeedToGoogleShopInBatch($productFeeds)
    {
        try {
            $this->logger->info('check working');

            $accessToken = $this->helperData->getAccessToken();
            if ($accessToken) {
                $config = $this->helperData->getConfigDetails();
                $client = new \Google_Client();
                $client->setAccessToken($config['oauth2_access_token']);
                $serviceShoppingContent =  new \Google_Service_ShoppingContent($client);
                // $this->logger->addError('created google client  : ');

                $product = $serviceShoppingContent->products->custombatch($productFeeds);
                $this->logger->error('exportData : '.json_encode($product));

                return ['error' => 0, 'product' => $product];
            } else {
                return ['error' => 1, 'product' => null, 'message' => __('Google feed account not authenticated.')];
            }
        } catch (\Exception $e) {
            $this->logger->addError('postShopData : '.$e->getMessage());
            return ['error' => 1, 'product' => null, 'message' => $e->getMessage()];
        }
    }
}
