<?php

namespace Modules\Product\Repositories;

use Illuminate\Http\Request;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
use Modules\Product\Enums\ProductStatusEnum;
use Modules\Product\Interfaces\ProductRepositoryInterface;
use Modules\Product\Models\Favorite;
use Modules\Product\Models\Item;
use Modules\Product\Models\ItemDescription;
use Modules\Product\Models\Product;
use Modules\Product\Models\ProductAddition;
use Modules\Product\Models\ProductAttribute;
use Modules\Product\Models\ProductDescription;
use Modules\Product\Models\ProductItem;
use Modules\Product\Models\ProductItemDescription;
use Modules\Product\Models\ProductLog;
use Modules\Product\Models\ProductPhoto;
use Modules\User\Services\AccountService;
use DB;

class ProductRepository implements ProductRepositoryInterface
{
    private AccountService $accountService;
    public function __construct(AccountService $accountService)
    {
        $this->accountService = $accountService;
    }
    public function get(Request $request)
    {
        $query = Product::query()
            ->join('product_descriptions AS sd', 'products.id', 'sd.product_id')
            ->join('languages', 'languages.id', 'sd.language_id')
            ->where('local', LaravelLocalization::getCurrentLocale())
            ->select(['sd.title','sd.description', 'products.*']);

        if ($request->favorite)
        {
            $account = $this->accountService->getAccount();
            $query->whereHas('favorites',function ($q) use($account){
                $q->where('status',$account['status'])->where('user_id',$account['user']->id);
            });
        }

        if ($request->not_id) {
            $query->where('products.id','!=', $request->not_id);
        }

        if ($request->status_sold)
        {
            $query->where('products.status_sold', $request->status_sold);
        }
        if ($request->category_id)
        {
            $query->where('products.category_id', $request->category_id);
        }

        if ($request->sub_ids) {
            if (count($request->sub_ids))
            {
                $query->whereIn('products.sub_category_id', $request->sub_ids);
            }
            else
            {
                if ($request->main_category_id)
                {
                    $query->where('products.category_id', $request->main_category_id);
                }
            }
        }
        else
        {
            if ($request->main_category_id) {
                $query->where('products.category_id', $request->main_category_id);
            }
        }

        if ($request->discount)
        {
            $query->where('products.cost_discount','!=',null);
        }
        if ($request->title) {
            $query->where('sd.title', 'LIKE', '%'.$request->title.'%');
        }

        if ($request->sold)
        {
            $query->whereHas('orders')->withSum('orders', 'count');
            $query->orderByDesc('orders_sum_count');
        }

        if ($request->date_from) {
            $query->whereDate('products.created_at', '>=', $request->date_from);
        }

        if ($request->date_to) {
            $query->whereDate('products.created_at', '<=', $request->date_to);
        }


        if ( !is_null($request->status) && $request->status == 0) {
            $query->onlyTrashed();
        }

        if ($request->orderBy)
        {
            if ($request->orderBy == 'newest')
            {
                $query->orderBy('products.id','DESC');
            }

            if ($request->orderBy == 'oldest')
            {
                $query->orderBy('products.id','ASC');
            }
            if (in_array($request->orderBy ,[ 'priceDesc','priceAsc','rate']))
            {
                $orderedIds = $this->orderByIds($request);
                $query->orderByRaw("field(products.id,".$orderedIds.")");
            }
        }

        if ($request->min_cost)
        {
            $query->whereRaw('IF(`cost_discount` != "", `cost_discount`, `cost`) >= '.$request->min_cost);
        }

        if ($request->max_cost)
        {
            $query->whereRaw('IF(`cost_discount` != "", `cost_discount`, `cost`) <= '.$request->max_cost);
        }

        if($request->size_ids)
        {
            $query->whereHas('sizes',function ($q) use ($request){
               $q->whereIn('attribute_id',$request->size_ids);
            });
        }

        if($request->color_ids)
        {
            $query->whereHas('colors',function ($q) use ($request){
                $q->whereIn('attribute_id',$request->color_ids);
            });
        }
        if ($request->paginate ?? null) {
            $products= $query->paginate(is_numeric($request->paginate)? $request->paginate : 50);
        }else{
            $products=$query->cursor();
        }


        return $products;
    }


    public function orderByIds(Request $request)
    {
        $query = Product::query()
            ->join('product_descriptions AS sd', 'products.id', 'sd.product_id')
            ->join('languages', 'languages.id', 'sd.language_id')
            ->where('local', LaravelLocalization::getCurrentLocale())
            ->select(['sd.title','sd.description', 'products.*']);


        if ($request->category_id)
        {
            $query->where('products.category_id', $request->category_id);
        }

        if ($request->sub_ids) {
            if (count($request->sub_ids))
            {
                $query->whereIn('products.sub_category_id', $request->sub_ids);
            }
            else
            {
                if ($request->main_category_id)
                {
                    $query->where('products.category_id', $request->main_category_id);
                }
            }
        }
        else
        {
            if ($request->main_category_id) {
                $query->where('products.category_id', $request->main_category_id);
            }
        }

        if ($request->min_cost)
        {
            $query->whereRaw('IF(`cost_discount` != "", `cost_discount`, `cost`) >= '.$request->min_cost);
        }

        if ($request->max_cost)
        {
            $query->whereRaw('IF(`cost_discount` != "", `cost_discount`, `cost`) <= '.$request->max_cost);
        }

        if($request->size_ids)
        {
            $query->whereHas('sizes',function ($q) use ($request){
                $q->whereIn('attribute_id',$request->size_ids);
            });
        }

        if($request->color_ids)
        {
            $query->whereHas('colors',function ($q) use ($request){
                $q->whereIn('attribute_id',$request->color_ids);
            });
        }
        $products=$query->get();
        if ($request->orderBy)
        {
            if ($request->orderBy == 'priceDesc')
            {
                $products = $products->sortByDESC('price');
            }

            if ($request->orderBy == 'priceAsc')
            {
                $products = $products->sortBy('price');
            }
            if ($request->orderBy == 'rate')
            {
                $products = $products->sortByDESC('rate');
            }
        }
        $ids = $products->pluck('id')->toArray();
        if (count($ids) == 0)
        {
            $ids = ['0'];
        }
        $orderedIds = implode(',', $ids );
        return $orderedIds;
    }

    public function getItem(Product $product)
    {
        $query = Product::where('products.id', $product->id)
            ->join('product_descriptions', 'product_descriptions.product_id','products.id')
            ->join('languages', 'languages.id', 'product_descriptions.language_id')
            ->select(['products.*','product_descriptions.title','product_descriptions.description', 'languages.local']);

        $productDescription= $query->get();

        foreach ($productDescription as $key=>$row) {
            if ($row->local == getCurrentLocale())
            {
                $product = $row;
            }
            $product[$row->local] = $row;
        }
        return $product ;
    }
    public function updateStatus(Request $request, Product $product): Product
    {
        $data= $request->all();
        $product->update($data);
        if ($request->status == ProductStatusEnum::INVALID->value)
        {
            ProductLog::create([
                'product_id'=>$product->id,
                'message'=>$request->message,
                'reason_id'=>$request->reason_id
            ]);
        }
        return $product;
    }

    //
    public function save(Request $request, ?Product $product): Product
    {
        $data= $request->all();
        unset($data['id']);// for security reasons
        if (!$product) {
            $product = Product::create($data);
        } else {
            $product->update($data);
            ProductDescription::where('product_id', $product->id)->delete();
            ProductItem::where('product_id', $product->id)->delete();
            ProductAttribute::where('product_id', $product->id)->delete();
            ProductPhoto::where('product_id', $product->id)->delete();
        }
        $this->saveData( $request, $product->id );
        return $product;
    }

    private function saveData(Request $request, int $product_id ) :void
    {
        $requestData= $request->all();
        foreach (languages() as $lang) {
            $data=[
                'product_id'=> $product_id,
                'language_id'=> $lang->id,
                'title'=> $requestData['title_'.$lang->local],
                'description'=> $requestData['description_'.$lang->local],
            ];

            ProductDescription::create($data);
        }
        if (isset($requestData['images']))
        {
            foreach ($request->images as $row)
            {
                ProductPhoto::create([
                    'image' => $row,
                    'product_id' => $product_id,
                ]);
            }
        }

        if (isset($requestData['sizes']))
        {
            foreach ($requestData['sizes'] as $row)
            {
                $size = ProductAttribute::create([
                    'attribute_id'=>$row['size_id'],
                    'product_id' => $product_id,
                ]);
                foreach ($row['colors'] as $color)
                {
                    ProductAttribute::create([
                        'count' => $color['count'],
                        'main_attribute_id' => $size->id,
                        'attribute_id' => $color['color_id'],
                        'product_id' => $product_id,
                    ]);
                }
            }
        }

        if (isset($requestData['items']))
        {
            foreach ($requestData['items'] as $row)
            {
                $item = ProductItem::create([
                    'product_id' => $product_id,
                ]);
                foreach (languages() as $lang)
                {
                    $data=[
                        'product_item_id'=> $item->id,
                        'language_id'=> $lang->id,
                        'title'=>$row['title_'.$lang->local],
                    ];
                    ProductItemDescription::create($data);
                }
                if (isset($row['item']))
                {
                    foreach ($row['item'] as $rowItem)
                    {
                        $item_row = Item::create([
                            'product_item_id' => $item->id,
                        ]);
                        foreach (languages() as $lang)
                        {
                            $data =
                            [
                                'item_id'=> $item_row->id,
                                'language_id'=> $lang->id,
                                'title'=>$rowItem['title_'.$lang->local],
                                'description'=>$rowItem['description_'.$lang->local],
                            ];
                            ItemDescription::create($data);
                        }
                    }
                }
            }
        }
    }
    public function items(Product $product)
    {
        $items = ProductItem::where('product_id',$product->id)->get();
        return $items;
    }
    public function additions(Product $product)
    {
        $additons = ProductAddition::where('product_id',$product->id)->get();
        return $additons;
    }
    public function logs(Product $product)
    {
        $logs = ProductLog::where('product_id',$product->id)->get();
        return $logs;
    }

    public function sizes(Product $product)
    {
        $sizes = ProductAttribute::where('product_id',$product->id)->where('main_attribute_id',null)->get();
        return $sizes;
    }
    /**
     * Remove the specified client from storage.
     * @param Request $request
     * @param int $id
     * @return array
     * @throws Exception
     */
    public function destroy(Request $request, int $id) :array
    {
        $product= Product::withTrashed()->find($id);
        if ($product) {
            if ($product->deleted_at) {
                $product->forceDelete();
            } else {
                $product->delete();
            }
            return [ ['message'=> __('dashboard.deletedDone')]];
        } else{
            return [ ['message'=> __('dashboard.noResult')], 400];
        }
    }

    /**
     * Remove several clients by IDs.
     *
     * @param Request $request
     * @return array
     */
    public function destroyAll(Request $request) :array
    {
        $ids= $request->ids;
        $query= Product::whereIn('id', $ids);
        if ($request->force) {
            $deleted= $query->onlyTrashed()->forceDelete();
        } else {
            $deleted= $query->delete();
        }
        if($deleted){
            return [['message'=> __('dashboard.deletedDone')]];
        }
        return [ ['message'=> __('dashboard.noResult')], 400];
    }

    /**
     * Restore the specified client from storage.
     *
     * @param Request $request
     * @param int $id
     * @return array
     */
    public function restore(Request $request, int $id) :array
    {
        $product= Product::withTrashed()->find($id);
        if ($product) {
            $product->restore();
            return [['message'=> __('dashboard.saveDone')]];
        }
        return [['message'=> __('dashboard.noResult')], 400];

    }

    /**
     * Restore several clients by IDs.
     *
     * @param Request $request
     * @return array
     */
    public function restoreAll(Request $request) :array
    {
        $ids= $request->ids;
        Product::whereIn('id', $ids)->onlyTrashed()->restore();
        return [['message'=> __('dashboard.saveDone')]];
    }

    public function favorite(Request $request) :void
    {
        Favorite::create($request->all());
    }
    public function deleteFavorite(Request $request) :void
    {
        Favorite::query()
            ->where('status',$request->status)
            ->where('product_id',$request->product_id)
            ->where('user_id',$request->user_id)
            ->delete();
    }
    public function getItemFav(Request $request)
    {
        $fav = Favorite::query()
            ->where('status',$request->status)
            ->where('product_id',$request->product_id)
            ->where('user_id',$request->user_id)
            ->first();
        return $fav;
    }
}
