<?php

namespace App\Http\Controllers\API;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

use App\Models\User;
use App\Models\ProductsAttribute;

class APIController extends Controller
{
    // Shiprocket API Integration
    // Shiprocket API Documentation: https://apidocs.shiprocket.in/
    // Push our 'Multi-vendor E-commerce Application' website orders (from our `orders` database table) to Shiprocket
    public function pushOrder($id) { // This route/URL/link is: GET http://127.0.0.1:8000/api/push-order/3
        // Get the Order from `orders` table and its order Details from `orders_products` table (using the 'order_items' Relationship)
        $getResults = \App\Models\Order::pushOrder($id);


        return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
            'status'  => $getResults['status'],
            'message' => $getResults['message']
        ]);
    }



    // Our Multi-vendor E-commerce Application Website API

    // Get ALL users    Or    Get a SINGLE user (GET)    (depending on if the {id?} Optional Paramter specified or not in the API Endpoint route)    // API Endpoint:    GET http://127.0.0.1:8000/api/users Or GET http://127.0.0.1:8000/api/users/37    // User must send an "Authorization" HTTP Header with all their HTTP Requests with this value (Bearer Token (JWT)): "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFtaXQgR3VwdGEiLCJpYXQiOjE1MTYyMzkwMjJ9.cNrgi6Sso9wvs4GlJmFnA4IqJY4o2QEcKXgshJTjfNg"    
    public function getUsers(Request $request, $id = null) { 
        if ($request->isMethod('get')) { // Check if the incoming HTTP Request Method/Verb is 'GET'
            // Simple Authentication    
            $header = $request->header('Authorization'); // Get the 'Authorization' HTTP Header sent from the user's client to the server with their HTTP Request    // Request Headers: https://laravel.com/docs/9.x/requests#request-headers
            // dd($header);

            if (empty($header)) { // If the user didn't send the "Authorization" HTTP Header (i.e. the Bearer Access Token) with their HTTP Request (if the user didn't provide the 'Authorization' Header) (Note: If the user didn't include the 'Authorization' Header at all, NOT gave a wrong value for it!)
                $message = '\'Authorization\' HTTP Request Header value (i.e. Bearer Access Token) is missing!';

                return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                    'status'  => false,
                    'message' => $message
                ], 422); // 422 HTTP Status Code: Unprocessable Content        

            } elseif ($header != 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFtaXQgR3VwdGEiLCJpYXQiOjE1MTYyMzkwMjJ9.cNrgi6Sso9wvs4GlJmFnA4IqJY4o2QEcKXgshJTjfNg') { // JWT token generated by (we wrote in "Ahmed Yahya" to generate this token in the website): https://jwt.io/    // User must send an "Authorization" HTTP Header with all their HTTP Requests with this value (Bearer Token (JWT)): "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFtaXQgR3VwdGEiLCJpYXQiOjE1MTYyMzkwMjJ9.cNrgi6Sso9wvs4GlJmFnA4IqJY4o2QEcKXgshJTjfNg"
                $message = 'Authorization Header value is Incorrect!';

                return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                    'status'  => false,
                    'message' => $message
                ], 422); // 422 HTTP Status Code: Unprocessable Content        
            }



            if (empty($id)) { // if the {id?} Optional Paramter is not specified in the API Endpoint URL, get ALL users
                $users = User::get();
            } else {  // if the {id?} Optional Paramter is specified in the API Endpoint URL, get a SINGLE user
                $users = User::find($id);
            }


            // Send back the newly submitted user data of the successful operation to the user again! (Note: This a well-known convention of APIs to send back the successful accepted data!)    
            return response()->json([ // Note: $user is AUTOMATICALLY converted from Laravel/PHP object to JSON! But we'll manually convert it to JSON using    return response()->json()    to show the "users" JSON property key/name in the response! Try the TWO cases and check the difference in Postman in "Pretty" tab!    // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                'users'   => $users
            ], 200); // 200 HTTP Status Code: OK            

        } else { // if the user is using the wrong dedicated HTTP Request Method/Verb for their request (i.e. User has used an HTTP Request Method/Verb other than 'GET')
            $message = 'You\'re using an incorrect/invalid HTTP Request Method/Verb to access this route/endpoint in our API!';

            return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                'status'  => false,
                'message' => $message
            ], 422); // 422 HTTP Status Code: Unprocessable Content        
        }
    }

    // Create a Single user (POST)    // API Endpoint:    POST http://127.0.0.1:8000/api/add-user    // 'name', 'email' and 'password' fields must be submitted by the user (from Postman). Note: Data can be posted/sent/submitted in Postman using a GET/POST/PUT/PATCH/DELETE request using TWO ways: First: "form-data" (resembles the HTML Form <input> fields (key/value pairs) and their "name" and "value" <input> HTML tag attributes, and you can retrieve those data in the backend using the Superglobals $_POST and $_FILES), Second: "raw" (through which you can decide the data type of the whole HTTP Request Body (e.g. JSON, HTML, ...etc), and you can retrieve those data in the backend using, for example if data were JSON, json_decode() function and then access the JSON key/value pairs as follows:    $jsonImageAttributes->filename    )     
    public function addUser(Request $request) {
        if ($request->isMethod('post')) { // Check if the incoming HTTP Request Method/Verb is 'POST'
            $userData = $request->input();

            // Validation (Laravel Validation)    // Manually Creating Validators: https://laravel.com/docs/9.x/validation#manually-creating-validators
            $rules = [
                // Fields/Column Names
                'name'     => 'required|regex:/^[\pL\s\-]+$/u', // regex:pattern: https://laravel.com/docs/9.x/validation#rule-regex
                'email'    => 'required|email|unique:users', // 'unique' validation rule in `users` datbase table    // unique:table,column: https://laravel.com/docs/9.x/validation#rule-unique
                'password' => 'required'
            ];

            // Customizing Laravel's default error messages for every [Field with Validation Rule] e.g. the 'required' Validation Rule for the 'name' field    // Customizing The Error Messages: https://laravel.com/docs/9.x/validation#manual-customizing-the-error-messages
            $customMessages = [
                // The SAME last Fields (inside $rules array)
                'name.required'     => 'Your Name (field) is required',

                'email.required'    => 'Your email (field) is required',
                'email.email'       => 'Your email (field) must be a Valid email',
                'email.unique'      => 'Your email already exists in our database!',

                'password.required' => 'Your password (field) is required'
            ];

            $validator = \Illuminate\Support\Facades\Validator::make($userData, $rules, $customMessages);

            if ($validator->fails()) {
                return response()->json($validator->errors(), 422);       
 
            }


            // Add/Save the submitted new user data in `users` table ('name', 'email', 'password' fields must be submitted in Postman!)
            $user = new User;
            $user->name     = $userData['name'];
            $user->email    = $userData['email'];
            $user->password = bcrypt($userData['password']); // Hash the password before storing it in the database table
            $user->save();


            // Send back the newly submitted user data of the successful operation to the user again! (Note: This a well-known convention of APIs to send back the successful accepted data!)    
            return response()->json([ // Note: $user is AUTOMATICALLY converted from Laravel/PHP object to JSON! But we'll manually convert it to JSON using    return response()->json()    to show the "users" JSON property key/name in the response! Try the TWO cases and check the difference in Postman in "Pretty" tab!    // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                'message' => 'User added successfully!',
                'user'    => $user
            ], 201); // 201 HTTP Status Code: Created    // With POST requests, 201 Created HTTP Status Code is sent with the HTTP Response        

        } else { // if the user is using the wrong dedicated HTTP Request Method/Verb for their request (i.e. User has used an HTTP Request Method/Verb other than 'POST')
            $message = 'You\'re using an incorrect/invalid HTTP Request Method/Verb to access this route/endpoint in our API!';

            return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                'status'  => false,
                'message' => $message
            ], 422); // 422 HTTP Status Code: Unprocessable Content        
        }
    }

    // Create Multiple users (also works for Create a Single user) (POST)    // API Endpoint:    POST http://127.0.0.1:8000/api/add-multiple-users    // Note: In Postman, JSON data are submitted using Curly Braces {} and a "users" Wrapping Object and Square Brackets [])    // 'name', 'email' and 'password' fields must be submitted by the user (from Postman). Note: Data can be posted/sent/submitted in Postman using a GET/POST/PUT/PATCH/DELETE request using TWO ways: First: "form-data" (resembles the HTML Form <input> fields (key/value pairs) and their "name" and "value" <input> HTML tag attributes, and you can retrieve those data in the backend using the Superglobals $_POST and $_FILES), Second: "raw" (through which you can decide the data type of the whole HTTP Request Body (e.g. JSON, HTML, ...etc), and you can retrieve those data in the backend using, for example if data were JSON, json_decode() function and then access the JSON key/value pairs as follows:    $jsonImageAttributes->filename    )     
    public function addMultipleUsers(Request $request) {
        if ($request->isMethod('post')) { // Check if the incoming HTTP Request Method/Verb is 'POST'
            $userData = $request->input();
            
            // Validation (Laravel Validation)    // Manually Creating Validators: https://laravel.com/docs/9.x/validation#manually-creating-validators
            // Important Note: Here, this situation is different! Because JSON data come in as bulk/multiple JSON data/objects! So, we have to modify our validation Rules syntax a litte!    // Important Note (Validation Rules syntax for incoming/submitted bulk/multiple JSON data/objects and their Custom Messages  i.e.  This is called "Validating Nested Array Input": https://laravel.com/docs/9.x/validation#validating-nested-array-input): If you want to validate (do Validation) incoming data, which for example come as JSON data submitted to your API, and those data come as bulk/multiple JSON data/objects which are wrapped inside a JSON Wrapping Object, you can write your $rules array like:     $rules = [ 'users.*.name' => 'requried' ];     where 'users' is the JSON Wrapping Object, and * (asterisk) is the array indexes (e.g. 0, 1, 2, ...)    // Validating Nested Array Input: https://laravel.com/docs/9.x/validation#validating-nested-array-input
            $rules = [
                // Fields/Column Names
                // Validating Nested Array Input: https://laravel.com/docs/9.x/validation#validating-nested-array-input
                'users.*.name'     => 'required|regex:/^[\pL\s\-]+$/u', // Note: Submitted data is bulk/mulple JSON data/objects wrapped in a 'users' JSON Wrapping Object, and '*' (asterisk) denotes the array keys/indexes (e.g. 0, 1, 2, ...)    // Validating Nested Array Input: https://laravel.com/docs/9.x/validation#validating-nested-array-input
                'users.*.email'    => 'required|email|unique:users',    // Note: Submitted data is bulk/mulple JSON data/objects wrapped in a 'users' JSON Wrapping Object, and '*' (asterisk) denotes the array keys/indexes (e.g. 0, 1, 2, ...)    // Validating Nested Array Input: https://laravel.com/docs/9.x/validation#validating-nested-array-input
                'users.*.password' => 'required'                        // Note: Submitted data is bulk/mulple JSON data/objects wrapped in a 'users' JSON Wrapping Object, and '*' (asterisk) denotes the array keys/indexes (e.g. 0, 1, 2, ...)    // Validating Nested Array Input: https://laravel.com/docs/9.x/validation#validating-nested-array-input
            ];

            // Customizing Laravel's default error messages for every [Field with Validation Rule] e.g. the 'required' Validation Rule for the 'name' field    // Customizing The Error Messages: https://laravel.com/docs/9.x/validation#manual-customizing-the-error-messages
            $customMessages = [
                // The SAME last Fields (inside $rules array)
                'users.*.name.required'     => 'Your Name (field) is required',              // Note: Submitted data is bulk/mulple JSON data/objects wrapped in a 'users' JSON Wrapping Object, and '*' (asterisk) denotes the array keys/indexes (e.g. 0, 1, 2, ...)    // Validating Nested Array Input: https://laravel.com/docs/9.x/validation#validating-nested-array-input

                'users.*.email.required'    => 'Your email (field) is required',             // Note: Submitted data is bulk/mulple JSON data/objects wrapped in a 'users' JSON Wrapping Object, and '*' (asterisk) denotes the array keys/indexes (e.g. 0, 1, 2, ...)    // Validating Nested Array Input: https://laravel.com/docs/9.x/validation#validating-nested-array-input
                'users.*.email.email'       => 'Your email (field) must be a Valid email',   // Note: Submitted data is bulk/mulple JSON data/objects wrapped in a 'users' JSON Wrapping Object, and '*' (asterisk) denotes the array keys/indexes (e.g. 0, 1, 2, ...)    // Validating Nested Array Input: https://laravel.com/docs/9.x/validation#validating-nested-array-input
                'users.*.email.unique'      => 'Your email already exists in our database!', // Note: Submitted data is bulk/mulple JSON data/objects wrapped in a 'users' JSON Wrapping Object, and '*' (asterisk) denotes the array keys/indexes (e.g. 0, 1, 2, ...)    // Validating Nested Array Input: https://laravel.com/docs/9.x/validation#validating-nested-array-input

                'users.*.password.required' => 'Your password (field) is required'           // Note: Submitted data is bulk/mulple JSON data/objects wrapped in a 'users' JSON Wrapping Object, and '*' (asterisk) denotes the array keys/indexes (e.g. 0, 1, 2, ...)    // Validating Nested Array Input: https://laravel.com/docs/9.x/validation#validating-nested-array-input
            ];

            
            $validator = \Illuminate\Support\Facades\Validator::make($userData, $rules, $customMessages);



            if ($validator->fails()) {
                return response()->json($validator->errors(), 422);       
 
            }


            // Use a foreach loop because there are multiple JSON data/objects submitted in one go in the request    // Note: In Postman, JSON data are submitted using Curly Braces {} and a "users" Wrapping Object and Square Brackets [])
            foreach ($userData['users'] as $key => $value) {
                // Add/Save the submitted new user data in `users` table ('name', 'email', 'password' fields must be submitted in Postman!)
                $user = new User;
                $user->name     = $value['name'];
                $user->email    = $value['email'];
                $user->password = bcrypt($value['password']); // Hash the password before storing it in the database table
                $user->save();
            }


            // Send back the newly submitted user data of the successful operation to the user again! (Note: This a well-known convention of APIs to send back the successful accepted data!)    
            return response()->json([ // Note: $user is AUTOMATICALLY converted from Laravel/PHP object to JSON! But we'll manually convert it to JSON using    return response()->json()    to show the "users" JSON property key/name in the response! Try the TWO cases and check the difference in Postman in "Pretty" tab!    // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                'message' => 'Users added successfully!'
            ], 201); // 201 HTTP Status Code: Created    // With POST requests, 201 Created HTTP Status Code is sent with the HTTP Response        

        } else { // if the user is using the wrong dedicated HTTP Request Method/Verb for their request (i.e. User has used an HTTP Request Method/Verb other than 'POST')
            $message = 'You\'re using an incorrect/invalid HTTP Request Method/Verb to access this route/endpoint in our API!';

            return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                'status'  => false,
                'message' => $message
            ], 422); // 422 HTTP Status Code: Unprocessable Content        
        }
    }

    // Update a Single user details (PUT)    // API Endpoint:    PUT http://127.0.0.1:8000/api/update-user-details Or PUT http://127.0.0.1:8000/api/update-user-details/23    // Note: In Postman, JSON data are submitted using Curly Braces {} and a "users" Wrapping Object and Square Brackets [])    // 'id', 'name', 'email' and 'password' fields must be submitted by the user (from Postman). Note: Data can be posted/sent/submitted in Postman using a GET/POST/PUT/PATCH/DELETE request using TWO ways: First: "form-data" (resembles the HTML Form <input> fields (key/value pairs) and their "name" and "value" <input> HTML tag attributes, and you can retrieve those data in the backend using the Superglobals $_POST and $_FILES), Second: "raw" (through which you can decide the data type of the whole HTTP Request Body (e.g. JSON, HTML, ...etc), and you can retrieve those data in the backend using, for example if data were JSON, json_decode() function and then access the JSON key/value pairs as follows:    $jsonImageAttributes->filename    )     
    public function updateUserDetails(Request $request, $id = null) { // Note: Query String Paramets (like 'id') can be submitted in THREE ways: using "Body" tab in Postman (as JSON data), as a URL Query String Parameters (e.g. www.example.com?id=3) and using Postman "Params" tab        
        if ($request->isMethod('put')) { // Check if the incoming HTTP Request Method/Verb is 'PUT'
            $userData = $request->input();

            // Validation (Laravel Validation)    // Manually Creating Validators: https://laravel.com/docs/9.x/validation#manually-creating-validators
            $rules = [
                // Fields/Column Names
                'name'     => 'required|regex:/^[\pL\s\-]+$/u', // regex:pattern: https://laravel.com/docs/9.x/validation#rule-regex
                'email'    => 'required|email', // 'unique' validation rule in `users` datbase table    // unique:table,column: https://laravel.com/docs/9.x/validation#rule-unique
                'password' => 'required'
            ];

            // Customizing Laravel's default error messages for every [Field with Validation Rule] e.g. the 'required' Validation Rule for the 'name' field    // Customizing The Error Messages: https://laravel.com/docs/9.x/validation#manual-customizing-the-error-messages
            $customMessages = [
                // The SAME last Fields (inside $rules array)
                'name.required'     => 'Your Name (field) is required',

                'email.required'    => 'Your email (field) is required',
                'email.email'       => 'Your email (field) must be a Valid email',

                'password.required' => 'Your password (field) is required'
            ];

            $validator = \Illuminate\Support\Facades\Validator::make($userData, $rules, $customMessages);

            if ($validator->fails()) {
                return response()->json($validator->errors(), 422);       
 
            }


            // Update submitted user details in `users` table
            User::where('id', isset($id) ? $id : $userData['id'])->update([ // if the id is sent as a URL Query String Parameter, take its value as is, or else, take its value from the JSON "Body"
                'name'     => $userData['name'],
                'email'    => $userData['email'],
                'password' => bcrypt($userData['password'])
            ]);


            // Send back the newly submitted user data of the successful operation to the user again! (Note: This a well-known convention of APIs to send back the successful accepted data!)    
            return response()->json([ // Note: $user is AUTOMATICALLY converted from Laravel/PHP object to JSON! But we'll manually convert it to JSON using    return response()->json()    to show the "users" JSON property key/name in the response! Try the TWO cases and check the difference in Postman in "Pretty" tab!    // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                'message' => 'User details updated successfully!'
            ], 202); // 202 HTTP Status Code: Accepted    // With PUT/PATCH requests, 202 Accepted HTTP Status Code is sent with the HTTP Response        

        } else { // if the user is using the wrong dedicated HTTP Request Method/Verb for their request (i.e. User has used an HTTP Request Method/Verb other than 'PUT')
            $message = 'You\'re using an incorrect/invalid HTTP Request Method/Verb to access this route/endpoint in our API!';

            return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                'status'  => false,
                'message' => $message
            ], 422); // 422 HTTP Status Code: Unprocessable Content        
        }
    }

    // Update the 'name' ONLY of a Single user (just a portion of a resource) (PATCH)    // API Endpoint:    PATCH http://127.0.0.1:8000/api/update-user-name Or PATCH http://127.0.0.1:8000/api/update-user-name/21    // Note: In Postman, JSON data are submitted using Curly Braces {} and a "users" Wrapping Object and Square Brackets [])    // 'id' and 'name' fields must be submitted by the user (from Postman). Note: Data can be posted/sent/submitted in Postman using a GET/POST/PUT/PATCH/DELETE request using TWO ways: First: "form-data" (resembles the HTML Form <input> fields (key/value pairs) and their "name" and "value" <input> HTML tag attributes, and you can retrieve those data in the backend using the Superglobals $_POST and $_FILES), Second: "raw" (through which you can decide the data type of the whole HTTP Request Body (e.g. JSON, HTML, ...etc), and you can retrieve those data in the backend using, for example if data were JSON, json_decode() function and then access the JSON key/value pairs as follows:    $jsonImageAttributes->filename    )     
    public function updateUserName(Request $request, $id = null) { // Note: Query String Paramets (like 'id') can be submitted in THREE ways: using "Body" tab in Postman (as JSON data), as a URL Query String Parameters (e.g. www.example.com?id=3) and using Postman "Params" tab        
        if ($request->isMethod('patch')) { // Check if the incoming HTTP Request Method/Verb is 'PATCH'
            $userData = $request->input();

            // Validation (Laravel Validation)     // Manually Creating Validators: https://laravel.com/docs/9.x/validation#manually-creating-validators
            $rules = [
                // Fields/Column Names
                'name'     => 'required|regex:/^[\pL\s\-]+$/u', // regex:pattern: https://laravel.com/docs/9.x/validation#rule-regex
            ];

            // Customizing Laravel's default error messages for every [Field with Validation Rule] e.g. the 'required' Validation Rule for the 'name' field    // Customizing The Error Messages: https://laravel.com/docs/9.x/validation#manual-customizing-the-error-messages
            $customMessages = [
                // The SAME last Fields (inside $rules array)
                'name.required'     => 'Your Name (field) is required'
            ];
            
            $validator = \Illuminate\Support\Facades\Validator::make($userData, $rules, $customMessages);

            if ($validator->fails()) {
                return response()->json($validator->errors(), 422);       
 
            }

            // Update the `name` column of the submitted user 'id' and 'name' in `users` table
            User::where('id', isset($id) ? $id : $userData['id'])->update(['name' => $userData['name']]); // if the id is sent as a URL Query String Parameter, take its value as is, or else, take its value from the JSON "Body"

            // Send back the newly submitted user data of the successful operation to the user again! (Note: This a well-known convention of APIs to send back the successful accepted data!)    
            return response()->json([ // Note: $user is AUTOMATICALLY converted from Laravel/PHP object to JSON! But we'll manually convert it to JSON using    return response()->json()    to show the "users" JSON property key/name in the response! Try the TWO cases and check the difference in Postman in "Pretty" tab!    // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                'message' => 'User\'s name ONLY updated successfully!'

            ], 202); // 202 HTTP Status Code: Accepted    // With PUT/PATCH requests, 202 Accepted HTTP Status Code is sent with the HTTP Response        

        } else { // if the user is using the wrong dedicated HTTP Request Method/Verb for their request (i.e. User has used an HTTP Request Method/Verb other than 'PATCH')
            $message = 'You\'re using an incorrect/invalid HTTP Request Method/Verb to access this route/endpoint in our API!';

            return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                'status'  => false,
                'message' => $message
            ], 422); // 422 HTTP Status Code: Unprocessable Content        
        }
    }

    // Delete a Single user (DELETE)    // API Endpoint:    DELETE http://127.0.0.1:8000/api/delete-user Or DELETE http://127.0.0.1:8000/api/delete-user/32    // Note: In Postman, JSON data are submitted using Curly Braces {} and a "users" Wrapping Object and Square Brackets [])    // 'id' field must be submitted by the user (from Postman). Note: Data can be posted/sent/submitted in Postman using a GET/POST/PUT/PATCH/DELETE request using TWO ways: First: "form-data" (resembles the HTML Form <input> fields (key/value pairs) and their "name" and "value" <input> HTML tag attributes, and you can retrieve those data in the backend using the Superglobals $_POST and $_FILES), Second: "raw" (through which you can decide the data type of the whole HTTP Request Body (e.g. JSON, HTML, ...etc), and you can retrieve those data in the backend using, for example if data were JSON, json_decode() function and then access the JSON key/value pairs as follows:    $jsonImageAttributes->filename    )     
    public function deleteUser(Request $request, $id = null) { // Note: Query String Paramets (like 'id') can be submitted in THREE ways: using "Body" tab in Postman (as JSON data), as a URL Query String Parameters (e.g. www.example.com?id=3) and using Postman "Params" tab        
        if ($request->isMethod('delete')) { // Check if the incoming HTTP Request Method/Verb is 'DELETE'
            $userData = $request->input();

            // Delete the submitted user 'id' from the `users` table
            User::where('id', isset($id) ? $id : $userData['id'])->delete(); // if the id is sent as a URL Query String Parameter, take its value as is, or else, take its value from the JSON "Body"


            // Send back the newly submitted user data of the successful operation to the user again! (Note: This a well-known convention of APIs to send back the successful accepted data!)    
            return response()->json([ // Note: $user is AUTOMATICALLY converted from Laravel/PHP object to JSON! But we'll manually convert it to JSON using    return response()->json()    to show the "users" JSON property key/name in the response! Try the TWO cases and check the difference in Postman in "Pretty" tab!    // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                'message' => 'User deleted successfully!'
            ], 202/* 204 */); // 204 HTTP Status Code: No Content    // With DELETE requests, 204 No Content, 202 Accepted or 200 HTTP Status Code is sent with the HTTP Response    // Note: 204 No Content HTTP Status Code cancels out/hides any Messages you send back with your HTTP Response! (Your Message would disappear/vanish with your HTTP Response! Nothing at all will show up to the user!)        

        } else { // if the user is using the wrong dedicated HTTP Request Method/Verb for their request (i.e. User has used an HTTP Request Method/Verb other than 'DELETE')
            $message = 'You\'re using an incorrect/invalid HTTP Request Method/Verb to access this route/endpoint in our API!';

            return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                'status'  => false,
                'message' => $message
            ], 422); // 422 HTTP Status Code: Unprocessable Content        
        }
    }

    // Delete Multiple users (DELETE)    // API Endpoint:    DELETE http://127.0.0.1:8000/api/delete-multiple-users Or DELETE http://127.0.0.1:8000/api/delete-multiple-users/11,13,20    // Note: In Postman, JSON data are submitted using Curly Braces {} and an "ids" Wrapping Object and Square Brackets [])    // 'ids' field must be submitted by the user (from Postman). Note: Data can be posted/sent/submitted in Postman using a GET/POST/PUT/PATCH/DELETE request using TWO ways: First: "form-data" (resembles the HTML Form <input> fields (key/value pairs) and their "name" and "value" <input> HTML tag attributes, and you can retrieve those data in the backend using the Superglobals $_POST and $_FILES), Second: "raw" (through which you can decide the data type of the whole HTTP Request Body (e.g. JSON, HTML, ...etc), and you can retrieve those data in the backend using, for example if data were JSON, json_decode() function and then access the JSON key/value pairs as follows:    $jsonImageAttributes->filename    )     
    public function deleteMultipleUsers(Request $request, $ids = null) { // Note: Query String Paramets (like 'id') can be submitted in THREE ways: using "Body" tab in Postman (as JSON data), as a URL Query String Parameters (e.g. www.example.com?id=3) and using Postman "Params" tab        
        if ($request->isMethod('delete')) { // Check if the incoming HTTP Request Method/Verb is 'DELETE'
            $userData = $request->input();

            if (isset($ids)) { // if the ids are sent as a URL Query String Parameter, take its value as is, or else, take its values from the JSON (using the "Body" tab in Postman)
                $ids = array_map('trim', (explode(',', $ids))); // In case user adds spaces between ids in the URL like "http://127.0.0.1:8000/api/delete-multiple-users/20, 9 , 10" instead of "http://127.0.0.1:8000/api/delete-multiple-users/20,9,10", I used array_map() function here to apply the trim() function on EVERY array element of the array returned from the explode() function
                // dd($ids);

                // Delete the submitted users 'id's from the `users` table
                User::whereIn('id', $ids)->delete(); // Used whereIn() method instead of where() because we are getting (to delete) an ARRAY of ids

                // Send back the newly submitted user data of the successful operation to the user again! (Note: This a well-known convention of APIs to send back the successful accepted data!)    
                return response()->json([ // Note: $user is AUTOMATICALLY converted from Laravel/PHP object to JSON! But we'll manually convert it to JSON using    return response()->json()    to show the "users" JSON property key/name in the response! Try the TWO cases and check the difference in Postman in "Pretty" tab!    // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                    'message' => 'Users deleted successfully!'
                ], 202/* 204 */); // 204 HTTP Status Code: No Content    // With DELETE requests, 204 No Content, 202 Accepted or 200 HTTP Status Code is sent with the HTTP Response    // Note: 204 No Content HTTP Status Code cancels out/hides any Messages you send back with your HTTP Response! (Your Message would disappear/vanish with your HTTP Response! Nothing at all will show up to the user!)        

            } else { // if the ids are not sent as a URL Query String Parameter, but else, sent in the "Body" tab in Postman as JSON data

                // Delete the submitted users 'id's from the `users` table
                User::whereIn('id', $userData['ids'])->delete(); // Submitted/Sent JSON data are bulk/multiple JSON data/objects which are wrapped in an "ids" Wrapping Object, and Curly Braces {} and Square Brackets [] are used    // Used whereIn() method instead of where() because we are getting (to delete) an ARRAY of ids

                // Send back the newly submitted user data of the successful operation to the user again! (Note: This a well-known convention of APIs to send back the successful accepted data!)    
                return response()->json([ // Note: $user is AUTOMATICALLY converted from Laravel/PHP object to JSON! But we'll manually convert it to JSON using    return response()->json()    to show the "users" JSON property key/name in the response! Try the TWO cases and check the difference in Postman in "Pretty" tab!    // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                    'message' => 'Users deleted successfully!'
                ], 202/* 204 */); // 204 HTTP Status Code: No Content    // With DELETE requests, 204 No Content, 202 Accepted or 200 HTTP Status Code is sent with the HTTP Response    // Note: 204 No Content HTTP Status Code cancels out/hides any Messages you send back with your HTTP Response! (Your Message would disappear/vanish with your HTTP Response! Nothing at all will show up to the user!)        
            }

        } else { // if the user is using the wrong dedicated HTTP Request Method/Verb for their request (i.e. User has used an HTTP Request Method/Verb other than 'DELETE')
            $message = 'You\'re using an incorrect/invalid HTTP Request Method/Verb to access this route/endpoint in our API!';

            return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                'status'  => false,
                'message' => $message
            ], 422); // 422 HTTP Status Code: Unprocessable Content        
        }
    }

    // Register a new user and Generate a new Access Token for them (POST)    // API Endpoint:    POST http://127.0.0.1:8000/api/register-user    // Whenever a new user registers a new account using our Registration API Endpoint, we'll generate an Access Token for them to use and send with all their subsequent HTTP Requests (and will store it in the `access_token` column in `users` table). Note: Whenever the user logs in, we'll generate a new Access Token (that acts the same as a browser Session (i.e. Both Session and Access Token are sent from the client to the server with EVERY HTTP Request), except the fact that there's no browser Session here!) that will replace the old one in the `access_token` column in `users` table. This token will be valid only till the user logs out and then expires (by deleting it from the `access_token` column in the `users` database table when the user logs out)    // User can use the new Access Token that gets generated wheny they register a new account with all their subsequent HTTP Requests    // Note: In Postman, JSON data are submitted using Curly Braces {} and an "ids" Wrapping Object and Square Brackets [])    // 'name', 'email' and 'password' fields must be submitted by the user (from Postman). Note: Data can be posted/sent/submitted in Postman using a GET/POST/PUT/PATCH/DELETE request using TWO ways: First: "form-data" (resembles the HTML Form <input> fields (key/value pairs) and their "name" and "value" <input> HTML tag attributes, and you can retrieve those data in the backend using the Superglobals $_POST and $_FILES), Second: "raw" (through which you can decide the data type of the whole HTTP Request Body (e.g. JSON, HTML, ...etc), and you can retrieve those data in the backend using, for example if data were JSON, json_decode() function and then access the JSON key/value pairs as follows:    $jsonImageAttributes->filename    )    
    public function registerUser(Request $request) {
        if ($request->isMethod('post')) { // Check if the incoming HTTP Request Method/Verb is 'POST'
            $userData = $request->input();

            // Validation (Laravel Validation)    // Manually Creating Validators: https://laravel.com/docs/9.x/validation#manually-creating-validators
            $rules = [
                // Fields/Column Names
                'name'     => 'required|regex:/^[\pL\s\-]+$/u', // regex:pattern: https://laravel.com/docs/9.x/validation#rule-regex
                'email'    => 'required|email|unique:users', // 'unique' validation rule in `users` datbase table    // unique:table,column: https://laravel.com/docs/9.x/validation#rule-unique
                'password' => 'required'
            ];

            // Customizing Laravel's default error messages for every [Field with Validation Rule] e.g. the 'required' Validation Rule for the 'name' field    // Customizing The Error Messages: https://laravel.com/docs/9.x/validation#manual-customizing-the-error-messages
            $customMessages = [
                // The SAME last Fields (inside $rules array)
                'name.required'     => 'Your Name (field) is required',

                'email.required'    => 'Your email (field) is required',
                'email.email'       => 'Your email (field) must be a Valid email',
                'email.unique'      => 'Your email already exists in our database!',

                'password.required' => 'Your password (field) is required'
            ];
            
            $validator = \Illuminate\Support\Facades\Validator::make($userData, $rules, $customMessages);

            if ($validator->fails()) {
                return response()->json($validator->errors(), 422);        
            }


            // Generate a new Access Token for the user, and save it in the `access_token` column in `users` table (and overwrite/override/replace the old Access Token in `access_token` column if there is any!)
            $accessToken = \Illuminate\Support\Str::random(60); // Str::random(): https://laravel.com/docs/9.x/helpers#method-str-random

            // Register the new user i.e. Save the submitted user data (name, email and password) along with the newly generated API Access Token in `users` table
            $user = new User;

            $user->name     = $userData['name'];
            $user->email    = $userData['email'];
            $user->password = bcrypt($userData['password']); // Hash the password before saving it in the database table

            // $user->api_token = $apiToken;
            $user->access_token = $accessToken;

            $user->save();


            // Send back the newly submitted user data of the successful operation to the user again! (Note: This a well-known convention of APIs to send back the successful accepted data!)    
            return response()->json([ // Note: $user is AUTOMATICALLY converted from Laravel/PHP object to JSON! But we'll manually convert it to JSON using    return response()->json()    to show the "users" JSON property key/name in the response! Try the TWO cases and check the difference in Postman in "Pretty" tab!    // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                'status'  => true,
                'message' => 'User registered successfully!',
                'token'   => $accessToken,
                'user'    => $user
            ], 201);  // 201 HTTP Status Code: Created    // With POST requests, 201 Created HTTP Status Code is sent with the HTTP Response        

        } else { // if the user is using the wrong dedicated HTTP Request Method/Verb for their request (i.e. User has used an HTTP Request Method/Verb other than 'POST')
            $message = 'You\'re using an incorrect/invalid HTTP Request Method/Verb to access this route/endpoint in our API!';

            return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                'status'  => false,
                'message' => $message
            ], 422); // 422 HTTP Status Code: Unprocessable Content        
        }
    }

    // Log in a user and Generate a new Access Token for them (POST)    // API Endpoint:    POST http://127.0.0.1:8000/api/login-user    // Whenever a new user registers a new account using our Registration API Endpoint, we'll generate an Access Token for them to use and send with all their subsequent HTTP Requests (and will store it in the `access_token` column in `users` table). Note: Whenever the user logs in, we'll generate a new Access Token (that acts the same as a browser Session (i.e. Both Session and Access Token are sent from the client to the server with EVERY HTTP Request), except the fact that there's no browser Session here!) that will replace the old one in the `access_token` column in `users` table. This token will be valid only till the user logs out and then expires (by deleting it from the `access_token` column in the `users` database table when the user logs out)    // User must send an "Authorization" HTTP Header with all their subsequent HTTP Requests with the value of the "Bearer" Accesss Token that they received in the HTTP Response when they first logged in or when they first registered their brand-new account. The "Bearer" Access Token should be sent in the following form:    "Bearer xxxxxxxxxxxxxxxxxx"    where xxxxxxxxxxxxxxxxxx is the "Bearer" Access Token value.    // Note: In Postman, JSON data are submitted using Curly Braces {} and an "ids" Wrapping Object and Square Brackets [])    // 'email' and 'password' fields must be submitted by the user (from Postman). Note: Data can be posted/sent/submitted in Postman using a GET/POST/PUT/PATCH/DELETE request using TWO ways: First: "form-data" (resembles the HTML Form <input> fields (key/value pairs) and their "name" and "value" <input> HTML tag attributes, and you can retrieve those data in the backend using the Superglobals $_POST and $_FILES), Second: "raw" (through which you can decide the data type of the whole HTTP Request Body (e.g. JSON, HTML, ...etc), and you can retrieve those data in the backend using, for example if data were JSON, json_decode() function and then access the JSON key/value pairs as follows:    $jsonImageAttributes->filename    )    
    public function loginUser(Request $request) {
        if ($request->isMethod('post')) { // Check if the incoming HTTP Request Method/Verb is 'POST'
            $userData = $request->input();

            // Validation (Laravel Validation)    // Manually Creating Validators: https://laravel.com/docs/9.x/validation#manually-creating-validators
            $rules = [
                // Fields/Column Names
                'email'    => 'required|email|exists:users', // 'exists' validation rule in `users` datbase table    // exists:table,column: https://laravel.com/docs/9.x/validation#rule-exists
                'password' => 'required'
            ];

            // Customizing Laravel's default error messages for every [Field with Validation Rule] e.g. the 'required' Validation Rule for the 'name' field    // Customizing The Error Messages: https://laravel.com/docs/9.x/validation#manual-customizing-the-error-messages
            $customMessages = [
                // The SAME last Fields (inside $rules array)
                'email.required'    => 'Your email (field) is required',
                'email.email'       => 'Your email (field) must be a Valid email',
                'email.exists'      => 'Your email does not exist in our database!',

                'password.required' => 'Your password (field) is required'
            ];

            $validator = \Illuminate\Support\Facades\Validator::make($userData, $rules, $customMessages);

            if ($validator->fails()) {
                return response()->json($validator->errors(), 422);       
 
            }

            // Fetch/Get the submitted user record (their `users` table row) from `users` table based on the submitted `email` in order to verify the submitted `password`
            $userDetails = User::where('email', $userData['email'])->first();

            // Verify the submitted Password (compare the submitted password (N.B. It gets hashed before comparing by password_verify() function) with the "hashed" `password` in `users` table). If both the submitted password and the user's password in the database table match, we generate a new Access Token for the user to use and send it with all their subsequent HTTP Requests, and update `access_token` column in `users` table with that new Access Token (we replace the old one with the new one)
            if (password_verify($userData['password'], $userDetails->password)) {
                // Generate a new Access Token for the user to use and send it with all their subsequent HTTP Requests
                $accessToken = \Illuminate\Support\Str::random(60); // Str::random(): https://laravel.com/docs/9.x/helpers#method-str-random

                // Update `access_token` column in `users` table with the new Access Token (We replace the old one with the new one)
                User::where('email', $userData['email'])->update(['access_token' => $accessToken]);


                // Send back the newly submitted user data of the successful operation to the user again! (Note: This a well-known convention of APIs to send back the successful accepted data!)    
                return response()->json([ // Note: $user is AUTOMATICALLY converted from Laravel/PHP object to JSON! But we'll manually convert it to JSON using    return response()->json()    to show the "users" JSON property key/name in the response! Try the TWO cases and check the difference in Postman in "Pretty" tab!    // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                    'status'  => true,
                    'message' => 'User logged in successfully!',
                    'token'   => $accessToken
                ], 201);  // 201 HTTP Status Code: Created    // With POST requests, 201 Created HTTP Status Code is sent with the HTTP Response        

            } else { // if the submitted Password (to log in) is incorrect
                return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                    'status'  => false,
                    'message' => 'Password is incorrect!'
                ], 422); // 422 HTTP Status Code: Unprocessable Content            
            }

        } else { // if the user is using the wrong dedicated HTTP Request Method/Verb for their request (i.e. User has used an HTTP Request Method/Verb other than 'POST')

            $message = 'You\'re using an incorrect/invalid HTTP Request Method/Verb to access this route/endpoint in our API!';

            return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                'status'  => false,
                'message' => $message
            ], 422); // 422 HTTP Status Code: Unprocessable Content        

        }
    }

    // Log out a user and Delete their current Access Token (POST)    // API Endpoint:    POST http://127.0.0.1:8000/api/logout-user    // Whenever a new user registers a new account using our Registration API Endpoint, we'll generate an Access Token for them to use and send with all their subsequent HTTP Requests (and will store it in the `access_token` column in `users` table). Note: Whenever the user logs in, we'll generate a new Access Token (that acts the same as a browser Session (i.e. Both Session and Access Token are sent from the client to the server with EVERY HTTP Request), except the fact that there's no browser Session here!) that will replace the old one in the `access_token` column in `users` table. This token will be valid only till the user logs out and then expires (by deleting it from the `access_token` column in the `users` database table when the user logs out)    // User must send an "Authorization" HTTP Header with all their subsequent HTTP Requests with the value of the "Bearer" Accesss Token that they received in the HTTP Response when they first logged in or when they first registered their brand-new account. The "Bearer" Access Token should be sent in the following form:    "Bearer xxxxxxxxxxxxxxxxxx"    where xxxxxxxxxxxxxxxxxx is the "Bearer" Access Token value.    // Note: In Postman, JSON data are submitted using Curly Braces {} and an "ids" Wrapping Object and Square Brackets [])    // No fields must be submitted by the user (from Postman) here! That's because the user will be identified through their Access Token sent (as 'Authorization' HTTP Header) with their HTTP Request to the server. Note: Data can be posted/sent/submitted in Postman using a GET/POST/PUT/PATCH/DELETE request using TWO ways: First: "form-data" (resembles the HTML Form <input> fields (key/value pairs) and their "name" and "value" <input> HTML tag attributes, and you can retrieve those data in the backend using the Superglobals $_POST and $_FILES), Second: "raw" (through which you can decide the data type of the whole HTTP Request Body (e.g. JSON, HTML, ...etc), and you can retrieve those data in the backend using, for example if data were JSON, json_decode() function and then access the JSON key/value pairs as follows:    $jsonImageAttributes->filename    )    
    public function logoutUser(Request $request) {
        if ($request->isMethod('post')) { // Check if the incoming HTTP Request Method/Verb is 'POST'
            $api_token = $request->header('Authorization'); // Get the 'Authorization' HTTP Header sent from the user's client to the server with their HTTP Request    // Request Headers: https://laravel.com/docs/9.x/requests#request-headers
            // dd($api_token);

            if (empty($api_token)) { // if the user didn't send the 'Authorization' HTTP Header with their HTTP Request at all
                return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                    'status'  => false,
                    'message' => '\'Authorization\' HTTP Request Header value (i.e. Bearer Access Token) is missing!'
                ], 422); // 422 HTTP Status Code: Unprocessable Content            

            } else { // if the user sent the 'Authorization' HTTP Header (i.e. the Bearer Access Token) with their HTTP Request

                // Check if the submitted 'Authorization' HTTP Header value (i.e. the Bearer Access Token) exists in `users` database table
                // Remove the 'Bearer ' portion of the string of the Bearer Access token value of the 'Authorization' HTTP Header (as the 'Authorization' HTTP Header is sent in the form of:    'Bearer xxxxxxxxxxxxxxxxxxxxxx' e.g.    'Bearer K7qq9PZyRg6ieKGEKhZolGC0vJWLw8iEJ88DRdyEp'    )
                $api_token = str_replace('Bearer ', '', $api_token);    // using str_replace() function
                // dd($api_token);

                $api_token_count = User::where('access_token', $api_token)->count();
                // dd($api_token_Count);
                if ($api_token_count > 0) { // if the submitted 'Authorization' HTTP Header value (i.e. the Bearer Access Token) exists in the `access_token` column in `users` database table, delete (not delete exactly!, just UPDATE the column value to 'null') it to expire the Access Token, so that the user can no longer use it to access their account
                    User::where('access_token', $api_token)->update(['access_token' => null]);

                    // Send back the newly submitted user data of the successful operation to the user again! (Note: This a well-known convention of APIs to send back the successful accepted data!)    
                    return response()->json([ // Note: $user is AUTOMATICALLY converted from Laravel/PHP object to JSON! But we'll manually convert it to JSON using    return response()->json()    to show the "users" JSON property key/name in the response! Try the TWO cases and check the difference in Postman in "Pretty" tab!    // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                        'status'  => true,
                        'message' => 'User logged out successfully!',
                    ], 200); // 200 HTTP Status Code: OK            

                } else { // if the submitted 'Authorization' HTTP Header value (i.e. the Bearer Access Token) doesn't exist in the `access_token` column in `users` database table
                    return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                        'status'  => false,
                        'message' => 'Your submitted \'Authorization\' HTTP Request Header value (i.e. the Bearer Access Token) does not exist in our database!'
                    ], 422); // 422 HTTP Status Code: Unprocessable Content                
                }

            }

        } else { // if the user is using the wrong dedicated HTTP Request Method/Verb for their request (i.e. User has used an HTTP Request Method/Verb other than 'POST')

            $message = 'You\'re using an incorrect/invalid HTTP Request Method/Verb to access this route/endpoint in our API!';

            return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                'status'  => false,
                'message' => $message
            ], 422); // 422 HTTP Status Code: Unprocessable Content        

        }
    }



    // API Endpoints/Routes using "Laravel Passport" package Authentication:

    // Register a new user and Generate a new Access Token for them Using "Passport" (POST)    // API Endpoint:    POST http://127.0.0.1:8000/api/register-user-with-passport    // Whenever a new user registers a new account using our Registration API Endpoint, we'll generate an Access Token for them to use and send with all their subsequent HTTP Requests (and will store it in the `api_token` column in `users` table). Note: Whenever the user logs in, we'll generate a new Access Token (that acts the same as a browser Session (i.e. Both Session and Access Token are sent from the client to the server with EVERY HTTP Request), except the fact that there's no browser Session here!) that will replace the old one in the `api_token` column in `users` table. This token will be valid only till the user logs out and then expires (by deleting it from the `api_token` column in the `users` database table when the user logs out)    // User can use the new Access Token that gets generated wheny they register a new account with all their subsequent HTTP Requests    // Note: In Postman, JSON data are submitted using Curly Braces {} and an "ids" Wrapping Object and Square Brackets [])    // 'name', 'email' and 'password' fields must be submitted by the user (from Postman). Note: Data can be posted/sent/submitted in Postman using a GET/POST/PUT/PATCH/DELETE request using TWO ways: First: "form-data" (resembles the HTML Form <input> fields (key/value pairs) and their "name" and "value" <input> HTML tag attributes, and you can retrieve those data in the backend using the Superglobals $_POST and $_FILES), Second: "raw" (through which you can decide the data type of the whole HTTP Request Body (e.g. JSON, HTML, ...etc), and you can retrieve those data in the backend using, for example if data were JSON, json_decode() function and then access the JSON key/value pairs as follows:    $jsonImageAttributes->filename    )    
    public function registerUserWithPassport(Request $request) {
        if ($request->isMethod('post')) { // Check if the incoming HTTP Request Method/Verb is 'POST'
            $userData = $request->input();

            // Validation (Laravel Validation)    // Manually Creating Validators: https://laravel.com/docs/9.x/validation#manually-creating-validators
            $rules = [
                // Fields/Column Names
                'name'     => 'required|regex:/^[\pL\s\-]+$/u', // regex:pattern: https://laravel.com/docs/9.x/validation#rule-regex
                'email'    => 'required|email|unique:users', // 'unique' validation rule in `users` datbase table    // unique:table,column: https://laravel.com/docs/9.x/validation#rule-unique
                'password' => 'required'
            ];

            // Customizing Laravel's default error messages for every [Field with Validation Rule] e.g. the 'required' Validation Rule for the 'name' field    // Customizing The Error Messages: https://laravel.com/docs/9.x/validation#manual-customizing-the-error-messages
            $customMessages = [
                // The SAME last Fields (inside $rules array)
                'name.required'     => 'Your Name (field) is required',

                'email.required'    => 'Your email (field) is required',
                'email.email'       => 'Your email (field) must be a Valid email',
                'email.unique'      => 'Your email already exists in our database!',

                'password.required' => 'Your password (field) is required'
            ];

            $validator = \Illuminate\Support\Facades\Validator::make($userData, $rules, $customMessages);

            if ($validator->fails()) {
                return response()->json($validator->errors(), 422);       
 
            }

            // Generate a new Access Token for the newly registered user, and save it in the `access_token` column in `users` table (and overwrite/override/replace the old Access Token in `access_token` column if there is any!)
            // $accessToken = \Illuminate\Support\Str::random(60); // Str::random(): https://laravel.com/docs/9.x/helpers#method-str-random

            

            // Register the new user i.e. Save the submitted user data (name, email and password) along with the newly generated API Access Token in `users` table
            $user = new User;

            $user->name     = $userData['name'];
            $user->email    = $userData['email'];
            $user->password = bcrypt($userData['password']); // Hash the password before saving it in the database table

            // $user->api_token = $apiToken;
            // $user->access_token = $accessToken;

            $user->save();



            // Authenticate the user / log in the user / log the user in    // Manually Authenticating Users: https://laravel.com/docs/9.x/authentication#authenticating-users
            if (\Illuminate\Support\Facades\Auth::attempt(['email' => $userData['email'], 'password' => $userData['password']])) {
                $user = User::where('email', $userData['email'])->first();
                // dd($user);

                // Generate a new Access Token using "Laravel Passport" Package for the newly registered user, and save it in the `access_token` column in `users` table (and overwrite/override/replace the old Access Token in `access_token` column if there is any!)
                $accessToken = $user->createToken($userData['email'])->accessToken; // Utilizing the HasApiTokens trait we're using in the User.php model    // Managing Personal Access Tokens: https://laravel.com/docs/9.x/passport#managing-personal-access-tokens
                // dd($accessToken);

                // UPDATE the `access_token` column in `users` table with the new $accessToken value (which is generated using "Laravel Passport" package)
                User::where('email', $userData['email'])->update(['access_token' => $accessToken]);

                // Send back the newly submitted user data of the successful operation to the user again! (Note: This a well-known convention of APIs to send back the successful accepted data!)    
                return response()->json([ // Note: $user is AUTOMATICALLY converted from Laravel/PHP object to JSON! But we'll manually convert it to JSON using    return response()->json()    to show the "users" JSON property key/name in the response! Try the TWO cases and check the difference in Postman in "Pretty" tab!    // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                    'status'  => true,
                    'message' => 'User registered successfully! (using Passport)',
                    // 'token'   => $apiToken,
                    'token'   => $accessToken,
                    'user'    => $user
                ], 201);  // 201 HTTP Status Code: Created    // With POST requests, 201 Created HTTP Status Code is sent with the HTTP Response        
            
            } else { // if the user fails authentication/logging in (enters wrong email or password)
                return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                    'status'  => false,
                    'message' => 'Wrong credentials! Incorrect email or password!'
                ], 422); // 422 HTTP Status Code: Unprocessable Content            
            }

        } else { // if the user is using the wrong dedicated HTTP Request Method/Verb for their request (i.e. User has used an HTTP Request Method/Verb other than 'POST')
            $message = 'You\'re using an incorrect/invalid HTTP Request Method/Verb to access this route/endpoint in our API!';
            return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                'status'  => false,
                'message' => $message
            ], 422); // 422 HTTP Status Code: Unprocessable Content        
        }
    }

    // Log in a user and Generate a new Access Token for them Using "Passport" (POST)    // API Endpoint:    POST http://127.0.0.1:8000/api/login-user-with-passport    // Whenever a new user registers a new account using our Registration API Endpoint, we'll generate an Access Token for them to use and send with all their subsequent HTTP Requests (and will store it in the `api_token` column in `users` table). Note: Whenever the user logs in, we'll generate a new Access Token (that acts the same as a browser Session (i.e. Both Session and Access Token are sent from the client to the server with EVERY HTTP Request), except the fact that there's no browser Session here!) that will replace the old one in the `api_token` column in `users` table. This token will be valid only till the user logs out and then expires (by deleting it from the `api_token` column in the `users` database table when the user logs out)    // User must send an "Authorization" HTTP Header with all their subsequent HTTP Requests with the value of the "Bearer" Accesss Token that they received in the HTTP Response when they first logged in or when they first registered their brand-new account. The "Bearer" Access Token should be sent in the following form:    "Bearer xxxxxxxxxxxxxxxxxx"    where xxxxxxxxxxxxxxxxxx is the "Bearer" Access Token value.    // Note: In Postman, JSON data are submitted using Curly Braces {} and an "ids" Wrapping Object and Square Brackets [])    // 'email' and 'password' fields must be submitted by the user (from Postman). Note: Data can be posted/sent/submitted in Postman using a GET/POST/PUT/PATCH/DELETE request using TWO ways: First: "form-data" (resembles the HTML Form <input> fields (key/value pairs) and their "name" and "value" <input> HTML tag attributes, and you can retrieve those data in the backend using the Superglobals $_POST and $_FILES), Second: "raw" (through which you can decide the data type of the whole HTTP Request Body (e.g. JSON, HTML, ...etc), and you can retrieve those data in the backend using, for example if data were JSON, json_decode() function and then access the JSON key/value pairs as follows:    $jsonImageAttributes->filename    )    
    public function loginUserWithPassport(Request $request) {
        if ($request->isMethod('post')) { // Check if the incoming HTTP Request Method/Verb is 'POST'
            $userData = $request->input();

            // Validation (Laravel Validation)    // Manually Creating Validators: https://laravel.com/docs/9.x/validation#manually-creating-validators
            $rules = [
                // Fields/Column Names
                'email'    => 'required|email|exists:users', // 'exists' validation rule in `users` datbase table    // exists:table,column: https://laravel.com/docs/9.x/validation#rule-exists
                'password' => 'required'
            ];

            // Customizing Laravel's default error messages for every [Field with Validation Rule] e.g. the 'required' Validation Rule for the 'name' field    // Customizing The Error Messages: https://laravel.com/docs/9.x/validation#manual-customizing-the-error-messages
            $customMessages = [
                // The SAME last Fields (inside $rules array)
                'email.required'    => 'Your email (field) is required',
                'email.email'       => 'Your email (field) must be a Valid email',
                'email.exists'      => 'Your email does not exist in our database!',

                'password.required' => 'Your password (field) is required'
            ];
            
            $validator = \Illuminate\Support\Facades\Validator::make($userData, $rules, $customMessages);

            if ($validator->fails()) {
                return response()->json($validator->errors(), 422);       
 
            }


            // Authenticate the user / log in the user / log the user in    // Manually Authenticating Users: https://laravel.com/docs/9.x/authentication#authenticating-users
            if (\Illuminate\Support\Facades\Auth::attempt(['email' => $userData['email'], 'password' => $userData['password']])) {
                $user = User::where('email', $userData['email'])->first();
                // dd($user);


                // Generate a new Access Token using "Laravel Passport" Package for the newly registered user, and save it in the `access_token` column in `users` table (and overwrite/override/replace the old Access Token in `access_token` column if there is any!)
                $accessToken = $user->createToken($userData['email'])->accessToken; // Utilizing the HasApiTokens trait we're using in the User.php model    // Managing Personal Access Tokens: https://laravel.com/docs/9.x/passport#managing-personal-access-tokens
                // dd($accessToken);

                // UPDATE the `access_token` column in `users` table with the new $accessToken value (which is generated using "Laravel Passport" package)
                User::where('email', $userData['email'])->update(['access_token' => $accessToken]);


                // Send back the newly submitted user data of the successful operation to the user again! (Note: This a well-known convention of APIs to send back the successful accepted data!)    
                return response()->json([ // Note: $user is AUTOMATICALLY converted from Laravel/PHP object to JSON! But we'll manually convert it to JSON using    return response()->json()    to show the "users" JSON property key/name in the response! Try the TWO cases and check the difference in Postman in "Pretty" tab!    // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                    'status'  => true,
                    'message' => 'User logged in successfully! (using Passport)',
                    'token'   => $accessToken,
                    'user'    => $user
                ], 201);  // 201 HTTP Status Code: Created    // With POST requests, 201 Created HTTP Status Code is sent with the HTTP Response        
            
            } else { // if the user fails authentication/logging in (enters wrong email or password)
                return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                    'status'  => false,
                    'message' => 'Wrong credentials! Incorrect email or password!'
                ], 422); // 422 HTTP Status Code: Unprocessable Content            
            }

        } else { // if the user is using the wrong dedicated HTTP Request Method/Verb for their request (i.e. User has used an HTTP Request Method/Verb other than 'POST')
            $message = 'You\'re using an incorrect/invalid HTTP Request Method/Verb to access this route/endpoint in our API!';
            return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                'status'  => false,
                'message' => $message
            ], 422); // 422 HTTP Status Code: Unprocessable Content        
        }
    }



    // Update the stock via a third-party API / 3rd-party API (an inventory/stock management system like Uniware Cloud Inventory Control, ...) (using cURL) (POST)    // Here, we're using a third party to handle our stock/inventory management i.e. we don't handle our stock/inventory management ourselves    // API Endpoint:    POST http://127.0.0.1:8000/api/update-stock    // The user must send this 'Authorization' HTTP Header value i.e. Bearer Access Token with their HTTP Request: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFtaXQgR3VwdGEiLCJpYXQiOjE1MTYyMzkwMjJ9.cNrgi6Sso9wvs4GlJmFnA4IqJY4o2QEcKXgshJTjfNg'    
    public function updateStock(Request $request) {
        if ($request->isMethod('post')) { // Check if the incoming HTTP Request Method/Verb is 'POST'
            $userData = $request->input();

            // Checking for the 'Authorization' HTTP Header value i.e. Bearer Access Token
            $header = $request->header('Authorization'); // Get the 'Authorization' HTTP Header sent from the user's client to the server with their HTTP Request    // Request Headers: https://laravel.com/docs/9.x/requests#request-headers
            // dd($header);

            // Check if the user sends the 'Authorization' HTTP Request Header or not with their HTTP Request (Check if the 'Authorization' Header is provided)
            if (empty($header)) { // if the user doesn't provide/send the 'Authorization' HTTP Header with their HTTP Request
                $message = '\'Authorization\' HTTP Request Header value (i.e. Bearer Access Token) is missing!';
                return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                    'status'  => false,
                    'message' => $message
                ], 422); // 422 HTTP Status Code: Unprocessable Content        

            } else { // if the user provides/sends the 'Authorization' HTTP Request Header with their HTTP Request

                // Check if the 'Authorization' HTTP Request Header is correct
                if ($header == 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFtaXQgR3VwdGEiLCJpYXQiOjE1MTYyMzkwMjJ9.cNrgi6Sso9wvs4GlJmFnA4IqJY4o2QEcKXgshJTjfNg') { // if the user sends the correct HTTP Request Header value (i.e. correct Bearer Access Token) with their HTTP Request    // JWT token generated by (we wrote in "Ahmed Yahya" to generate this token in the website): https://jwt.io/    // User must send an "Authorization" HTTP Header with all their HTTP Requests with this value (Bearer Token (JWT)): "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFtaXQgR3VwdGEiLCJpYXQiOjE1MTYyMzkwMjJ9.cNrgi6Sso9wvs4GlJmFnA4IqJY4o2QEcKXgshJTjfNg"

                    $url = 'http://sitemakers.in/stocks.json'; // Supposing that this is the third-party API endpoint of the Stock/Inventory Management System (like Uniware, ...) that runs our website stock/inventory management
                    $curl = curl_init(); // Initialize a cURL session (The cURL Handle)

                    curl_setopt_array($curl, [ // Set multiple options for a cURL transfer    // Instead of using curl_setopt_array() function, you can use curl_setopt() function multiple times
                        CURLOPT_URL            => $url, // The URL to fetch. This can also be set when initializing a session with curl_init()
                        CURLOPT_RETURNTRANSFER => true, // true (i.e. 1) to return the transfer as a string of the return value of curl_exec() instead of outputting it directly
                        CURLOPT_HEADER         => false // true (i.e. 1) to include the header in the output
                    ]);

                    $data = curl_exec($curl); // The JSON HTTP Response of the server for our HTTP request    // Perform a cURL session

                    curl_close($curl); // Close a cURL session

                    $data = json_decode($data, true); // Convert the server HTTP Response from JSON to PHP array    // https://www.php.net/manual/en/function.json-decode.php#:~:text=RFC%207159.-,associative,-When%20true%2C%20JSON

                    if (isset($data['items'])) { // if    $data['items']    has returned from the server HTTP Response
                        foreach ($data['items'] as $key => $value) {
                            // Update the `stock` column in our `products_attributes` database table
                            ProductsAttribute::where('sku', $value['sku'])->update([ 'stock' => $value['stock'] ]);
                        }

                        // Send a stock update success/confirmation JSON HTTP Response
                        return response()->json([ // Note: $user is AUTOMATICALLY converted from Laravel/PHP object to JSON! But we'll manually convert it to JSON using    return response()->json()    to show the "users" JSON property key/name in the response! Try the TWO cases and check the difference in Postman in "Pretty" tab!    // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                            'status'  => true,
                            'message' => 'Products stocks updated successfully!',
                        ], 200); // 200 HTTP Status Code: OK            
                    } else { // if    $data['items']    hasn't returned from the server HTTP Response
                        return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                            'status'  => false,
                            'message' => 'No items found!'
                        ], 422); // 422 HTTP Status Code: Unprocessable Content        
                    }

                } else { // if the user sends an inccorrect HTTP Request Header value (i.e. incorrect Bearer Access Token) with their HTTP Request
                    return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                        'status'  => false,
                        'message' => 'Your submitted \'Authorization\' HTTP Request Header value (i.e. the Bearer Access Token) is incorrect!'
                    ], 422); // 422 HTTP Status Code: Unprocessable Content        
                }

            }

        } else { // if the user is using the wrong dedicated HTTP Request Method/Verb for their request (i.e. User has used an HTTP Request Method/Verb other than 'POST')
            $message = 'You\'re using an incorrect/invalid HTTP Request Method/Verb to access this route/endpoint in our API!';
            return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                'status'  => false,
                'message' => $message
            ], 422); // 422 HTTP Status Code: Unprocessable Content        
        }
    }

    // Webhook: Update the stock by giving this API endpoint to a third-party inventory/stock management system (like Uniware Cloud Inventory Control, ...) to access to update our stock (POST)    // Here, the third-party stock/inventory management system (Webhook) accesses our API endpoint only when there's a stock update on their end (the stock/inventory management system's end) to update our stock on our end in our database    // API Endpoint:    POST http://127.0.0.1:8000/api/update-stock-with-webhook    // The user must send this 'Authorization' HTTP Header value i.e. Bearer Access Token with their HTTP Request: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFtaXQgR3VwdGEiLCJpYXQiOjE1MTYyMzkwMjJ9.cNrgi6Sso9wvs4GlJmFnA4IqJY4o2QEcKXgshJTjfNg'    
    public function updateStockWithWebhook(Request $request) {
        if ($request->isMethod('post')) { // Check if the incoming HTTP Request Method/Verb is 'POST'

            // Checking for the 'Authorization' HTTP Header value i.e. Bearer Access Token
            $header = $request->header('Authorization'); // Get the 'Authorization' HTTP Header sent from the user's client to the server with their HTTP Request    // Request Headers: https://laravel.com/docs/9.x/requests#request-headers
            // dd($header);

            // Check if the user sends the 'Authorization' HTTP Request Header or not with their HTTP Request (Check if the 'Authorization' Header is provided)
            if (empty($header)) { // if the user doesn't provide/send the 'Authorization' HTTP Header with their HTTP Request
                $message = '\'Authorization\' HTTP Request Header value (i.e. Bearer Access Token) is missing!';
                return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                    'status'  => false,
                    'message' => $message
                ], 422); // 422 HTTP Status Code: Unprocessable Content        

            } else { // if the user provides/sends the 'Authorization' HTTP Request Header with their HTTP Request

                // Check if the 'Authorization' HTTP Request Header is correct
                if ($header == 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFtaXQgR3VwdGEiLCJpYXQiOjE1MTYyMzkwMjJ9.cNrgi6Sso9wvs4GlJmFnA4IqJY4o2QEcKXgshJTjfNg') { // if the user sends the correct HTTP Request Header value (i.e. correct Bearer Access Token) with their HTTP Request    // JWT token generated by (we wrote in "Ahmed Yahya" to generate this token in the website): https://jwt.io/    // User must send an "Authorization" HTTP Header with all their HTTP Requests with this value (Bearer Token (JWT)): "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFtaXQgR3VwdGEiLCJpYXQiOjE1MTYyMzkwMjJ9.cNrgi6Sso9wvs4GlJmFnA4IqJY4o2QEcKXgshJTjfNg"
                    $data = $request->all();

                    if (isset($data['items'])) { // if    $data['items']    has returned from the server HTTP Response
                        foreach ($data['items'] as $key => $value) {
                            // Update the `stock` column in our `products_attributes` database table
                            ProductsAttribute::where('sku', $value['sku'])->update([ 'stock' => $value['stock'] ]);
                        }

                        // Send a stock update success/confirmation JSON HTTP Response
                        return response()->json([ // Note: $user is AUTOMATICALLY converted from Laravel/PHP object to JSON! But we'll manually convert it to JSON using    return response()->json()    to show the "users" JSON property key/name in the response! Try the TWO cases and check the difference in Postman in "Pretty" tab!    // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                            'status'  => true,
                            'message' => 'Products stocks updated successfully! (through/via Webhook)',
                        ], 200); // 200 HTTP Status Code: OK            

                    } else { // if    $data['items']    hasn't returned from the server HTTP Response
                        return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                            'status'  => false,
                            'message' => 'No items found!'
                        ], 422); // 422 HTTP Status Code: Unprocessable Content        
                    }

                } else { // if the user sends an inccorrect HTTP Request Header value (i.e. incorrect Bearer Access Token) with their HTTP Request
                    return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                        'status'  => false,
                        'message' => 'Your submitted \'Authorization\' HTTP Request Header value (i.e. the Bearer Access Token) is incorrect!'
                    ], 422); // 422 HTTP Status Code: Unprocessable Content        
                }

            }

        } else { // if the user is using the wrong dedicated HTTP Request Method/Verb for their request (i.e. User has used an HTTP Request Method/Verb other than 'POST')
            $message = 'You\'re using an incorrect/invalid HTTP Request Method/Verb to access this route/endpoint in our API!';
            return response()->json([ // JSON Responses: https://laravel.com/docs/9.x/responses#json-responses
                'status'  => false,
                'message' => $message
            ], 422); // 422 HTTP Status Code: Unprocessable Content        
        }
    }

}