/home/brandsfa/public_html/app/Http/Controllers/RestAPI/v4/CustomerController.php
<?php

namespace App\Http\Controllers\RestAPI\v4;

use App\Http\Controllers\Controller;
use App\Models\DeliveryCountryCode;
use App\Models\DeliveryZipCode;
use App\Models\Order;
use App\Models\ShippingAddress;
use App\Models\SupportTicket;
use App\Models\SupportTicketConv;
use App\Models\Wishlist;
use App\Traits\CommonTrait;
use App\User;
use App\Utils\CustomerManager;
use App\Utils\Helpers;
use App\Utils\ImageManager;
use App\Utils\OrderManager;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;

class CustomerController extends Controller
{
    use CommonTrait;

    public function __construct(
        private Order $order
    )
    {
    }

    public function info(Request $request)
    {
        $customer = $request->user();
        $wishlists = Wishlist::whereHas('wishlistProduct', function ($q) {
            return $q;
        })->where('customer_id', $customer->id)->count();

        $total_order = Order::where('customer_id', $customer->id)->count();

        $data = [
            'customer' => $customer,
            'wishlists' => $wishlists,
            'total_order' => $total_order,
            'compare_list' => $request->user()->compare_list->count(),
        ];
        return response()->json($data, 200);
    }

    public function create_support_ticket(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'subject' => 'required',
            'type' => 'required',
            'description' => 'required',
        ]);

        if ($validator->fails()) {
            return response()->json(['errors' => Helpers::error_processor($validator)], 403);
        }

        $image = [];
        if ($request->file('images')) {
            foreach ($request['image'] as $key => $value) {
                $image_name = ImageManager::upload('support-ticket/', 'webp', $value);
                $image[] = $image_name;
            }
        }

        $request['customer_id'] = $request->user()->id;
        $request['status'] = 'pending';
        $request['attachment'] = json_encode($image);

        try {
            CustomerManager::create_support_ticket($request);
        } catch (\Exception $e) {
            return response()->json([
                'errors' => [
                    'code' => 'failed',
                    'message' => 'Something went wrong',
                ],
            ], 422);
        }
        return response()->json(['message' => 'Support ticket created successfully.'], 200);
    }

    public function account_delete(Request $request)
    {
        $user = User::find($request->user()->id);

        $ongoing = ['out_for_delivery', 'processing', 'confirmed', 'pending'];
        $order = Order::where('customer_id', $user->id)->whereIn('order_status', $ongoing)->count();
        if ($order > 0) {
            return response()->json(['message' => 'You can`t delete account due ongoing order!!'], 403);
        }
        ImageManager::delete('/profile/' . $user['image']);

        $user->delete();
        return response()->json(['message' => 'Your account has been deleted successfully'], 200);
    }

    public function reply_support_ticket(Request $request, $ticket_id)
    {
        $image = [];
        if ($request->file('images')) {
            foreach ($request->images as $key => $value) {
                $image_name = ImageManager::upload('support-ticket/', 'webp', $value);
                $image[] = $image_name;
            }
        }

        $ticket = SupportTicket::find($ticket_id);
        $ticket->status = 'open';
        $ticket->save();

        $support = new SupportTicketConv();
        $support->support_ticket_id = $ticket_id;
        $support->attachment = json_encode($image);
        $support->admin_id = 1;
        $support->customer_message = $request['message'];
        $support->save();
        return response()->json(['message' => 'Support ticket reply sent.'], 200);
    }

    public function support_ticket_close(Request $request)
    {
        SupportTicket::where(['id' => $request->ticket_id])->update([
            'status' => 'close',
            'updated_at' => now(),
        ]);

        return response()->json(['message' => 'Ticket closed'], 200);
    }

    public function get_support_tickets(Request $request)
    {
        return response()->json(SupportTicket::where('customer_id', $request->user()->id)->get(), 200);
    }

    public function get_support_ticket_conv(Request $request, $ticket_id)
    {
        $conversations = SupportTicketConv::where('support_ticket_id', $ticket_id)->get();
        $support_ticket = SupportTicket::find($ticket_id);

        $conversations->map(function ($conversation) {
            $conversation['attachment'] = json_decode($conversation->attachment);
            return $conversation;
        });

        $conversations = $conversations->toArray();

        if ($support_ticket) {
            $description = array(
                'support_ticket_id' => $ticket_id,
                'admin_id' => null,
                'customer_message' => $support_ticket->description,
                'admin_message' => null,
                'attachment' => json_decode($support_ticket->attachment),
                'position' => 0,
                'created_at' => $support_ticket->created_at,
                'updated_at' => $support_ticket->updated_at,
            );
            array_unshift($conversations, $description);
        }

        return response()->json($conversations, 200);

    }

    public function add_to_wishlist(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'product_id' => 'required',
        ]);

        if ($validator->fails()) {
            return response()->json(['errors' => Helpers::error_processor($validator)], 403);
        }

        $wishlist = Wishlist::where('customer_id', $request->user()->id)->where('product_id', $request->product_id)->first();

        if (empty($wishlist)) {
            $wishlist = new Wishlist;
            $wishlist->customer_id = $request->user()->id;
            $wishlist->product_id = $request->product_id;
            $wishlist->save();
            return response()->json(['message' => 'Successfully added!'], 200);
        }

        return response()->json(['message' => 'Already in your wishlist'], 409);
    }

    public function remove_from_wishlist(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'product_id' => 'required',
        ]);

        if ($validator->fails()) {
            return response()->json(['errors' => Helpers::error_processor($validator)], 403);
        }

        $wishlist = Wishlist::where('customer_id', $request->user()->id)->where('product_id', $request->product_id)->first();

        if (!empty($wishlist)) {
            Wishlist::where(['customer_id' => $request->user()->id, 'product_id' => $request->product_id])->delete();
            return response()->json(['message' => 'successfully removed!'], 200);

        }
        return response()->json(['message' => 'No such data found!'], 404);
    }

    public function removeAllWishlist(Request $request): JsonResponse
    {
        Wishlist::where(['customer_id' => $request->user()->id])->delete();
        return response()->json(['message' => 'successfully removed!'], 200);
    }

    public function wish_list(Request $request)
    {

        $wishlist = Wishlist::whereHas('wishlistProduct', function ($q) {
            return $q;
        })->with(['productFullInfo'])->where('customer_id', $request->user()->id)->get();

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

    public function address_list(Request $request)
    {
        $user = Helpers::get_customer($request);
        if ($user == 'offline') {
            $data = ShippingAddress::where(['customer_id' => $request->guest_id, 'is_guest' => 1])->latest()->get();
        } else {
            $data = ShippingAddress::where(['customer_id' => $user->id, 'is_guest' => '0'])->latest()->get();
        }
        return response()->json($data, 200);
    }

    public function add_new_address(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'contact_person_name' => 'required',
            'address_type' => 'required',
            'address' => 'required',
            'city' => 'required',
            'zip' => 'required',
            'country' => 'required',
            'phone' => 'required',
            'is_billing' => 'required'
        ]);

        if ($validator->fails()) {
            return response()->json(['errors' => Helpers::error_processor($validator)], 403);
        }

        $zip_restrict_status = Helpers::get_business_settings('delivery_zip_code_area_restriction');
        $country_restrict_status = Helpers::get_business_settings('delivery_country_restriction');

        if ($country_restrict_status && !self::delivery_country_exist_check($request->input('country'))) {
            return response()->json(['message' => 'Delivery unavailable for this country'], 403);

        } elseif ($zip_restrict_status && !self::delivery_zipcode_exist_check($request->input('zip'))) {
            return response()->json(['message' => 'Delivery unavailable for this zip code area'], 403);
        }

        $user = Helpers::get_customer($request);
        $address = [
            'customer_id' => $user == 'offline' ? $request->guest_id : $user->id,
            'is_guest' => $user == 'offline' ? 1 : 0,
            'contact_person_name' => $request->contact_person_name,
            'address_type' => $request->address_type,
            'address' => $request->address,
            'city' => $request->city,
            'zip' => $request->zip,
            'country' => $request->country,
            'email' => $request->email,
            'phone' => $request->phone,
            'latitude' => $request->latitude,
            'longitude' => $request->longitude,
            'is_billing' => $request->is_billing,
            'created_at' => now(),
            'updated_at' => now(),
        ];
        ShippingAddress::insert($address);
        return response()->json(['message' => 'successfully added!'], 200);
    }

    public function update_address(Request $request)
    {
        $user = Helpers::get_customer($request);
        $shipping_address = ShippingAddress::where([
            'customer_id' => $user == 'offline' ? $request->guest_id : $user->id,
            'id' => $request->id
        ])->first();

        if (!$shipping_address) {
            return response()->json(['message' => 'Not found'], 200);
        }

        $zip_restrict_status = Helpers::get_business_settings('delivery_zip_code_area_restriction');
        $country_restrict_status = Helpers::get_business_settings('delivery_country_restriction');

        if ($country_restrict_status && !self::delivery_country_exist_check($request->input('country'))) {
            return response()->json(['message' => 'Delivery unavailable for this country'], 403);

        } elseif ($zip_restrict_status && !self::delivery_zipcode_exist_check($request->input('zip'))) {
            return response()->json(['message' => 'Delivery unavailable for this zip code area'], 403);
        }

        $shipping_address->update([
            'contact_person_name' => $request->contact_person_name,
            'address_type' => $request->address_type,
            'address' => $request->address,
            'city' => $request->city,
            'zip' => $request->zip,
            'country' => $request->country,
            'phone' => $request->phone,
            'latitude' => $request->latitude,
            'longitude' => $request->longitude,
            'is_billing' => $request->is_billing,
            'created_at' => now(),
            'updated_at' => now(),
        ]);

        return response()->json(['message' => 'Update successful'], 200);
    }

    public function delete_address(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'address_id' => 'required',
        ]);

        if ($validator->fails()) {
            return response()->json(['errors' => Helpers::error_processor($validator)], 403);
        }

        if (DB::table('shipping_addresses')->where(['id' => $request['address_id'], 'customer_id' => $request->user()->id])->first()) {
            DB::table('shipping_addresses')->where(['id' => $request['address_id'], 'customer_id' => $request->user()->id])->delete();
            return response()->json(['message' => 'successfully removed!'], 200);
        }
        return response()->json(['message' => 'No such data found!'], 404);
    }

    public function get_order_list(Request $request)
    {
        $status = ['delivered', 'canceled', 'failed'];
        $orders = Order::with('seller.shop', 'deliveryMan')
            ->withsum('details', 'qty')
            ->where(['customer_id' => $request->user()->id])
            ->when($request->type == 'previous', function ($query) use ($status) {
                $query->whereIn('order_status', $status);
            })
            ->when($request->type == 'ongoing', function ($query) use ($status) {
                $query->whereNotIn('order_status', $status);
            })
            ->latest()
            ->paginate($request['limit'], ['*'], 'page', $request['offset']);

        return [
            'total_size' => $orders->total(),
            'limit' => $request['limit'],
            'offset' => $request['offset'],
            'orders' => $orders->items()
        ];
    }

    public function get_order_details(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'order_id' => 'required',
        ]);
        if ($validator->fails()) {
            return response()->json(['errors' => Helpers::error_processor($validator)], 403);
        }

        $user = Helpers::get_customer($request);

        $order = $this->order->with(['details.seller.shop', 'details.product', 'verificationImages','deliveryManReview','offlinePayments','customer'])
            ->where([
                'id' => $request->order_id,
                'customer_id' => $user == 'offline' ? $request->guest_id : $user->id,
                'is_guest' => $user == 'offline' ? 1 : '0'
            ])
            ->first();

        if ($order) {
            $order['summery'] = OrderManager::order_summary($order);
            $order->details->map(function ($query) {
                $query['variation'] = json_decode($query['variation'], true);
                $query['product'] = Helpers::product_data_formatting(json_decode($query['product'], true));
                $query['product_details'] = json_decode($query['product_details'], true);
                return $query;
            });
        }
        return response()->json($order, 200);
    }

    public function get_order_by_id(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'order_id' => 'required',
        ]);

        if ($validator->fails()) {
            return response()->json(['errors' => Helpers::error_processor($validator)], 403);
        }

        $order = Order::with('verification_images', 'offline_payments')->where(['id' => $request['order_id']])->first();
        $order['shipping_address_data'] = json_decode($order['shipping_address_data']);
        $order['billing_address_data'] = json_decode($order['billing_address_data']);
        return response()->json($order, 200);
    }

    public function update_profile(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'f_name' => 'required',
            'l_name' => 'required',
            'phone' => 'required|unique:users,phone,'.$request->user()->id,
            'image' => 'image|mimes:jpeg,png,jpg,gif|max:6000'
        ], [
            'f_name.required' => 'First name is required!',
            'l_name.required' => 'Last name is required!',
        ]);

        if ($validator->fails()) {
            return response()->json(['errors' => Helpers::error_processor($validator)], 403);
        }

        if ($request->has('image')) {
            $imageName = ImageManager::update('profile/', $request->user()->image, 'webp', $request->file('image'));
        } else {
            $imageName = $request->user()->image;
        }

        if ($request['password'] != null && strlen($request['password']) > 5) {
            $pass = bcrypt($request['password']);
        } else {
            $pass = $request->user()->password;
        }

        $userDetails = [
            'f_name' => $request->f_name,
            'l_name' => $request->l_name,
            'phone' => $request->phone,
            'image' => $imageName,
            'password' => $pass,
            'updated_at' => now(),
        ];

        User::where(['id' => $request->user()->id])->update($userDetails);

        return response()->json(['message' => 'Successfully updated!'], 200);
    }

    public function update_cm_firebase_token(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'cm_firebase_token' => 'required',
        ]);

        if ($validator->fails()) {
            return response()->json(['errors' => Helpers::error_processor($validator)], 403);
        }

        DB::table('users')->where('id', $request->user()->id)->update([
            'cm_firebase_token' => $request['cm_firebase_token'],
        ]);

        return response()->json(['message' => 'successfully updated!'], 200);
    }

    public function get_restricted_country_list(Request $request)
    {
        $country_restriction = Helpers::get_business_settings('delivery_country_restriction');

        $stored_countries = DeliveryCountryCode::orderBy('country_code', 'ASC')->pluck('country_code')->toArray();
        $country_list = COUNTRIES;

        $countries = array();

        if ($country_restriction) {
            foreach ($country_list as $country) {
                if (in_array($country['code'], $stored_countries)) {
                    $countries[] = [
                        'code' => $country['code'],
                        'name' => $country['name']
                    ];
                }
            }
        } else {
            foreach ($country_list as $country) {
                $countries[] = [
                    'code' => $country['code'],
                    'name' => $country['name']
                ];
            }
        }

        if ($request->search) {
            $countries = array_values(preg_grep('~' . $request->search . '~i', $countries));
        }

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

    public function get_restricted_zip_list(Request $request)
    {
        $zipcodes = DeliveryZipCode::orderBy('zipcode', 'ASC')
            ->when($request->search, function ($query) use ($request) {
                $query->where('zipcode', 'like', "%{$request->search}%");
            })
            ->get();

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