<?php namespace AhmadFatoni\ApiGenerator\Controllers\API;

use Cms\Classes\Controller;
use Illuminate\Http\Request;
use AhmadFatoni\ApiGenerator\Helpers\Helpers;
use Illuminate\Support\Facades\Validator;
use TPS\Birzha\Models\Product;
use TPS\Birzha\Models\Favourites;
use TPS\Birzha\Models\Category;
use TPS\Birzha\Models\City;
use TPS\Birzha\Models\Term;
use TPS\Birzha\Models\Measure;
use TPS\Birzha\Models\Settings;
use October\Rain\Support\Facades\Event;
use TPS\Birzha\Classes\ErrorResponseApi;
use TPS\Birzha\Classes\MeasureResource;
use TPS\Birzha\Classes\ProductResource;
use DB;
use Carbon\Carbon;
use ToughDeveloper\ImageResizer\Classes\Image;

class ProductsAPIController extends Controller
{
	protected $Product;

    protected $helpers;

    public function __construct(Product $Product, Helpers $helpers)
    {
        parent::__construct();
        $this->Product    = $Product;
        $this->helpers          = $helpers;
    }
    
    
    
    public function searchProd(Request $request)
    {
        $data = $request->all();
        $validator = Validator::make($data, [
            'key' => 'required',
        ]);
        
        if($validator->fails()) {
            return $this->helpers->apiArrayResponseBuilder(400, 'fail', $validator->errors() );
        }
        //dd("sdf");
        $perPage = intval(input('custom_per_page')); // intval protects from injection

        try {
            $products = Product::where('keyword', 'like', "%".(string)$data["key"]."%")->orWhere('name', 'like', "%".$data["key"]."%")->orWhere('slug','LIKE','%'.$data["key"].'%')->with(['translations:locale,model_id,attribute_data',
                'images:attachment_id,attachment_type,disk_name,file_name',
                'vendor:id,name,email,type,logo,banner,shop_title,slogan,is_instagram,web2',
                'place',])->where('status', 'approved')->paginate(15);
                
            $products->map(function ($product) {
                   $image = new Image($product->images[0]->path);
                   $product->images[0]->compressed_image = $image->resize(510)->getCachedImagePath(true);
                   
                   return $product;
            });
                
           // foreach($products as $product) {
           ///    $image = new Image($product->images[0]->path);
           //    $product->images[0]->path = $image->resize(200,200)->getCachedImagePath(true);
           // }
            
           // dd($products[0]->images[0]);
              
        } catch (\Throwable $th) {
            return $this->helpers->apiArrayResponseBuilder(500, 'server error', ['message' => 'Something went wrong']);
        }

        return response()->json($products, 200);
    }
    

    public function index(){
        //dd("sdf");
        $sortOrderParam = strtolower(input('sort_order'));

        // protect from sql injection
        if($sortOrderParam != 'asc' && $sortOrderParam != 'desc') {
            $sortOrder = 'desc'; // by default
        } else {
            $sortOrder = $sortOrderParam;
        }

        $categoryId = intval(input('category_id')); // intval protects from injection
        $perPage = intval(input('custom_per_page')); // intval protects from injection
        $productId = intval(input('product_id')); // intval protects from injection
        $is_home = intval(input('is_home')); 
        $queryString = input('q');
        $locale = input('locale');
        
        $type = input('type');
        
        $sortPrice = input('price');
        $place =  input('place');
        
        
        $seller = input('seller_id');
        $categorySeller = input('seller_category_id');

        // $query = $this->Product::with('categories:id,name')
        $query = Product::with([
                'translations:locale,model_id,attribute_data',
                'images:attachment_id,attachment_type,disk_name,file_name',
                'vendor:id,name,email,type,logo,banner,shop_title,slogan,is_instagram,web2',
                'place',
            ])
            ->withCount(['comments as rating_avg' => function($query) {
                $query->select(DB::raw('avg(rating)'));
            }])
            ->approved();
            
            
            
            
        if($type){
            $query = $query->where("type", $type)->orderBy('ends_at', $sortOrder);
        }
            
         if($sortPrice) { // fetch offers by the category of the product
     
              $query = $query->orderBy('price', $sortPrice)->orderBy('ends_at', $sortOrder);
        }
        
        
        if($place) { // fetch offers by the category of the product
                 
            
              if($place == (0).$place){
                  
                  $allCity = City::where('primary_key', $place)->select("id")->get()->pluck('id')->toArray();
                  
                  $query = $query->where("place_id", $allCity)->orderBy('ends_at', $sortOrder);
                  
              }else{
                  
                  $query = $query->where('place_id', $place)->orderBy('ends_at', $sortOrder);
                  
              }
              
              
        }
        
        
        if($seller){
            
            $query = Product::with([
                'translations:locale,model_id,attribute_data',
                'images:attachment_id,attachment_type,disk_name,file_name',
                'vendor:id,name,email,type,logo,banner,shop_title,slogan,is_instagram,web2',
                'place',
            ])
            ->withCount(['comments as rating_avg' => function($query) {
                $query->select(DB::raw('avg(rating)'));
            }])
            ->where('vendor_id', $seller)
            ->approved()->orderBy('id', $sortOrder);
        }


        if($seller && $categorySeller) {
        
            $category = Category::find($categorySeller);
            $sellerProducts = Product::where("vendor_id", $seller);
            
            if($category) {
                
                if($categorySeller == 0){
                
                         $query = $sellerProducts->where('vendor_id', $seller)->with('categories:id,name')
                            ->with([
                                'translations:locale,model_id,attribute_data',
                                'images:attachment_id,attachment_type,disk_name,file_name',
                                'vendor:id,name,email,type,logo,banner,shop_title,slogan,is_instagram,web2',
                                'place',
                            ])->approved()->orderBy('id', $sortOrder);
                    
                }else{
                    
                         $query = $category->products()
                            ->with('categories:id,name')
                            ->with([
                                'translations:locale,model_id,attribute_data',
                                'images:attachment_id,attachment_type,disk_name,file_name',
                                'vendor:id,name,email,type,logo,banner,shop_title,slogan,is_instagram,web2',
                                'place',
                            ])
                            ->withCount(['comments as rating_avg' => function($query) {
                                $query->select(DB::raw('avg(rating)'));
                            }])
                            ->where('vendor_id', $seller)
                            ->approved()
                            ->orderBy('ends_at', $sortOrder);
                    
                    }
                
                
            } else {
                $query = null;
            }
        
        }

        
        if($categoryId) { // fetch offers by the category of the product
            $category = Category::find($categoryId);
            if($category) {
                
                $query = $category->products()
                            ->with('categories:id,name')
                            ->with([
                                'translations:locale,model_id,attribute_data',
                                'images:attachment_id,attachment_type,disk_name,file_name',
                                'vendor:id,name,email,type,logo,banner,shop_title,slogan,is_instagram,web2',
                                'place'
                            ])
                            ->withCount(['comments as rating_avg' => function($query) {
                                $query->select(DB::raw('avg(rating)'));
                            }])
                            ->approved();
                
                 if($place) { // fetch offers by the category of the product
     
                       if($place == (0).$place){
                  
                          $allCity = City::where('primary_key', $place)->select("id")->get()->pluck('id')->toArray();
                          
                          $query = $query->where("place_id", $allCity)->orderBy('ends_at', $sortOrder);
                          
                      }else{
                          
                          $query = $query->where('place_id', $place)->orderBy('ends_at', $sortOrder);
                          
                      }
                 }
                
                 if($sortPrice){
                     
                     $query = $query->orderBy('price', $sortPrice)->orderBy('ends_at', $sortOrder);
                 }
                
                
            } else {
                $query = null;
            }
        }
        
        if($is_home) { // fetch offers by the category of the product
     
          $query = $this->Product::with([
            'translations:locale,model_id,attribute_data',
            'images:attachment_id,attachment_type,disk_name,file_name',
            'place',
            'vendor:id,name,email,type,logo,banner,shop_title,slogan,is_instagram,web2'
            ])
            ->withCount(['comments as rating_avg' => function($query) {
                $query->select(DB::raw('avg(rating)'));
            }])
            ->where('is_home', 1)
            ->approved()
            ->orderBy('ends_at', $sortOrder);
        }
        

        if($productId) { // fetch offers with products in the same category

            $product = $this->Product::find($productId);

            if($product) {
                $category = $product->categories->first();

                $query = $category->products()
                    ->where('id','!=',$productId)
                    // ->with('categories:id,name')
                    ->with([
                        'translations:locale,model_id,attribute_data',
                        'images:attachment_id,attachment_type,disk_name,file_name',
                    ])
                    ->withCount(['comments as rating_avg' => function($query) {
                        $query->select(DB::raw('avg(rating)'));
                    }])
                    // ->approvedAndFreshEndDate()
                    ->approved()
                    ->orderBy('ends_at', $sortOrder);
            } else {
                $query = null;
            }
        }

        if($queryString && $locale) {
            $query = $this->Product::searched($locale, $queryString)
            ->with([
                'translations:locale,model_id,attribute_data',
                'images:attachment_id,attachment_type,disk_name,file_name',
            ])
            ->withCount(['comments as rating_avg' => function($query) {
                $query->select(DB::raw('avg(rating)'));
            }])
            ->orderBy('ends_at', $sortOrder);
        }
        
        
        $data = $query ? $query->orderBy('created_at', "DESC")->orderBy('id', "DESC")->paginate($perPage) : null;

        $data->map(function ($product) {
            
               $image = new Image($product->images[0]->path);
               $product->images[0]->compressed_image = $image->resize(510)->getCachedImagePath(true);
               
               return $product;
               
               //foreach($product->images as $compressImage){
               //    $image = new Image($compressImage->path);
               //    $compressImage->compressed_image = $image->resize([ 'quality' => 50])->getCachedImagePath(true);
               //}
               
        });
        
        return response()->json($data, 200);
    }

    public function show($id){
        
        $product = Product::find($id);
        
        $product->number_of_views++;
        $product->save();

        $data = $this->Product::with([
            'translations:locale,model_id,attribute_data',
            'images:id,attachment_id,attachment_type,disk_name,file_name',
            'vendor:id,name,surname,email,username,logo,banner,type,web2',
            'files', 'place', 'categories:id,name,slug,primary_key,icon'
        ])
        //->withCount('comments')->withAvg('comments', 'rating')
       ->withCount(['comments as rating_avg' => function($query) {
            $query->select(DB::raw('avg(rating)'));
        }])
        ->find($id);
        
        $data->main_path = 'https://gurlushyk.com.tm' . \Config::get('cms.storage.media.path');
        //$data->rating_avg = number_format((float)$data->rating_avg, 1, '.', '');;

        if ($data && $data->status == 'approved' /*&& $data->ends_at >= \Carbon\Carbon::now()*/){
            return response()->json($data, 200);
        } else {
            return $this->helpers->apiArrayResponseBuilder(404, 'not found', ['error' => 'Resource id=' . $id . ' could not be found']);
        }

    }

    // step1
    public function store(Request $request){
        $data = $request->all();
       //  dd($data);
        $rules = [
            //'name_ru' => 'required',
            'name_tm' => 'required',
            'price' => 'required|numeric',
            'place_id' => 'required',
            'description_tm' => 'required',
            //'description_ru' => 'required',
            'new_img' => 'array',
            'is_file' => 'required',
            // allowed only jpg & png files with size <= 1024
            'new_img.*' => 'mimes:jpg,png|max:1024',
            
            //'new_file.*' => 'max:9024',

            'category_id' => [
                'required',
                'exists:tps_birzha_categories,id',
                // validation for category status - it should be active
                function ($attribute, $value, $fail) {
                    $c = Category::find($value);
                    if($c) {
                        if($c->status != 1) $fail(":attribute is non-active!");
                    }
                }
            ],
            
            
            //'place_id' => 'required',

        ];

        $validator = $this->validateForm($data, $rules);
        if($validator->fails()) {
            return $this->helpers->apiArrayResponseBuilder(400, 'fail', $validator->errors() );
        }
        
           // validate if no old images and no new images
        if(!$request->has('new_img')) {
            return response()->json(ErrorResponseApi::translateErrorMessage('atleast_1_image'), 400);
        }

        // if new_img field is passed but empty
        if($request->has('new_img')) {
            $rules = [
                'new_img' => 'required'
            ];
            $validator = $this->validateForm($data, $rules);
            if($validator->fails()) {
                return $this->helpers->apiArrayResponseBuilder(400, 'fail', $validator->errors() );
            }
        }
        
        
          
         $category = Category::find($data['category_id']);

       
        $product = new $this->Product;
       

        $product->translateContext('tm');
        
        $product->name = $data['name_tm'];
        
        $product->translateContext('tm');

        $product->description = $data['description_tm'];
        
        $product->short_description = $data['short_description'];

        $product->slug = \Str::slug($data['name_tm'],'-');
        $product->status = 'new';
        
        $product->place_id = $data['place_id'];
        $product->price = $data['price'];
        $product->phone = $data['phone'];
        $product->stock = $data['stock'];
        
        $product->is_file_product = $data['is_file'];
        
        if($data['is_file'] == 1){
               // validate if no old images and no new images
            if(!$request->has('new_file')) {
                return response()->json(ErrorResponseApi::translateErrorMessage('atleast_1_file'), 400);
            }
    
            // if new_img field is passed but empty
            if($request->has('new_file')) {
                $rules = [
                    'new_file' => 'required'
                ];
                $validator = $this->validateForm($data, $rules);
                if($validator->fails()) {
                    return $this->helpers->apiArrayResponseBuilder(400, 'fail', $validator->errors() );
                }
            }
            
            
            try {
            
                foreach($data['new_file'] ?? [] as $key => $fileq) {
                   $product->files = $fileq;
                   $product->save();
                }
                
            } catch(\Throwable $e) {
              
                return $this->helpers->apiArrayResponseBuilder(500, 'server error', ['message' => 'something went wrong file']);
            }
            
        }

        $product->vendor_id = \JWTAuth::parseToken()->authenticate()->id;

        $product->ends_at = null; // if approved but date was expired
        
        
         try {
            
            foreach($data['new_img'] ?? [] as $key => $img) {
               $product->images = $img;
               $product->save();
            }
            
        } catch(\Throwable $e) {
          
            return $this->helpers->apiArrayResponseBuilder(500, 'server error', ['message' => 'qqqsomething went wrong']);
        }
        
           // product found, validation passed -> can fill product &save
       
        if(!isset($data['productForEditing'])) {
            // $product->created_at = Carbon::now('Asia/Ashgabat');
            $category->products()->save($product);
        } else {
            // detach from all other categories
            $product->categories()->detach();
            // attach to a new category
            $category->products()->save($product);
        }
        
        
        //$produt->save();
     

        return $this->helpers->apiArrayResponseBuilder(200, 'ok', ['product' => $product]);
    }

    public function update($id, Request $request){

        if(!$attachedProduct = $this->checkUserHasProduct($id)) {
            return $this->helpers->apiArrayResponseBuilder(404, 'not found', ['error' => "Resource id = {$id} could not be found"]);
        }

        $data = $request->all();
        
        $rules = [
            //'name_ru' => 'required',
            'name_tm' => 'required',
            'price' => 'required|numeric',
            'place_id' => 'required',
            'description_tm' => 'required',
            //'description_ru' => 'required',
            'new_img' => 'array',
            'is_file' => 'required',
            
            'old_img' => 'array',
            // allowed only jpg & png files with size <= 1024
            'new_img.*' => 'mimes:jpg,png|max:1024',
            
            //'new_file.*' => 'max:9024',

            'category_id' => [
                'required',
                'exists:tps_birzha_categories,id',
                // validation for category status - it should be active
                function ($attribute, $value, $fail) {
                    $c = Category::find($value);
                    if($c) {
                        if($c->status != 1) $fail(":attribute is non-active!");
                    }
                }
            ],
            
            
            //'place_id' => 'required',

        ];

        $validator = $this->validateForm($data, $rules);
        if($validator->fails()) {
            return $this->helpers->apiArrayResponseBuilder(400, 'fail', $validator->errors() );
        }
        
        if($data['is_file'] == 1){
               // validate if no old images and no new images
            if(!$request->has('new_file')) {
                return response()->json(ErrorResponseApi::translateErrorMessage('atleast_1_file'), 400);
            }
    
            // if new_img field is passed but empty
            if($request->has('new_file')) {
                $rules = [
                    'new_file' => 'required'
                ];
                $validator = $this->validateForm($data, $rules);
                if($validator->fails()) {
                    return $this->helpers->apiArrayResponseBuilder(400, 'fail', $validator->errors() );
                }
            }
            
            
            try {
            
                foreach($data['new_file'] ?? [] as $key => $fileq) {
                   $product->files = $fileq;
                   $product->save();
                }
                
            } catch(\Throwable $e) {
              
                return $this->helpers->apiArrayResponseBuilder(500, 'server error', ['message' => 'something went wrong file']);
            }
            
        }
        

        // validate if no old images and no new images
        if((!$request->has('new_img') && !$request->has('old_img'))) {
            return response()->json(ErrorResponseApi::translateErrorMessage('atleast_1_image'), 400);
        }

        // if new_img field is passed but empty
        if($request->has('new_img')) {
            $rules = [
                'new_img' => 'required'
            ];
            $validator = $this->validateForm($data, $rules);
            if($validator->fails()) {
                return $this->helpers->apiArrayResponseBuilder(400, 'fail', $validator->errors() );
            }
        }

        // if old_img field is passed but empty
        if($request->has('old_img')) {
            $rules = [
                'old_img' => 'required'
            ];
            $validator = $this->validateForm($data, $rules);
            if($validator->fails()) {
                return $this->helpers->apiArrayResponseBuilder(400, 'fail', $validator->errors() );
            }
        }

        // product found, validation passed -> can fill product &save
        try {
            $attachedProduct = $this->fillProduct($data,$attachedProduct);

            foreach($data['new_img'] ?? [] as $key => $img) {
                $attachedProduct->images = $img;
                $attachedProduct->save();
            }
        } catch(\Throwable $e) {
            return $this->helpers->apiArrayResponseBuilder(500, 'server error', ['message' => 'something went wrong']);
        }

        return $this->helpers->apiArrayResponseBuilder(200, 'ok', ['message' => 'updated successfully']);
    }
    
    
    public function checkUserHasProduct($id)
    {
        $currentUser = \JWTAuth::parseToken()->authenticate();

        return $currentUser->products->find($id);
    }
    
    
    public function updateStatus($id){

        if(!$product = $this->checkUserHasProduct($id)) {
            return $this->helpers->apiArrayResponseBuilder(404, 'not found', ['error' => "Resource id = {$id} could not be found"]);
        }


        try {
           
           if($product){
               
                
                if($product->status == "disabled"){
                        $product->status = "new";
                        $product->save();
                }else{
                    
                    $product->status = "disabled";
                    $product->save();
                
                }
            
            }

        } catch(\Throwable $e) {
            return $this->helpers->apiArrayResponseBuilder(500, 'server error', ['message' => 'something went wrong']);
        }

        return $this->helpers->apiArrayResponseBuilder(200, 'ok', ['message' => 'updated successfully']);
    }
    
    
     public function updateEndsAt($id){
         
        $currentDate = Carbon::now()->timezone('UTC +05:00');
        $currentDateFormat =  $currentDate->format('Y-m-d');

        if(!$product = $this->checkUserHasProduct($id)) {
            return $this->helpers->apiArrayResponseBuilder(404, 'not found', ['error' => "Resource id = {$id} could not be found"]);
        }


        try {
           
           if($product){
               
                $product->created_at = $currentDateFormat;
                $product->save();
        
            
            }

        } catch(\Throwable $e) {
            return $this->helpers->apiArrayResponseBuilder(500, 'server error', ['message' => 'something went wrong']);
        }

        return $this->helpers->apiArrayResponseBuilder(200, 'ok', ['message' => 'updated successfully']);
    }
    
    
    
    protected function fillProduct($data, $attachedProduct) {
        
        
        $attachedProduct->translateContext('tm');
        
        $attachedProduct->name = $data['name_tm'];
        
        $attachedProduct->translateContext('tm');

        $attachedProduct->description = $data['description_tm'];
        
        $attachedProduct->short_description = $data['short_description'];

        $attachedProduct->slug = \Str::slug($data['name_tm'],'-');
        
        $attachedProduct->status = 'new';
        
        $attachedProduct->place_id = $data['place_id'];
        
        $attachedProduct->price = $data['price'];
        
        $attachedProduct->phone = $data['phone'];
        
        $attachedProduct->stock = $data['stock'];
        
        $attachedProduct->is_file_product = $data['is_file'];
        
        $attachedProduct->save();

        return $attachedProduct;
    }

    /**
     * Delete my product
     */
    public function delete($id){

        if(!$product = $this->checkUserHasProduct($id)) {
            return $this->helpers->apiArrayResponseBuilder(404, 'not found', ['error' => "Resource id = {$id} could not be found"]);
        }

        /**
         * user can not delete product with status 'new'
         */
        if($product->status == 'new') {
            return $this->helpers->apiArrayResponseBuilder(404, 'not found', ['error' => 'Resource id=' . $id . ' could not be found']);
        }

        $product->images()->delete();
        $product->translations()->delete();
        $product->delete();

        return $this->helpers->apiArrayResponseBuilder(200, 'success', ['message' => 'Data has been deleted successfully']);
    }

    public function destroy($id){

        $this->Product->where('id',$id)->delete();

        return $this->helpers->apiArrayResponseBuilder(200, 'success', 'Data has been deleted successfully.');
    }

    public function imageDelete($id, $image_id)
    {
        if(!$product = $this->checkUserHasProduct($id)) {
            return $this->helpers->apiArrayResponseBuilder(404, 'not found', ['error' => "Resource id = {$id} could not be found"]);
        }

        try {
            $image = $product->images()->find($image_id);

            if(!$image) {
                return $this->helpers->apiArrayResponseBuilder(404, 'not found', ['error' => "Resource id = {$image_id} could not be found"]);
            }

            $image->delete();

        } catch(\Throwable $e) {
            return $this->helpers->apiArrayResponseBuilder(500, 'server error', ['message' => 'Something went wrong']);
        }

        return $this->helpers->apiArrayResponseBuilder(200, 'success', ['message' => 'Image deleted successfully']);
    }

    public function publish($id)
    {
        if(!$product = $this->checkUserHasProduct($id)) {
            return $this->helpers->apiArrayResponseBuilder(404, 'not found', ['error' => "Resource id = {$id} could not be found"]);
        }

        try {
            $balance = \JWTAuth::parseToken()->authenticate()->getBalance();

            if($balance - Settings::getValue('fee') < 0) {
                // ... message about not enough money
                return response()->json(ErrorResponseApi::translateErrorMessage('low_balance'), 300);
            } else {

                //save how much user payed because fee can be changed by admin tomorrow
                // if post is denied we get back payed fee, not admin's set fee
                $product->payed_fee_for_publ = Settings::getValue('fee');
                $product->status = 'new';

                if($product->save()) {
                    Event::fire('tps.product.received',[$product]);
                } else {
                    return $this->helpers->apiArrayResponseBuilder(500, 'server error', ['message' => 'Something went wrong']);
                }
            }
        } catch (\Throwable $th) {
            return $this->helpers->apiArrayResponseBuilder(500, 'server error', ['message' => 'Something went wrong']);
        }

        return $this->helpers->apiArrayResponseBuilder(200, 'ok', ['message' => 'published successfully']);
    }

    public static function getAfterFilters() {return [];}
    public static function getBeforeFilters() {return [];}
    public static function getMiddleware() {return [];}
    // public function callAction($method, $parameters=false) {
    //     return call_user_func_array(array($this, $method), $parameters);
    // }

    protected function validateForm($data, $rules)
    {
        return Validator::make($data, $rules);
    }

    

    public function myProducts()
    {
        //dd("sdf");
        $perPage = intval(input('custom_per_page')); // intval protects from injection

        try {
            $products = \JWTAuth::parseToken()->authenticate()
                ->products()
                ->with(['translations:locale,model_id,attribute_data',
                    'images:attachment_id,attachment_type,disk_name,file_name', 'place', 'files'])
                ->orderBy('updated_at', 'desc')
                ->paginate($perPage);

              
        } catch (\Throwable $th) {
            return $this->helpers->apiArrayResponseBuilder(500, 'server error', ['message' => 'Something went wrong']);
        }

        return response()->json($products, 200);
    }
    
    
    

    public function showMyProductById($id) {

        if(!$product = $this->checkUserHasProduct($id)) {
            return $this->helpers->apiArrayResponseBuilder(404, 'not found', ['error' => "Resource id = {$id} could not be found"]);
        } else {
            return $product;
        }
    }
    
    
    public function createFav($id){
        $favourite = Favourites::firstOrCreate([
                        "product_id" => $id,
                        "user_id" => \Auth::user()->id,
                     ]);
        return $this->helpers->apiArrayResponseBuilder(200, 'ok', ['message' => 'Added to wishlist']);
    }

   
}
