<?php

namespace App\Repositories;

use App\Models\OrderArchive;
use App\Models\PriceList;
use App\Models\Product;
use App\Models\ProfitCenter;

class ProductRepository extends RepositoryBase implements ProductRepositoryInterface
{
    private ?bool $needPrice = false;

    private ?string $deliveryDate = null;

    public function setNeedPrice(bool $needPrice): void
    {
        $this->needPrice = $needPrice;
    }

    /**
     * @var array|string[]
     */
    private array $defaultRelations = ['ProductGroup', 'Supplier', 'Producer', 'LastPrice'];

    /**
     * ProductRepository constructor.
     */
    // public function __construct(Product $Model)
    public function __construct()
    {
        /*        $this->Model = Product::class;
                $this->actualRelations = $this->defaultRelations;
        */
        parent::__construct(Product::class, $this->defaultRelations);
    }

    /**
     * Get's a record by it's supplier_id and supplierProductNumber
     */
    public function getBySupplierAndSupplierProductNumber(int $supplierId, string $supplierProductNumber, $withRelations = false, ?array $relationOptions = null): ?array
    {
        if ($withRelations) {
            if ($relationOptions) {
                $this->setRelation($relationOptions);
            }
            $product = $this->getQueryWithRelations();

        } else {
            $product = new Product;
        }
        if ($productData = $product->where('supplier_id', $supplierId)
            ->where('supplierProductNumber', $supplierProductNumber)->get()->first()) {
            return $productData->toArray();
        } else {
            return null;
        }
        /*        return $product->where('supplier_id',$supplierId)
                    ->where('supplierProductNumber',$supplierProductNumber)->get()->first()->toArray();*/
    }

    /**
     * Get's a record by it's ID withRelations
     *
     * @param int|array
     */
    public function getWithRelations($id): ?array
    {
        $ret = [];
        if (gettype($id) == 'array') {
            $ret = $this->getQueryWithRelations()->whereIn('id', $id)->orderBy('name')->get();
            foreach ($ret as $item) {
                $item->setAttributePrice($this->deliveryDate);
            }
        } else {
            $ret = $this->getQueryWithRelations()->where('id', $id)->first();
            if ($this->needPrice) {
                $ret->setAttributePrice($this->deliveryDate);
            }
        }

        return $ret->toArray();
    }

    /**
     * Get's a record by groupID [withRelations]
     *
     * @param int
     */
    public function getByGroupId($groupId, $withRelations = false): ?array
    {
        if ($withRelations) {
            return $this->getQueryWithRelations()->where('product_group_id', $groupId)->get()->toArray();
        } else {
            return Product::where('product_group_id', $groupId)->get()->toArray();
        }

    }

    public function getSupplierProductGroupsIdFromPriceList(int $supplierId, ?string $deliveryDate = null)
    {
        $priceLists = PriceList::where('supplier_id', $supplierId);
        if ($deliveryDate) {
            $priceLists->where('available', '<=', $deliveryDate);
        }
        if ($priceLists->orderBy('available', 'desc')->first()) {
            $products = $priceLists->orderBy('available', 'desc')->first()->products();

            return array_keys($products->get()->groupBy('product_group_id')->toArray());
        }

        return null;
    }

    /*
     getSupplierProductSpecial
        private function getSupplierProductSpecial() {

        }
     */

    private function getSupplierProductSpecialLast($supplierId, $products, $options)
    {
        $maxItems = 20;
        $Orders = OrderArchive::select('productSelected')->where('profit_center_id', $options['profitCenterId'])->where('supplier_id', $supplierId)->orderBy('id', 'desc')->take(50)->get();
        $productsIds = [];
        foreach ($Orders as $order) {
            // $orderProducts=json_decode($order->productSelected);
            if (count($productsIds) < $maxItems) {
                $productsIds = array_unique(array_merge($productsIds, array_keys(json_decode($order->productSelected, true))));
            }
        }
        $productsIds = array_slice($productsIds, 0, $maxItems);
        $products->whereIn('id', $productsIds);
        $products->orderBy('name');

        return $products;
    }

    private function getSupplierProductSpecialOften($supplierId, $products, $options)
    {
        $maxItems = 20;
        $Orders = OrderArchive::select('productSelected')->where('profit_center_id', $options['profitCenterId'])->where('supplier_id', $supplierId)->orderBy('id', 'desc')->take(50)->get();
        $productsIds = [];
        foreach ($Orders as $order) {
            // $orderProducts=json_decode($order->productSelected);
            $orderProductIds = array_keys(json_decode($order->productSelected, true));
            foreach ($orderProductIds as $pid) {
                if (! isset($productsIds[$pid])) {
                    $productsIds[$pid] = 1;
                } else {
                    $productsIds[$pid]++;
                }
            }
        }

        arsort($productsIds);
        $productsIds = array_keys($productsIds);
        $productsIds = array_slice($productsIds, 0, $maxItems);
        $products->whereIn('id', $productsIds);
        $products->orderBy('name');

        return $products;

    }

    private function getSupplierProductSpecialFavorites($supplierId, $products, $options)
    {
        debug(__FUNCTION__);
        $favorites = ProfitCenter::find($options['profitCenterId'])->favorites()->get()->pluck('id')->toArray();
        $products->whereIn('id', $favorites);

        return $products;
    }

    private function getSupplierProductSpecialSpecialOffer($supplierId, $products, $options)
    {
        debug(__FUNCTION__);
        $products->where('specialOffer', 1);

        return $products;
    }

    private function getSupplierProductSpecialWeekly($supplierId, $products, $options)
    {
        debug(__FUNCTION__);
        $maxItems = 20;
        $Orders = OrderArchive::select('id', 'orderType', 'orderFlag', 'productSelected')
            ->where('profit_center_id', $options['profitCenterId'])
            ->where('supplier_id', $supplierId)
            ->where('orderType', '=', 'daily')
            ->whereNotNull('parent_id')
            ->where(function ($query) {
                $query->whereNull('orderFlag')
                    ->orwhere('orderFlag', 'modifier');
            })
            ->orderBy('id', 'desc')->take(50)->get();
        $productsIds = [];
        foreach ($Orders as $order) {
            // $orderProducts=json_decode($order->productSelected);
            $orderProductIds = array_keys(json_decode($order->productSelected, true));
            foreach ($orderProductIds as $pid) {
                if (! isset($productsIds[$pid])) {
                    $productsIds[$pid] = 1;
                } else {
                    $productsIds[$pid]++;
                }
            }
        }
        arsort($productsIds);
        $productsIds = array_keys($productsIds);
        $productsIds = array_slice($productsIds, 0, $maxItems);
        $products->whereIn('id', $productsIds);
        $products->orderBy('name');

        return $products;
    }

    private function getSupplierProductSpecial($supplierId, $products, $options)
    {
        $functionName = 'getSupplierProductSpecial'.ucfirst($options['type']);
        debug('call'.$functionName);
        if (method_exists($this, $functionName)) {
            return call_user_func([$this, $functionName], $supplierId, $products, $options);
        }

        return $products;
    }

    private function assignFavoritesToProductArray($profitCenterId, $productsArray)
    {
        $favorites = ProfitCenter::find($profitCenterId)->favorites()->get()->pluck('id')->toArray();

        foreach ($productsArray as $key => $product) {
            if (in_array($product['id'], $favorites)) {

                $productsArray[$key]['favorites'] = true;
            } else {
                $productsArray[$key]['favorites'] = false;
            }
        }

        return $productsArray;
    }

    public function getSupplierProductFromPriceList(int $supplierId, int $profitCenterId, ?string $deliveryDate = null, ?int $productGroupId = null, ?string $searchStr = null, ?array $special = null)
    {
        debug('special', $special);
        $productsArray = [];
        $priceLists = PriceList::where('supplier_id', $supplierId);
        if ($deliveryDate) {
            $priceLists->where('available', '<=', $deliveryDate);
        }
        if ($priceLists->orderBy('available', 'desc')->first()) {
            $products = $priceLists->first()->products();
            $products->where('canSee', 1);
            // dd($products->get()->toArray());
            if ($special && isset($special['type'])) {
                $products = $this->getSupplierProductSpecial($supplierId, $products, $special);
            }
            if ($productGroupId) {
                $products->where('product_group_id', $productGroupId);
            }
            if ($searchStr) {
                $products->where('name', 'like', "%$searchStr%");
            }

            if (isset($special['krel'])) {
                $products->where('krel', 1);
            }
            $productsArray = $products->get()->toArray();
        }

        if ($special && isset($special['withFavorites'])) {
            $productsArray = $this->assignFavoritesToProductArray($profitCenterId, $productsArray);
        }

        return $productsArray;
    }

    /**
     * Get's all records by indexed.
     *
     * @return mixed
     */
    public function allByIndex($index)
    {
        if (! $index) {
            return Product::all()->keyBy('id')->toArray();
        } else {
            return Product::all()->keyBy($index)->toArray();
        }
    }

    public function checkIsChanged(int $id, array $data)
    {
        /* //error test
                if($id==2){
                    return ['error'=>'invalid Item'];
                }*/
        /**
         * @var $product \App\Models\Product
         */
        /*
                if(!$product=Product::find($id)){
                    return ['error'=>'invalid Item'];
                }
        */
        if (! $product = $this->Model::find($id)) {
            return ['error' => 'invalid Item'];
        }
        /*        print "<pre>";
                $data['name']='proba';*/

        foreach (array_keys($product->toArray()) as $key) {

            if (// isset($data[$key]) ||
                array_key_exists($key, $data)
            ) {
                $product->$key = $data[$key];
            }
        }
        if ($product->isDirty()) {
            $ret = [];
            foreach ($product->getDirty() as $key => $value) {
                $ret[$key] = ['old' => $product->getOriginal($key), 'new' => $product->$key];
            }

            return $ret;
        }

        return [];
    }

    public function setDeliveryDate(string $deliveryDate): void
    {
        $this->deliveryDate = $deliveryDate;
    }

    public function updatePrice($id, float $price): bool
    {
        /**
         * @var $product \App\Models\Product
         */
        if (! $product = $this->Model::find($id)) {
            return ['error' => 'invalid Item'];
        }

        $product->setAttributePrice();
        if ($product->price != $price) {
            $priceList = $product->getActualPriceList();

            return $priceList->products()->updateExistingPivot($product, ['price' => $price]);
        }

        return true;
    }

    public function updateVisibilitiesByIds(array $productIds, bool $canSee = true): bool
    {
        return $this->Model::whereIn('id', $productIds)->update(['canSee' => $canSee]);
    }
}
