<?php

namespace App\Http\Controllers\Web;

use App\Coupon;
use App\Evaluate;
use App\Http\Controllers\Controller;
use App\Http\Requests\EvaluateRequest;
use App\Order;
use App\Product;
use App\ProductBlock;
use App\ProductOrder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Validator;
use Illuminate\View\View;

class ProductController extends Controller
{
    private $view = 'web.products.';

    /**
     * Show the application dashboard.
     * @return View
     */
    public function index(): View
    {
        $products = [];
        if (request()->query('search')){
            $productName = request()->query('search');
            $products = Product::withDescription(null, $productName);
        }
//        else {
//            $products = Product::withDescription();
//        }

        return view($this->view.'index', compact('products'));
    }

    public function show(Product $product)
    {

        if (!$product->status){
            return redirect()->route('home');
        }

        $products = Product::withDescription(null, null, $product->id);

        $productBlocks = ProductBlock::withDescription($product->id);
        $comments = Evaluate::withoutTrashed()
                ->where('evaluates.status', 1)->where('product_id', $product->id)
                ->join('users', 'users.id', 'evaluates.user_id')
                ->select(['evaluates.*', 'users.photo as user_photo', 'users.name as user_name'])
                ->cursor() ?? [];

        $purchaseList = [];
        if (Auth::check()){
            $user = Auth::user();
            $purchaseList = Order::getUserOrder($user->id, 'complete')->pluck('main_prod_id')->toArray();
        }


        return view($this->view.'show', compact('products', 'productBlocks', 'purchaseList', 'comments'));

    }

    public function productEvaluate(EvaluateRequest $request)
    {

        if (! Auth::check()){
            return response()->json(['errors' => __('products.pleas_login')]);
        }

        $product = Product::find($request->product_id);
        $user = Auth::user();

        $purchaseList = Order::getUserOrder($user->id, 'complete')->pluck('main_prod_id')->toArray();

        if (!in_array($request->product_id, $purchaseList)){
            return response()->json(['errors' => __('products.not_in_shipping_list_or_not_complete')]);
        }


        $evaluate = Evaluate::where('product_id', $product->id)->where('user_id', $user->id)->first();

        if ($evaluate){
            $evaluate->forceDelete();
        }

        Evaluate::create([
            'comment' => $request->comment,
            'evaluate' => $request->evaluate,
            'user_id' => $user->id,
            'product_id' => $request->product_id,
        ]);

        return response()->json(['message' => __('products.comment_successfully')]);

    }

    public function cart()
    {
        $calcCart = $this->calcCart();

        if ($calcCart['errors']){
            return redirect()->home()->with('alert_pop_up', $calcCart['errors']);
        }

        $carts = $calcCart['carts'];
        $total = $calcCart['total'];
        $addedValue = $calcCart['addedValue'];
        $shippingValue = $calcCart['shippingValue'];
        $totalWithAddedAndShippingValue = $calcCart['totalWithAddedAndShippingValue'];
        $totalAddedValue = $calcCart['totalAddedValue'];
        return view($this->view.'cart', compact(
            'carts',
            'total',
            'addedValue',
            'shippingValue',
            'totalWithAddedAndShippingValue',
            'totalAddedValue'
        ));
    }

    public function addToCart(Request $request, Product $product)
    {
        if (request()->ajax()){
            if (!Auth::check()){
                return response()->json(['errors' => __('products.pleas_login_to_add_cart')]);
            }

            $user = Auth::user();

            if ($user->role != 'user'){
                return response()->json(['errors' => __('products.member_not_allowed_cart')]);
            }

            if (!$product->status){
                return response()->json(['errors' => __('products.product_not_available_now')]);
            }

            $validation = Validator::make($request->all(), [
                'amount' => 'required|not_in:0|gt:0',
                'color' => 'required'
            ], [], [
                'amount' => __('products.amount'),
                'color' => __('products.colors'),
            ]);

            if ($validation->fails()){
                return ['errors' => $validation->errors()->first()];
            }

            $productColorsWithAmount = $product->colors[$request->color]; // [color_hash=>color_amount]
            if ($productColorsWithAmount == 0 ){
                return ['errors' => __('products.product_out_of_stock')];
            }
            if ($productColorsWithAmount < $request->amount){
                return ['errors' => __('products.product_not_enough')];
            }


            $hasCart = Order::where('orders.user_id', $user->id)
                ->where('orders.status', 'cart_mode')
                ->first();

            $addedValue = 0;
            if (array_key_exists('added_value', settings()) && settings('added_value') && array_key_exists('show_added_value', settings()) && settings('show_added_value')){
                $addedValue = settings('added_value');
            }
            $shippingValue = array_key_exists('shipping_value', settings()) ? settings('shipping_value') : 15; // shipping value by SAR no percentage

            if ($hasCart){
                // check if product in product list or not
                $productFound = ProductOrder::where('order_id', $hasCart->id)
                    ->where('product_id', $product->id)
                    ->where('color', $request->color)->first();
                $data = [
                    'order_id' => $hasCart->id,
                    'product_id' => $product->id,
                    'amount' => $request->amount,
                    'color' => $request->color,
                    'price' => $product->discount ?? $product->price
                ];

                if ($productFound){
                    $productFound->update($data); // update product order if found
                } else {
                    ProductOrder::create($data); // create product order if not found
                }

                if ($hasCart->coupon_id){
                    $coupon = Coupon::where('id', $hasCart->coupon_id)->first();
                    if (!$coupon){
                        return ['errors' => __('products.invalid_coupon')];
                    }
                    $request['coupon'] = $coupon->code;
                    $checkCoupon = $this->checkCoupon($request);
                    if ($checkCoupon['errors']){
                        return $checkCoupon;
                    }

                    $checkCoupon = $this->checkCoupon($request);
                    $hasCart->update(
                        [
                            'order_discount' => $checkCoupon['discount'],
                            'order_total' => $checkCoupon['totalWithAddedAndShippingValue'],
                            'net_total' => $checkCoupon['total'],
                        ]
                    );

                } else {
                    $order_total = [];
                    $net_total = [];
                    $productOrders = $hasCart->productOrder;
                    foreach ($productOrders as $productOrder) {
                        $netTotal = $productOrder->amount*$productOrder->price;
                        $net_total[] = $netTotal;
                        $order_total[] = $netTotal+(($netTotal*$addedValue)/100);
                    }
                    $hasCart->update(
                        [
                            'order_discount' => null,
                            'order_total' => array_sum($order_total)+$shippingValue,
                            'net_total' => array_sum($net_total),
                        ]
                    );
                }

                return response()->json(['message' => __('products.add_cart_successfully')]);

            } else {
                // If user have not any cart then create it
                $order = Order::create([
                    'user_id' => $user->id,
                    'status' => 'cart_mode',
                ]);

                ProductOrder::create([
                    'order_id' => $order->id,
                    'product_id' => $product->id,
                    'amount' => $request->amount,
                    'color' => $request->color,
                    'price' => $product->discount ?? $product->price
                ]);

                $carts = $this->calcCart();
                $totalWithAddedAndShippingValue = $carts['totalWithAddedAndShippingValue'];
                $total = $carts['total'];

                $order->update([
                    'order_total' => $totalWithAddedAndShippingValue,
                    'net_total' => $total,
                    'order_discount' => null,
                    'coupon_id' => null,
                ]);

                return response()->json(['message' => __('products.add_cart_successfully')]);
            }

        }

    }

    public function addToCartForGuest(Request $request, Product $product)
    {
        if (!$product->status){
            return response()->json(['errors' => __('products.product_not_available_now')]);
        }

        $validation = Validator::make($request->all(), [
            'amount' => 'required|not_in:0|gt:0',
            'color' => 'required'
        ], [], [
            'amount' => __('products.amount'),
            'color' => __('products.colors'),
        ]);

        if ($validation->fails()){
            return ['errors' => $validation->errors()->first()];
        }

        $productColorsWithAmount = $product->colors[$request->color];
        if ($productColorsWithAmount == 0 ){
            return ['errors' => __('products.product_out_of_stock')];
        }
        if ($productColorsWithAmount < $request->amount){
            return ['errors' => __('products.product_not_enough')];
        }

        $addedValue = 0;
        if (array_key_exists('added_value', settings()) && settings('added_value') && array_key_exists('show_added_value', settings()) && settings('show_added_value')){
            $addedValue = settings('added_value');
        }

        $net_total = [];
        $order_total = [];
        $orderProducts = [];
        $productCount = 0;

        $oldCart = Session::get('cart_mode');
        if ($oldCart){
            $oldCart['products'][$product->id.'_'.$request->color] = [
                'product_id' => $product->id,
                'price' => $product->discount ?? $product->price,
                'amount' => $request->amount,
                'color' => $request->color,
            ];

            foreach ($oldCart['products'] as $productId => $productDetails) {
                $netTotal = $productDetails['amount']*$productDetails['price'];
                $net_total[] = $netTotal;
                $order_total[] = $netTotal+(($netTotal*$addedValue)/100);
            }

            $cartMode = [
                'order_total' => array_sum($order_total),
                'net_total' => array_sum($net_total),
                'products' => $oldCart['products'],
            ];

            $productCount = count($oldCart['products']);

            Session::put(['cart_mode' => $cartMode]);
        } else {
            $orderProducts[$product->id.'_'.$request->color] = [
                'product_id' => $product->id,
                'price' => $product->discount ?? $product->price,
                'amount' => $request->amount,
                'color' => $request->color,
            ];

            $netTotal = $request->amount*($product->discount ?? $product->price);
            $net_total[] = $netTotal;
            $order_total[] = $netTotal+(($netTotal*$addedValue)/100);

            $cartMode = [
                'order_total' => array_sum($order_total),
                'net_total' => array_sum($net_total),
                'products' => $orderProducts,
            ];

            $productCount = 1;

            Session::put(['cart_mode' => $cartMode]);
        }

        return response()->json(['cart_guest' => __('products.add_cart_successfully'), 'counter' => $productCount]);
    }

    public function changeAmount(Request $request)
    {
        $user = Auth::user();
        $carts = Order::getUserOrder($user->id, 'cart_mode');
        $productOrderIds = $carts->pluck('product_id')->toArray();

        if (!in_array($request->product_id, $productOrderIds)){
            return response()->json(['errors' => __('products.product_not_found_in_cart')]);
        }

        if ($request->coupon){
            $checkCoupon = $this->checkCoupon($request);
            if ($checkCoupon['errors']){
                return $checkCoupon;
            }
        }

        $productOrder = ProductOrder::where('id', $request->product_id)
            ->where('order_id', $carts->first()->id)->first();

        $productColorsWithAmount = $productOrder->product->colors[$productOrder->color]; // $productOrder->product->amount

        if ($request->amount_plus){
            if ($productColorsWithAmount == 0 ){
                return response()->json(['errors' => __('products.product_out_of_stock')]);
            }
            if ($productColorsWithAmount < $productOrder->amount+1){
                return response()->json(['errors' => __('products.product_not_enough')]);
            }
            $productOrder->update(['amount' => $productOrder->amount+1]);
        }
        if ($request->amount_minus){
            if ($productOrder->amount == 1){
                return response()->json(['errors' => __('products.product_amount_less_than')]);
            }
            if ($productColorsWithAmount == 0 ){
                return response()->json(['errors' => __('products.product_out_of_stock')]);
            }
            if ($productColorsWithAmount < $productOrder->amount-1){
                return response()->json(['errors' => __('products.product_not_enough')]);
            }
            $productOrder->update(['amount' => $productOrder->amount-1]);
        }

        // calc total depend on coupon if found
        if ($request->coupon){
            $checkCoupon = $this->checkCoupon($request);
            $checkCoupon['amount'] = $productOrder->amount;
            $checkCoupon['item_price'] = $productOrder->amount*$productOrder->price;
            $productOrder->order()->update([
                'order_total' => $checkCoupon['totalWithAddedAndShippingValue'],
                'net_total' => $checkCoupon['total'],
                'order_discount' => $checkCoupon['discount'],
                'coupon_id' => $checkCoupon['coupon']->id,
            ]);
            return $checkCoupon;
        }

        // calc total if not coupon
        $carts = $this->calcCart();
        $total = $carts['total'];
        $addedValue = $carts['addedValue'];
        $shippingValue = $carts['shippingValue'];
        $totalAddedValue = $carts['totalAddedValue'];
        $totalWithAddedAndShippingValue = $carts['totalWithAddedAndShippingValue'];

        $productOrder->order()->update([
            'order_total' => $totalWithAddedAndShippingValue,
            'net_total' => $total,
            'order_discount' => null,
            'coupon_id' => null,
        ]);

        return [
            'item_price' => $productOrder->amount*$productOrder->price,
            'amount' => $productOrder->amount,
            'total' => $total,
            'addedValue' => $addedValue,
            'shippingValue' => $shippingValue,
            'totalAddedValue' => $totalAddedValue,
            'totalWithAddedAndShippingValue' => $totalWithAddedAndShippingValue,
        ];

    }

    public function delete(Request $request)
    {
        $user = Auth::user();
        $carts = Order::getUserOrder($user->id, 'cart_mode');
        $cart = $carts->first();
        $productOrderIds = $carts->pluck('product_id')->toArray();

        if (!in_array($request->product_id, $productOrderIds)){
            return response()->json(['errors' => __('products.product_not_found_in_cart')]);
        }

        if ($request->coupon || $cart->coupon_id){
            $coupon = Coupon::find($cart->coupon_id);
            if ($coupon){
                $request['coupon'] = $coupon->code;
            }
            $checkCoupon = $this->checkCoupon($request);
            if ($checkCoupon['errors']){
                return $checkCoupon;
            }
        }

        $productOrder = ProductOrder::where('id', $request->product_id)->where('order_id', $carts->first()->id)->delete();

        if (! $productOrder) {
            return response()->json(['message' => __('products.not_in_shipping_list')]);
        }

        // calc total depend on coupon if found
        if ($request->coupon || $cart->coupon_id){
            $checkCoupon = $this->checkCoupon($request);
            if (!count($checkCoupon['carts'])){
                return ['carts' => false];
            }
            $cart = $checkCoupon['carts']->first();
            $cart->update([
                'order_total' => $checkCoupon['totalWithAddedAndShippingValue'],
                'net_total' => $checkCoupon['total'],
                'order_discount' => $checkCoupon['discount'],
                'coupon_id' => $checkCoupon['coupon']->id,
            ]);
            return $checkCoupon;
        }

        // calc total if not coupon
        $calcCart = $this->calcCart();
        $carts = $calcCart['carts'];
        $total = $calcCart['total'];
        $addedValue = $calcCart['addedValue'];
        $shippingValue = $calcCart['shippingValue'];
        $totalAddedValue = $calcCart['totalAddedValue'];
        $totalWithAddedAndShippingValue = $calcCart['totalWithAddedAndShippingValue'];

        if (!count($carts)){
            $cart->update(
                [
                    'order_total' => null,
                    'net_total' => null,
                    'order_discount' => null,
                    'coupon_id' => null,
                ]
            );
            return ['carts' => false];
        }

        $cart->update([
            'order_total' => $totalWithAddedAndShippingValue,
            'net_total' => $total,
            'order_discount' => null,
            'coupon_id' => null,
        ]);

        return [
            'total' => $total,
            'addedValue' => $addedValue,
            'shippingValue' => $shippingValue,
            'totalAddedValue' => $totalAddedValue,
            'totalWithAddedAndShippingValue' => $totalWithAddedAndShippingValue,
            'cart_count' => count($carts),
        ];

    }

    public function payNow(Request $request)
    {
        if ($request->ajax()){

            // if use coupon
            if ($request->coupon){
                $checkCoupon = $this->checkCoupon($request);
                if ($checkCoupon['errors']){
                    return $checkCoupon;
                }

                $cart = $checkCoupon['carts']->first();

                $cart->update([
                    'coupon_id' => $checkCoupon['coupon']->id,
                    'order_total' => $checkCoupon['totalWithAddedAndShippingValue'],
                    'order_discount' => $checkCoupon['discount'],
                    'net_total' => $checkCoupon['total'],

                ]);

                return response()->json(['url' => route('product.completePay')]);
            }

            // if not use coupon
            $carts = $this->calcCart();
            $cart = $carts['carts']->first();

            $cart->update([
                'order_total' => $carts['totalWithAddedAndShippingValue'],
                'net_total' => $carts['total'],
                'coupon_id' => null,
                'order_discount' => null,
            ]);

            return response()->json(['url' => route('product.checkAddress')]);
//            return response()->json(['url' => route('product.completePay')]);
        }
    }

    public function checkAddress()
    {
        $user = Auth::user();
        return view($this->view.'check_address', compact('user'));
    }

    public function checkAddressAndRedirectToCompletePay(Request $request)
    {
        if ($request->ajax()){
            $user = Auth::user();
            $validation = Validator::make($request->all(),
                ['address' => 'required|max:50'],[],['address' => __('members.address')]);
            if ($validation->fails()){
                return response()->json(['errors' => $validation->errors()->first()]);
            }

            $user->update(['address' => $request->address]);

            return response()->json(['url' => route('product.completePay')]);
        }
    }

    public function completePay(Request $request)
    {
        $calcCart = $this->calcCart();
        if ($calcCart['errors']){
            return redirect()->home()->with('alert_pop_up', $calcCart['errors']);
        }

        $carts = $calcCart['carts'];

        if (!count($carts)){
            return redirect()->route('home');
        }

        $cart = $carts->first();

        if ($cart->coupon_id){
            $coupon = Coupon::find($cart->coupon_id);
            $request['coupon'] = $coupon->code;
            $checkCoupon = $this->checkCoupon($request);
            if ($checkCoupon['errors']){
                return redirect()->route('home')->with('alert_pop_up', $checkCoupon['errors']);
            }

            $cart = $checkCoupon['carts']->first();

            $cart->update([
                'coupon_id' => $checkCoupon['coupon']->id,
                'order_total' => $checkCoupon['totalWithAddedAndShippingValue'],
                'order_discount' => $checkCoupon['discount'],
                'net_total' => $checkCoupon['total'],

            ]);
        } else {
            $cart->update([
                'coupon_id' => null,
                'order_discount' => null,
                'order_total' => $calcCart['totalWithAddedAndShippingValue'],
                'net_total' => $calcCart['total'],

            ]);
        }


        $total = $calcCart['total'];
        $addedValue = $calcCart['addedValue'];
        $shippingValue = $calcCart['shippingValue'];
        $totalWithAddedAndShippingValue = $calcCart['totalWithAddedAndShippingValue'];
        $totalAddedValue = $calcCart['totalAddedValue'];

        $order = $carts->first();
        $couponCode = null;
        if ($order->coupon_id){
            $coupon = Coupon::where('id', $order->coupon_id)->first();
            if ($coupon){
                $couponCode = $coupon->code;
            }
        }
        $addedTax = (($total-$order->order_discount)*$addedValue)/100;

        return view($this->view.'complete_pay', compact(
            'carts',
            'order',
            'couponCode',
            'total',
            'addedValue',
            'addedTax',
            'shippingValue',
            'totalWithAddedAndShippingValue',
            'totalAddedValue'
        ));
    }

    public function checkCoupon(Request $request)
    {
        $validation = Validator::make($request->all(), [
            'coupon' => 'required|exists:coupons,code'
        ], [
            'coupon.exists' => __('products.invalid_coupon')
        ], [
            'coupon' =>  __('products.coupon')
        ]);

        if ($validation->fails()){
            return ['errors' => $validation->errors()->first()];
        }

        $coupon = Coupon::where('code', $request->coupon)->first();

        if (!$coupon){
            return ['errors' => __('products.invalid_coupon')];
        }

        if ($coupon->status == 0){
            return ['errors' => __('products.invalid_coupon')];
        }

        if ($coupon->used_count >= $coupon->available_users){
            return ['errors' => __('products.invalid_coupon')];
        }

        if ($coupon->start_date > date('Y-m-d')){
            return ['errors' => __('products.coupon_not_allow_before_date') . $coupon->start_date];
        }

        if ($coupon->end_date < date('Y-m-d')){
            return ['errors' => __('products.invalid_coupon')];
        }

        $calcCart = $this->calcCart();
        $addedValue = $calcCart['addedValue'];
        $shippingValue = $calcCart['shippingValue'];
        $total = $calcCart['total'];
        $carts = $calcCart['carts'];
        $discount = ($total*$coupon->discount)/100;
//        $total = $total-$discount;
        $totalAddedValue = (($total-$discount)*$addedValue)/100; // calc added value after minus coupon discount
        $totalWithAddedAndShippingValue = ($total+$totalAddedValue+$shippingValue)-$discount;

        return [
            'errors' => false,
            'carts' => $carts,
            'cart_count' => count($carts),
            'coupon' => $coupon,
            'total' => $total,
            'discount' => $discount,
            'addedValue' => $addedValue,
            'shippingValue' => $shippingValue,
            'totalAddedValue' => $totalAddedValue,
            'totalWithAddedAndShippingValue' => $totalWithAddedAndShippingValue,
        ];

    }

    public function calcCart()
    {
        $user = Auth::user();
        $carts = Order::getUserOrder($user->id, 'cart_mode');
        $total = [];
        foreach ($carts as $cart) {
            $product = Product::where('id', $cart->main_prod_id)->first();
            $productColorsWithAmount = $product->colors[$cart->color]; // $product->amount

            if ($productColorsWithAmount == 0 ){
                return ['errors' => __('products.product_out_of_stock')];
            }
            if ($productColorsWithAmount < $cart->amount){
                return ['errors' => __('products.product_not_enough')];
            }

            if ($cart->discount){
                $total[] = $cart->discount*$cart->amount;
            } else {
                $total[] = $cart->product_price*$cart->amount;
            }
        }

        $total = array_sum($total);

        $addedValue = 0;
        if (array_key_exists('added_value', settings()) && settings('added_value') && array_key_exists('show_added_value', settings()) && settings('show_added_value')){
            $addedValue = settings('added_value');
        }
        $shippingValue = array_key_exists('shipping_value', settings()) ? settings('shipping_value') : 15; // shipping value by SAR no percentage
        $totalAddedValue = ($total*$addedValue)/100;
        $totalWithAddedAndShippingValue = $total+$totalAddedValue+$shippingValue;
        $couponDiscount = null;


        return [
            'errors' => false,
            'cart_count' => count($carts),
            'carts' => $carts,
            'total' => $total,
            'addedValue' => $addedValue,
            'shippingValue' => $shippingValue,
            'totalAddedValue' => $totalAddedValue,
            'totalWithAddedAndShippingValue' => $totalWithAddedAndShippingValue,
        ];

    }

}
