<?php
/**
 * File name: OrderAPIController.php
 * Last modified: 2020.05.31 at 19:34:40
 * Author: Milk App - Rishabh Rai
 * Copyright (c) 2020
 *
 */

namespace App\Http\Controllers\API;


use App\Events\OrderChangedEvent;
use App\Http\Controllers\Controller;

use App\Notifications\NewOrder;
use App\Notifications\StatusChangedOrder;
use App\Repositories\CartRepository;
use App\Repositories\NotificationRepository;
use App\Repositories\OrderRepository;
use App\Repositories\PaymentRepository;
use App\Repositories\UserRepository;
use App\Repositories\DeliveryAddressRepository;

use Braintree\Gateway;
use Flash;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;
use InfyOm\Generator\Criteria\LimitOffsetCriteria;
use Prettus\Repository\Criteria\RequestCriteria;
use Prettus\Repository\Exceptions\RepositoryException;
use Prettus\Validator\Exceptions\ValidatorException;
use Stripe\Token;
use App\Models\Coupon;
use App\Models\UserWallet;
use App\Models\DeliveryAddress;
use App\Models\Cart;
use App\Models\CardDetails;
use App\Models\Payment;
use App\Models\User;
use App\Models\CollectionProducts;
use App\Models\Order;
use App\Models\OrderComboProducts;
use App\Models\OrderProduct;
use App\Models\OrderProductsDelivery;
use App\Models\DriverWorkingAreas;
/**
 * Class OrderController
 * @package App\Http\Controllers\API
 */
class OrderAPIController extends Controller
{
    /** @var  OrderRepository */
    private $orderRepository;
    
    /** @var  CartRepository */
    private $cartRepository;
    /** @var  UserRepository */
    private $userRepository;
    /** @var  PaymentRepository */
    private $paymentRepository;
    /** @var  NotificationRepository */
    private $notificationRepository;

    /** @var  DeliveryAddressRepository */
    private $deliveryAddressRepository;
    private $currentDatetime;

    /**
     * OrderAPIController constructor.
     * @param OrderRepository $orderRepo
     * @param CartRepository $cartRepo
     * @param PaymentRepository $paymentRepo
     * @param NotificationRepository $notificationRepo
     * @param UserRepository $userRepository
     */

    protected $num_per_page = '10';

    public function __construct(OrderRepository $orderRepo, CartRepository $cartRepo, PaymentRepository $paymentRepo, NotificationRepository $notificationRepo, UserRepository $userRepository,DeliveryAddressRepository $deliveryAddressRepo)
    {
        $this->orderRepository = $orderRepo;
        $this->cartRepository = $cartRepo;
        $this->userRepository = $userRepository;
        $this->paymentRepository = $paymentRepo;
        $this->notificationRepository = $notificationRepo;
        $this->deliveryAddressRepository = $deliveryAddressRepo;
        config(['app.timezone' => setting('timezone')]);
        date_default_timezone_set(setting('timezone'));
        $this->currentDatetime = date('Y-m-d H:i:s');
    }

    public function index(Request $request)
    {
        try {
            $this->orderRepository->pushCriteria(new RequestCriteria($request));
            $this->orderRepository->pushCriteria(new LimitOffsetCriteria($request));
        } catch (RepositoryException $e) {
            Flash::error($e->getMessage());
        }
        $user = $this->userRepository->findByField('api_token', $request->input('api_token'))->first();
        if (!$user) {
            return $this->sendError('User not found', 401);
        }
        if ($user->hasRole('driver'))
        {
            $this->num_per_page = (isset($post['perpage']))?$post['perpage']:$this->num_per_page;
            $delivery_date = date("Y-m-d");

            if($request->input('history')==1){
                $resultObj = OrderProductsDelivery::where('delivery_date','<',date("Y-m-d",strtotime($delivery_date)))->where('driver_id',$user->id)->where('status',1)->with('order')->with('deliveryAddress')->with('orderStatus')->with('user')->groupBy('order_id')->paginate($this->num_per_page)->appends('perpage', $this->num_per_page);
            }else{
                $resultObj = OrderProductsDelivery::where('delivery_date',date("Y-m-d",strtotime($delivery_date)))->where('driver_id',$user->id)->where('status',1)->where('order_status_id','!=',5)->with('order')->with('deliveryAddress')->with('orderStatus')->with('user')->groupBy('order_id')->paginate($this->num_per_page)->appends('perpage', $this->num_per_page);
            }

            foreach ($resultObj as $row) {
                if($request->input('history')==1){
                    $order_id = OrderProductsDelivery::where('delivery_date','<=',date("Y-m-d",strtotime($delivery_date)))->where('status',1)->where('order_id',$row->order_id)->pluck('order_product_id');
                }else{
                    $order_id = OrderProductsDelivery::where('delivery_date','<=',date("Y-m-d",strtotime($delivery_date)))->where('order_status_id','!=',5)->where('status',1)->where('order_id',$row->order_id)->pluck('order_product_id');
                }
                $row->product_orders = OrderProduct::whereIn('id',$order_id)->with('combo')->with('product')->get();
            }            
            return $this->sendResponse($resultObj, 'Orders retrieved successfully');

        }else{
            $orders = Order::where('user_id',$user->id)->with('product_orders')->with('orderStatus')->with('deliveryAddress')->with('user')->get();
            return $this->sendResponse($orders, 'Orders retrieved successfully');    
        }
    }

    public function show(Request $request, $id)
    {
        /** @var Order $order */
        if (!empty($this->orderRepository)) {
            try {
                $this->orderRepository->pushCriteria(new RequestCriteria($request));
                $this->orderRepository->pushCriteria(new LimitOffsetCriteria($request));
            } catch (RepositoryException $e) {
                Flash::error($e->getMessage());
            }
            $user = $this->userRepository->findByField('api_token', $request->input('api_token'))->first();
            if (!$user) {
                return $this->sendError('User not found', 401);
            }
            
            if ($user->hasRole('driver'))
            {
                $order = $this->orderRepository->findWithoutFail($id);
                $orders = $order->toArray();
                return $this->sendResponse($orders, 'Order retrieved successfully');
            }
            else{
                $orders = Order::where('id',$id)->with('deliveryAddress')->with('product_orders')->with('orderStatus')->with('user')->first();
                return $this->sendResponse($orders, 'Order retrieved successfully');
            }
        }

        /* if (empty($orders)) {
            return $this->sendError('Order not found');
        } */
        if (empty($orders)) {
            return $this->sendError('Order not found');
        }
    }

    public function store(Request $request)
    {
        $input = $request->all();

        $subtotal = 0;
        $tax = 0;
        $delivery_fee = 0;
        $promotional_disount = 0;
        $final_amount = 0;

        $user = User::where('api_token',$input['api_token'])->first();
        if (empty($user)) {
            return $this->sendError('User not found', 401);
        }
        try {
            $orderPost = $request->only('delivery_address_id','area_id');

            //get Driver id
            if(isset($input['area_id'])){
                $driverObj = DriverWorkingAreas::where('working_area_id',$input['area_id'])->first();
                if($driverObj){
                    $orderPost['driver_id'] = $driverObj->id;
                }
            }

            $orderPost['user_id'] = $user->id;
            $orderPost['payment_method'] = $input['payment']['method'];
            $orderPost['created_at'] = date('Y-m-d H:i:s');
            $orderId = Order::insertGetId($orderPost);

            $order = $this->orderRepository->findByField('id', $orderId)->first();

            $cartData = Cart::where('user_id',$user->id)->get();
            
            foreach($cartData as $items){
                $inject = array(
                    'user_id'=>$user->id,
                    'order_id' => $order->id,
                    'quantity'=>$items->quantity,
                    'per_item_amount' => $items->per_item_amount,
                    'per_item_discount_amount'=>$items->per_item_discount_amount,
                    'per_delivery_amount' => $items->per_delivery_amount,
                    'per_delivery_delivery_fee' => $items->per_delivery_delivery_fee,
                    'per_delivery_tax' => $items->per_delivery_tax,
                    'total_delivery_amount' => $items->total_delivery_amount,
                    'no_of_delivery'=>$items->no_of_delivery,
                    'order_frequency'=>$items->order_frequency,
                    'days'=>$items->days,
                    'combo_id' => $items->combo_id,
                    'product_id' => $items->product_id,
                    'order_status_id'=>1,
                    'start_date'=>date('Y-m-d',strtotime($items->start_date)),
                    'end_date'=>date('Y-m-d',strtotime($items->end_date)),
                    'created_at'=>date('Y-m-d H:i:s')
                );                
                $orderitemId = OrderProduct::insertGetId($inject);

                if($items->combo_id!=0){
                    $collection = CollectionProducts::where('collection_id',$items->combo_id)->get();
                    foreach($collection as $collect){
                        $orderPro = array(
                            'order_id' => $orderId,
                            'product_id' => $collect->product_id,
                            'order_product_id'=> $orderitemId,
                            'quantity' => 1,
                            'created_at'=>date('Y-m-d H:i:s')
                        );
                        OrderComboProducts::insertGetId($orderPro);
                    }
                }

                $delivery_dates = explode(",",$items->delivery_dates);
                foreach ($delivery_dates as $r) {
                    $delivery = array(
                        'area_id' => $order->area_id,
                        'delivery_address_id' => $order->delivery_address_id,
                        'driver_id' => $order->driver_id,
                        'user_id' => $user->id,
                        'order_id' => $orderId,
                        'combo_id' => $items->combo_id,
                        'product_id' => $items->product_id,
                        'order_product_id'=> $orderitemId,
                        'delivery_date' => date("Y-m-d",strtotime($r)),
                        'order_status_id' => 1,
                        'status' => 1,
                        'created_at'=>date('Y-m-d H:i:s')
                    );
                    OrderProductsDelivery::insert($delivery);    
                }
                $subtotal = $subtotal + $items->total_delivery_amount;
            }

            $orderPostData['subtotal'] = round($subtotal,2);
            $orderPostData['delivery_fee'] = ($orderPostData['subtotal']<setting('minimum_order_value'))?setting('shipping_charge'):0;
            $orderPostData['tax'] = round((($orderPostData['subtotal'] * setting('default_tax')) / 100),2);
            $orderPostData['tax'] = round($orderPostData['tax'],2);
            $orderPostData['final_amount'] = round(($orderPostData['subtotal'] + $orderPostData['delivery_fee'] + $orderPostData['tax']),2);
            $orderPostData['final_amount'] = $orderPostData['final_amount'];
            $orderPostData['updated_at'] = $this->currentDatetime;

            $total_wallet = UserWallet::getWalletbalance($user->id);
            if($total_wallet<$orderPostData['final_amount']){
                OrderProductsDelivery::where('order_id',$orderId)->delete();
                OrderComboProducts::where('order_id',$orderId)->delete();
                OrderProduct::where('order_id',$orderId)->delete();
                Order::where('id',$orderId)->delete();
                return $this->sendError("You don't have sufficient wallet amount to purchase the order", 401);
            }else{
                Order::where('id',$order->id)->update($orderPostData);
                $wallet = UserWallet::create([
                    "user_id" => $user->id,
                    "type" => "debit",
                    "amount" => "-".$orderPostData['final_amount'],
                    "order_id" => $order->id,
                    "description" => trans("lang.payment_order_done"),
                ]);
                $this->cartRepository->deleteWhere(['user_id' => $order->user_id]);
            }
        } catch (ValidatorException $e) {
            return $this->sendError($e->getMessage());
        }
        $orders = Order::where('id',$order->id)->with('deliveryAddress')->with('product_orders')->with('orderStatus')->with('user')->first();
        return $this->sendResponse($orders, __('lang.saved_successfully', ['operator' => __('Order')]));
    }
    
    public function statusUpdate($id, Request $request)
    {
        $oldOrder = $this->orderRepository->findWithoutFail($id);

        if (empty($oldOrder)) {
            return $this->sendError('Order not found');
        }

        $oldStatus = ($oldOrder->payment)?$oldOrder->payment->status:'';

        $input = $request->all();
        $delivery_date = date("Y-m-d");

        try {
            $orderPost = array(
                'order_status_id' => $input['order_status_id']
            );
            OrderProductsDelivery::where('order_id',$id)->where('delivery_date',date("Y-m-d",strtotime($delivery_date)))->update($orderPost);


            if($input['order_status_id']==6){
                $this->calculateCancelProcess();
            }

            $user = $this->userRepository->where('id',$oldOrder->user_id)->first();
            if($user){
                if($user->device_token!=null){
                    $key = "AAAAWQm8xzI:APA91bEicbIHzGqQa7qASAwiNF5qP01rD02HYDR-FcSQ-elL3meoVRPpd7H8aOIrYwNWBCq3pCvwsLoG7Nck8o6ycocpGiTJbmzRk1jhZXPSQ0R_uVyV3jt_7fPIG2JIEBu9EbSnp942";
                    $title = 'Order Status Changed';
                    $msg = 'Order Status Changed #'.$oldOrder->id.' '.$oldOrder->orderStatus->status;
                    sendNotification($user->device_token,$msg,$title,$key);
                }
            }

            event(new OrderChangedEvent($oldStatus, $oldOrder));

            if (setting('enable_notifications', false)) {
                if (isset($input['order_status_id']) && $input['order_status_id'] != $oldOrder->order_status_id) {
                    Notification::send([$oldOrder->user], new StatusChangedOrder($oldOrder));
                }
            }
        } catch (ValidatorException $e) {
            return $this->sendError($e->getMessage());
        }

        return $this->sendResponse([], __('lang.saved_successfully', ['operator' => __('Order')]));
    }

    public function cancelOrder(Request $request)
    {
        $input = $request->all();
        $oldOrder = $this->orderRepository->findWithoutFail($input['id']);
        if (empty($oldOrder)) {
            return $this->sendError('Order not found');
        }
        $oldStatus = $oldOrder->payment->status;
        $input['order_status_id'] = 6; 
        try {
            $orderPost = array(
                'order_status_id' => $input['order_status_id'],
                'updated_at'=>$this->currentDatetime
            );
            $order = $this->orderRepository->update($orderPost,$input['id']);

            $this->calculateCancelProcess();
            
            if (setting('enable_notifications', false)) {
                if (isset($input['order_status_id']) && $input['order_status_id'] != $oldOrder->order_status_id) {
                    Notification::send([$order->user], new StatusChangedOrder($order));
                }
            }

        } catch (ValidatorException $e) {
            return $this->sendError($e->getMessage());
        }

        return $this->sendResponse($order->toArray(), __('lang.order_canceled', ['operator' => __('Order')]));
    }

    private function calculateCancelProcess()
    {
        // code...
    }

    public function cancelOrderProduct(Request $request)
    {
        return "Please contact to admin";exit;
        $input = $request->all();
        try {
            if(!empty($input)){
                $oldOrder = $this->orderRepository->findWithoutFail($input['order_id']);
                $product_order = OrderProduct::where('order_id',$input['order_id'])->get();

                $oldStatus = $oldOrder->payment->status;

                $input['order_status_id'] = 6; 

                $user = User::where('api_token',$input['api_token'])->first();
                if($input['type']=='combo'){
                    $orderProduct = OrderProduct::where('order_id',$input['order_id'])->where('combo_id',$input['item_id'])->first();
                }else{
                    $orderProduct = OrderProduct::where('id',$input['item_id'])->first();
                }

                if($orderProduct){
                    if($input['type']=='combo'){
                        OrderProduct::where('order_id',$input['order_id'])->where('combo_id',$input['item_id'])->delete();
                    }else{
                        if($input['type']=='once'){
                            OrderProduct::where('id',$input['item_id'])->delete();
                        }else{
                            OrderProduct::where('id',$input['item_id'])->delete();
                        }
                    }
                    $product_order = OrderProduct::where('order_id',$input['order_id'])->get();
                    if(count($product_order)==0){
                        $orderPost = array(
                            'order_status_id' => $input['order_status_id'],
                            'updated_at'=>$this->currentDatetime
                        );
                        $order = $this->orderRepository->update($orderPost,$input['order_id']);
                    } 
                }else{
                    return $this->sendError("Product is not added in this order.");
                }                               
            }
        } catch (ValidatorException $e) {
            return $this->sendError($e->getMessage());
        }
        return $this->sendResponse([], __('lang.cancel', ['operator' => __('Order')]));
    }

    public function getMyDeliveries(Request $request)
    {
        $input = $request->all();
        $user = $this->userRepository->findByField('api_token', $request->input('api_token'))->first();
        if (!$user) {
            return $this->sendError('User not found', 401);
        }
        $delivery_date = (isset($input['order_date']))?date("Y-m-d",strtotime($input['order_date'])):date("Y-m-d");
        $result = OrderProductsDelivery::where('user_id',$user->id)->where('delivery_date',date("Y-m-d",strtotime($delivery_date)))->with('order')->with('user')->with('product_orders')->with('orderStatus')->get();
        return $this->sendResponse($result, "Record found");
    }

    public function getMyAllDeliveries(Request $request)
    {
        $input = $request->all();
        $user = $this->userRepository->findByField('api_token', $request->input('api_token'))->first();
        if (!$user) {
            return $this->sendError('User not found', 401);
        }


        $delivered_products = OrderProductsDelivery::where('user_id',$user->id)->groupBy('delivery_date')->orderBy('delivery_date','ASC')->get();
        $AllDeliveryDates = array();
        foreach ($delivered_products as $delivered) {
            $temp = array(
                'date' => $delivered->delivery_date,
                'data' => OrderProductsDelivery::where('user_id',$user->id)->where('delivery_date',$delivered->delivery_date)->with('order')->with('user')->with('product_orders')->with('orderStatus')->get()
            );
            array_push($AllDeliveryDates,$temp);
        }
        return $this->sendResponse($AllDeliveryDates, "Record found");
    }
}
