<?php

namespace App\Http\Controllers\User;


use App\Helpers\GoogleAuthenticator;
use App\Http\Controllers\Controller;
use App\Models\Deposit;
use App\Models\Gateway;
use App\Models\Kyc;
use App\Models\Language;
use App\Models\Order;
use App\Models\PlanSchedule;
use App\Models\PurchasePlan;
use App\Models\Store;
use App\Models\StoreProduct;
use App\Models\Transaction;
use App\Models\UserKyc;
use App\Traits\Upload;
use DateTime;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;
use PragmaRX\Google2FA\Google2FA;


class HomeController extends Controller
{
    use Upload;

    public function __construct()
    {
        $this->middleware(['auth']);
        $this->middleware(function ($request, $next) {
            $this->user = auth()->user();
            return $next($request);
        });
        $this->theme = template();
    }

    public function saveToken(Request $request)
    {
        try {
            Auth::user()
                ->fireBaseToken()
                ->create([
                    'token' => $request->token,
                ]);
            return response()->json([
                'msg' => 'token saved successfully.',
            ]);
        } catch (\Exception $exception) {
            return back()->with('error', $exception->getMessage());
        }
    }


    public function index()
    {
        $basic = basicControl();
        $fraction = $basic->fraction_number;
        $user = Auth::user();
        $last30 = date('Y-m-d', strtotime('-30 days'));
        $last7 = date('Y-m-d', strtotime('-7 days'));
        $today = today();
        $dayCount = date('t', strtotime($today));

        $transactions = Transaction::select('created_at')
            ->whereMonth('created_at', $today)
            ->with(['transactional' => function (MorphTo $morphTo) {
                $morphTo->morphWith([
                    PurchasePlan::class => ['user'],
                    Order::class => ['user'],
                ]);
            }])
            ->whereHasMorph('transactional',
                [
                    PurchasePlan::class,
                    Order::class,
                ],
                function ($query, $type) use ($user) {
                    if ($type == PurchasePlan::class || $type == Order::class) {
                        $query->where('user_id', $user->id);
                    }
                })
            ->groupBy([DB::raw("DATE_FORMAT(created_at, '%j')")])
            ->selectRaw("SUM(CASE WHEN transactional_type like '%PurchasePlan' THEN amount ELSE 0 END) as PurchasePlan")
            ->selectRaw("SUM(CASE WHEN transactional_type like '%Order' THEN amount ELSE 0 END) as TrsOrder")
            ->get()
            ->groupBy([function ($query) {
                return $query->created_at->format('j');
            }]);

        $labels = [];
        $dataPurchasePlan = [];
        $dataOrder = [];
        for ($i = 1; $i <= $dayCount; $i++) {
            $labels[] = date('jS M', strtotime(date('Y/m/') . $i));
            $currentPurchasePlan = 0;
            $currentOrder = 0;
            if (isset($transactions[$i])) {
                foreach ($transactions[$i] as $key => $transaction) {
                    $currentPurchasePlan += $transaction->PurchasePlan;
                    $currentOrder += $transaction->TrsOrder;
                }
            }
            $dataPurchasePlan[] = round($currentPurchasePlan, $fraction);
            $dataOrder[] = round($currentOrder, $fraction);
        }

        $data['basic'] = $basic;
        $data['labels'] = $labels;
        $data['dataPurchasePlan'] = $dataPurchasePlan;
        $data['dataOrder'] = $dataOrder;

        $chartOrders = Order::select('created_at')
            ->where('status', 1)
            ->whereYear('created_at', $today)
            ->groupBy([DB::raw("DATE_FORMAT(created_at, '%m')")])
            ->selectRaw("COUNT((CASE WHEN stage = 0 OR stage = 2 OR stage = 3  THEN id END)) AS pendingOrders")
            ->selectRaw("COUNT((CASE WHEN stage = 4  THEN id END)) AS cancelOrders")
            ->selectRaw("COUNT((CASE WHEN stage = 1  THEN id END)) AS completeOrders")
            ->where('user_id', $user->id)
            ->get()
            ->groupBy([function ($query) {
                return $query->created_at->format('F');
            }]);

        $data['yearLabels'] = ['January', 'February', 'March', 'April', 'May', 'June', 'July ', 'August', 'September', 'October', 'November', 'December'];

        $yearPendingOrders = [];
        $yearCancelOrders = [];
        $yearCompleteOrders = [];


        foreach ($data['yearLabels'] as $yearLabel) {
            $currentYearPendingOrders = 0;
            $currentYearCancelOrders = 0;
            $currentYearCompleteOrders = 0;

            if (isset($chartOrders[$yearLabel])) {
                foreach ($chartOrders[$yearLabel] as $key => $itemOrder) {
                    $currentYearPendingOrders += $itemOrder->pendingOrders;
                    $currentYearCancelOrders += $itemOrder->cancelOrders;
                    $currentYearCompleteOrders += $itemOrder->completeOrders;
                }
            }
            $yearPendingOrders[] = round($currentYearPendingOrders, 2);
            $yearCancelOrders[] = round($currentYearCancelOrders, 2);
            $yearCompleteOrders[] = round($currentYearCompleteOrders, 2);
        }

        $data['yearPendingOrders'] = $yearPendingOrders;
        $data['yearCancelOrders'] = $yearCancelOrders;
        $data['yearCompleteOrders'] = $yearCompleteOrders;

        $stores = Store::selectRaw("COUNT(id) as TotalStore")
            ->selectRaw("COUNT(CASE WHEN status = 1 THEN 1 ELSE null END) as ActiveStores")
            ->where('user_id', $user->id)
            ->get();

        $orders = Order::
        selectRaw("COUNT(CASE WHEN status = 1 THEN 1 ELSE null END) as TotalOrders")
            ->where('user_id', $user->id)
            ->get();

        $menus = StoreProduct::selectRaw("COUNT(id) as TotalMenu")
            ->selectRaw("COUNT(CASE WHEN status = 1 THEN 1 ELSE null END) as ActiveMenu")
            ->where('user_id', $user->id)
            ->get();

        $store = $stores[0];
        $order = $orders[0];
        $menu = $menus[0];


        $purchasePlan = $user->plan;
        $data['remainingStores'] = @$purchasePlan->num_stores - $store['TotalStore'];
        $data['remainingOrders'] = @$purchasePlan->order_num - $order['TotalOrders'];
        $data['remainingMenus'] = @$purchasePlan->product_qty - $menu['TotalMenu'];
        $data['firebaseNotify'] = config('firebase');
        return view(template() . 'user.dashboard', $data, compact('user','store', 'order', 'menu'));
    }

    public function getTransactionChart(Request $request)
    {
        $start = $request->start;
        $end = $request->end;
        $user = Auth::user();

        $transactions = Transaction::select('created_at')
            ->whereBetween('created_at', [$start, $end])
            ->with(['transactional' => function (MorphTo $morphTo) {
                $morphTo->morphWith([
                    PurchasePlan::class => ['user'],
                    Order::class => ['user'],
                ]);
            }])
            ->whereHasMorph('transactional',
                [
                    PurchasePlan::class,
                    Order::class,
                ],
                function ($query, $type) use ($user) {
                    if ($type == PurchasePlan::class || $type == Order::class) {
                        $query->where('user_id', $user->id);
                    }
                })
            ->groupBy([DB::raw("DATE_FORMAT(created_at, '%j')")])
            ->selectRaw("SUM(CASE WHEN transactional_type like '%PurchasePlan' THEN amount ELSE 0 END) as PurchasePlan")
            ->selectRaw("SUM(CASE WHEN transactional_type like '%Order' THEN amount ELSE 0 END) as TrsOrder")
            ->get()
            ->groupBy([function ($query) {
                return $query->created_at->format('j');
            }]);

        $labels = [];
        $dataPurchasePlan = [];
        $dataOrder = [];
        $start = new DateTime($start);
        $end = new DateTime($end);

        for ($day = $start; $day <= $end; $day->modify('+1 day')) {
            $i = $day->format('j');
            $labels[] = $day->format('jS M');
            $currentPurchasePlan = 0;
            $currentOrder = 0;

            if (isset($transactions[$i])) {
                foreach ($transactions[$i] as $key => $transaction) {
                    $currentPurchasePlan += $transaction->PurchasePlan;
                    $currentOrder += $transaction->TrsOrder;
                }
            }
            $dataPurchasePlan[] = round($currentPurchasePlan, basicControl()->fraction_number);
            $dataOrder[] = round($currentOrder, basicControl()->fraction_number);
        }

        $data['basic'] = basicControl();
        $data['labels'] = $labels;
        $data['dataPurchasePlan'] = $dataPurchasePlan;
        $data['dataOrder'] = $dataOrder;
        return response()->json($data);
    }

    public function profile(Request $request)
    {
        $validator = Validator::make($request->all(), []);
        $data['user'] = $this->user;
        $data['languages'] = Language::all();
        $data['identityFormList'] = Kyc::where('status', 1)->get();
        if ($request->has('identity_type')) {
            $validator->errors()->add('identity', '1');
            $data['identity_type'] = $request->identity_type;
            $data['identityForm'] = Kyc::where('slug', trim($request->identity_type))->where('status', 1)->firstOrFail();
            $kycId = $data['identityForm']->id;
            $userKyc = UserKyc::where('kyc_id', $kycId)->where('user_id', auth()->id())->select('id','status','reason')->latest()->first();
            if ($userKyc){
                $data['submissionStatus'] = $userKyc->status == 0 ? 'Your KYC submission is pending' : ($userKyc->status == 1 ? 'Your KYC submission has been verified' : 'Your KYC submission has been rejected');
            }else{
                $data['submissionStatus'] = 'You have not submitted your KYC yet';
            }
            return view(template().'user.profile.my_profile', $data)->withErrors($validator);
        }
        return view(template() . 'user.profile.my_profile', $data);
    }

    public function profileUpdateImage(Request $request)
    {
        $allowedExtensions = array('jpg', 'png', 'jpeg');
        $image = $request->image;
        $this->validate($request, [
            'image' => [
                'required',
                'max:4096',
                function ($fail) use ($image, $allowedExtensions) {
                    $ext = strtolower($image->getClientOriginalExtension());
                    if (($image->getSize() / 1000000) > 2) {
                        throw ValidationException::withMessages(['image' => "Images MAX  4MB ALLOW!"]);
                    }
                    if (!in_array($ext, $allowedExtensions)) {
                        throw ValidationException::withMessages(['image' => "Only png, jpg, jpeg images are allowed"]);
                    }
                }
            ]
        ]);
        $user = Auth::user();
        if ($request->hasFile('image')) {
            $image = $this->fileUpload($request->image, config('filelocation.userProfile.path'), null, null, 'webp', 99, $user->image, $user->image_driver);
            if ($image) {
                $profileImage = $image['path'];
                $ImageDriver = $image['driver'];
            }
        }
        $user->image = $profileImage ?? $user->image;
        $user->image_driver = $ImageDriver ?? $user->image_driver;
        $user->save();
        return back()->with('success', 'Updated Successfully.');
    }

    public function profileUpdate(Request $request)
    {
        $languages = Language::all()->map(function ($item) {
            return $item->id;
        });
        throw_if(!$languages, 'Language not found.');

        $req = $request->except('_method', '_token');
        $user = Auth::user();
        $rules = [
            'first_name' => 'required|string|min:1|max:100',
            'last_name' => 'required|string|min:1|max:100',
            'email' => 'required|email:rfc,dns',
            'phone' => 'required|min:1|max:50',
            'username' => "sometimes|required|alpha_dash|min:5|unique:users,username," . $user->id,
            'address_one' => 'required|string|min:2|max:500',
            'address_two' => 'nullable|string|min:2|max:500',
            'language_id' => Rule::in($languages),
        ];
        $message = [
            'first_name.required' => 'First name field is required',
            'last_name.required' => 'Last name field is required',
        ];

        $validator = Validator::make($req, $rules, $message);
        if ($validator->fails()) {
            $validator->errors()->add('profile', '1');
            return back()->withErrors($validator)->withInput();
        }
        try {
            $response = $user->update([
                'language_id' => $req['language_id'],
                'firstname' => $req['first_name'],
                'lastname' => $req['last_name'],
                'email' => $req['email'],
                'phone' => $req['phone'],
                'username' => $req['username'],
                'address_one' => $req['address_one'],
                'address_two' => $req['address_two'] ?? $user->address_two,
            ]);

            throw_if(!$response, 'Something went wrong, While updating profile data');
            return back()->with('success', 'Profile updated Successfully.');
        } catch (\Exception $exception) {
            return back()->with('error', $exception->getMessage());
        }
    }


    public function updatePassword(Request $request)
    {
        $rules = [
            'current_password' => "required",
            'password' => "required|min:5|confirmed",
        ];

        $validator = Validator::make($request->all(), $rules);
        if ($validator->fails()) {
            return back()->withErrors($validator)->withInput();
        }
        $user = Auth::user();
        try {
            if (Hash::check($request->current_password, $user->password)) {
                $user->password = bcrypt($request->password);
                $user->save();
                return back()->with('success', 'Password Changes successfully.');
            } else {
                throw new \Exception('Current password did not match');
            }
        } catch (\Exception $e) {
            return back()->with('error', $e->getMessage());
        }
    }

    public function downloadPDF($Id)
    {
        $order = Order::with(['details', 'store', 'gateway', 'shipping'])->findOrFail($Id);
        $data = [
            'storeName' => optional($order->store)->name ?? 'unknown',
            'orderNumber' => $order->order_number,
            'paidType' => ($order->gateway_id == 0 ? 'Offline' : 'Online'),
            'gateway' => ($order->gateway_id == 0 ? 'Cash On Delivery' : optional($order->gateway)->name),
            'orderDate' => dateTime($order->created_at, 'd/M/Y H:i'),
            'deliveryAddress' => optional($order->shipping)->address ?? 'unknown',
            'detailsAddress' => $order->detailed_address ?? 'unknown',
            'deliveryNote' => $order->delivery_note ?? '',
            'orderNote' => $order->order_note ?? '',
            'fullName' => $order->full_name ?? 'unknown',
            'email' => $order->email ?? 'unknown',
            'phone' => $order->phone ?? 'unknown',
            'items' => $order->details,
            'deliveryFee' => getAmount($order->shipping_charge, 2) ?? 0,
            'discount' => getAmount($order->discount_amount, 2) ?? 0,
            'subtotal' => getAmount($order->total_amount, 2) ?? 0,
            'paymentAmount' => getAmount($order->payment_amount, 2) ?? 0,
            'currencySymbol' => basicControl()->currency_symbol,
        ];

        $pdf = App::make('dompdf.wrapper');
        $pdf->loadView($this->theme . 'pdf.order', $data);

        return $pdf->download();
    }

    public function sendPdf($order_id)
    {
        $data['order'] = Order::find($order_id);
        $pdf = App::make('dompdf.wrapper');
        $pdf->loadView('order_summary', $data);

        return $pdf->download();
    }
}
