<?php

declare(strict_types=1);

namespace App\Models;

use App\Helpers\FileHandler;
use App\Lib\Database;
use App\Models\{UserSession, Menu, Dish, Customizations, Cuisine, Discount};
use App\Util\{Helper, DeviceManager, JWTManager};
use WebPConvert\WebPConvert;
use Overtrue\Socialite\SocialiteManager;

class Restaurant
{
    protected $db;
    private string $tableName = 'restaurant';
    protected DeviceManager $deviceManager;
    protected Helper $helper;
    public static $uploadDirectory = UPLOADS['public_dir'] . '/restaurant';
    public static $publicDirectory = UPLOADS['public'] . '/restaurant';
    public static $defaultImages = 'images/';
    public static $compressedImages = 'compressed-images/';

    public function __construct()
    {
        $this->db = Database::connectDB();
        $this->helper = new Helper;
    }

    public function getDishUpload(string $email, string $fileName, bool $isPublic = false): string
    {
        $directory = $isPublic ? $this::$publicDirectory : $this::$uploadDirectory;
        $webpName = $this->getWebpName($fileName);
        $defaultImage = $this::$uploadDirectory . "/{$email}/" . $this::$defaultImages . 'dish/' . $fileName;
        $compressedImage = $this::$uploadDirectory . "/{$email}/" . $this::$compressedImages . 'dish/' . $webpName;

        $viewDefaultImage = $directory . "/{$email}/" . $this::$defaultImages . 'dish/' . $fileName;
        $viewCompressedImage = $directory . "/{$email}/" . $this::$compressedImages . 'dish/' . $webpName;

        if(Helper::isFileExists($compressedImage)){
            return $viewCompressedImage;
        }
        if(Helper::isFileExists($defaultImage)){
            return $viewDefaultImage;
        }
        return $fileName;
    }

    public function getCustomizedDishUpload(string $email, string $fileName, bool $isPublic = false): string
    {
        $directory = $isPublic == true ? $this::$publicDirectory : $this::$uploadDirectory;
        $webpName = $this->getWebpName($fileName);
        $defaultImage = $this::$uploadDirectory . "/{$email}/" . $this::$defaultImages . 'side-item/' . $fileName;
        $compressedImage = $this::$uploadDirectory . "/{$email}/" . $this::$compressedImages . 'side-item/' . $webpName;

        $viewDefaultImage = $directory . "/{$email}/" . $this::$defaultImages . 'side-item/' . $fileName;
        $viewCompressedImage = $directory . "/{$email}/" . $this::$compressedImages . 'side-item/' . $webpName;

        if(Helper::isFileExists($compressedImage)){
            return $viewCompressedImage;
        }
        if(Helper::isFileExists($defaultImage)){
            return  $viewDefaultImage;
        }
        return $fileName;
    }

    public function getWebpName(string $fileName): string
    {
        $name = Helper::replaceStrings($fileName, ['.jpg', '.JPG', '.jpeg', '.JPEG', '.png', '.PNG'], '.webp');
        return $name;
    }

    public function isSupportOnlinePayment(string $country)
    {
        $stripe = [];
        $razorPay = ['India'];
        // check if $country is found in any of the arrays
        return in_array($country, $stripe) || in_array($country, $razorPay);
    }

    public function getById(int $partnerId, string $selector = '*')
    {
        $stmt = $this->db->fetch("SELECT {$selector} FROM {$this->tableName} WHERE id = ? LIMIT 1", $partnerId);
        return $stmt;
    }

    public function getBySlug(string $partnerSlug, string $selector = '*')
    {
        $stmt = $this->db->fetch("SELECT {$selector} FROM {$this->tableName} WHERE restaurant_slug = ? LIMIT 1", $partnerSlug);
        return $stmt;
    }

    public function getByEmail(string $partnerEmail, string $selector = '*')
    {
        $stmt = $this->db->fetch("SELECT {$selector} FROM {$this->tableName} WHERE restaurant_email = ? LIMIT 1", $partnerEmail);
        return $stmt;
    }

    public function getAll(string $selector = '*'): array
    {
        $query = "SELECT {$selector} FROM {$this->tableName} ORDER BY created_at";
        $stmt = $this->db->fetchAll($query);
        return $stmt;
    }

    public function hasEmail(string $email): int|bool
    {
        $stmt = $this->db->query("SELECT restaurant_email FROM {$this->tableName} WHERE restaurant_email = ? LIMIT 1", $email);
        return $stmt->rowCount() ?? false;
    }

    public function hasName(string $name): int|bool
    {
        $stmt = $this->db->query("SELECT restaurant_name FROM {$this->tableName} WHERE restaurant_name LIKE '{$name}'");
        return $stmt->rowCount() ?? false;
    }

    public function hasSlug(string $slug): int|bool
    {
        $stmt = $this->db->query("SELECT restaurant_slug FROM {$this->tableName} WHERE restaurant_slug = ?", $slug);
        return $stmt->rowCount() ?? false;
    }

    public function getImage(int $partnerId, string $type = 'header')
    {
        $stmt = $this->db->fetch("SELECT image_file FROM {$this->tableName}_image WHERE image_type = '{$type}' AND restaurant_id = ? LIMIT 1", $partnerId);
        return $stmt;
    }

    public function getBank(int $partnerId, string $selection = '*')
    {
        $stmt = $this->db->fetch("SELECT {$selection} FROM {$this->tableName}_bank WHERE restaurant_id = ? LIMIT 1", $partnerId);
        return $stmt;
    }

    public function getSettings(int $partnerId, string $selection = '*')
    {
        $stmt = $this->db->fetch("SELECT {$selection} FROM {$this->tableName}_setting WHERE restaurant_id = ? LIMIT 1", $partnerId);
        return $stmt;
    }

    public function getCharges(int $partnerId, string $selection = '*')
    {
        $stmt = $this->db->fetch("SELECT {$selection} FROM {$this->tableName}_charges WHERE restaurant_id = ? LIMIT 1", $partnerId);
        return $stmt;
    }

    public function getWorkingHours(int $partnerId, string $selection = '*')
    {
        $stmt = $this->db->fetch("SELECT {$selection} FROM {$this->tableName}_hours WHERE restaurant_id = ? LIMIT 1", $partnerId);
        return $stmt;
    }

    public function getPaymentRequest(int $restaurantId)
    {
        $stmt = $this->db->fetch("SELECT * FROM restaurant_payment_request WHERE restaurant_id = ? LIMIT 1", $restaurantId);
        return $stmt;
    }

    public function hasBankAccount(int $restaurant_id): bool
    {
        $stmt = $this->db->query("SELECT bank_id FROM restaurant_bank WHERE restaurant_id = ? LIMIT 1", $restaurant_id);
        return $stmt->rowCount() > 0 ?? false;
    }

    /////////////// ONBOARDING SETTINGS ////////////////////////

    public function isOnboardingCompleted(int $businessId)
    {
        $stmt = $this->db->query("SELECT restaurant_wizard FROM {$this->tableName} WHERE id = ? and restaurant_wizard = ?", $businessId, 'complete');
        return $stmt->rowCount() > 0 ? true : false;
    }

    public function onboardingFirst(int $businessId, string $businessName, string $businessType)
    {
        $restaurantData = $this->getById($businessId);
        if (empty($restaurantData)) {
            return ["status" => false, "message" => "Sorry, restaurant not found."];
        }

        if (empty($businessName)) {
            return ["status" => false, "message" => "Please provide your business name."];
        }

        if (empty($businessType)) {
            return ["status" => false, "message" => "Please provide the type of business you run."];
        }

        if ($this->hasName($businessName)) {
            return ["status" => false, "message" => "Sorry, but this restaurant name has already been used."];
        }

        $result = $this->db->transaction(function ($database) use ($businessId, $businessName, $businessType) {

            $restaurantSlug = Helper::slugify($businessName);

            $this->setProfile('restaurant_name', $businessName, $businessId);
            $this->setProfile('restaurant_type', $businessType, $businessId);
            $this->setProfile('restaurant_slug', $restaurantSlug, $businessId);
            $this->setProfile('restaurant_wizard', '2', $businessId);
            return true;
        });

        if ($result) {
            return [
                "status" => true,
                "message" => "Step 1 onboarding completed.",
                "next_step" => 2,
            ];
        }
    }

    public function onboardingSecond(int $businessId, array $workingHours)
    {
        $restaurantData = $this->getById($businessId);
        if (empty($restaurantData)) {
            return ["status" => false, "message" => "Sorry, restaurant not found."];
        }

        if (empty($workingHours)) {
            return ["status" => false, "message" => "Please provide your business working hours."];
        }

        $morningOpening = $workingHours[0]['morning']['openingTime'];
        $morningClosing = $workingHours[0]['morning']['closingTime'];
        $eveningOpening = $workingHours[0]['evening']['openingTime'];
        $eveningClosing = $workingHours[0]['evening']['closingTime'];

        if (empty($morningOpening) || empty($morningClosing)) {
            return ["status" => false, "message" => "Please provide your business morning opening and closing hours."];
        }

        if (empty($eveningOpening) || empty($eveningClosing)) {
            return ["status" => false, "message" => "Please provide your business evening opening and closing hours."];
        }

        $result = $this->db->transaction(function ($database) use ($businessId, $morningOpening, $morningClosing, $eveningOpening, $eveningClosing) {

            if (!$this->hasWorkingHour((int) $businessId)) {
                $database->query("INSERT INTO restaurant_hours", [
                    'hour_id' => NULL,
                    'restaurant_id' => $businessId,
                    'opening_time_morning' => $morningOpening,
                    'closing_time_morning' => $morningClosing,
                    'opening_time_evening' => $eveningOpening,
                    'closing_time_evening' => $eveningClosing
                ]);
            } else {
                $workingHours = [
                    'opening_morning' => $morningOpening,
                    'closing_morning' => $morningClosing,
                    'opening_evening' => $eveningOpening,
                    'closing_evening' => $eveningClosing
                ];

                $this->setWorkingHour($workingHours, $businessId);
            }


            $this->setProfile('restaurant_wizard', '3', $businessId);
            return true;
        });

        if ($result) {
            return [
                "status" => true,
                "message" => "Step 2 onboarding completed.",
                "next_step" => 3,
            ];
        }
    }

    public function onboardingThird(int $businessId, string $phoneNumber, string $whatsApp)
    {
        $restaurantData = $this->getById($businessId);
        if (empty($restaurantData)) {
            return ["status" => false, "message" => "Sorry, restaurant not found."];
        }

        if (empty($phoneNumber)) {
            return ["status" => false, "message" => "Please provide your business phone number."];
        }

        if (empty($whatsApp)) {
            return ["status" => false, "message" => "Please provide your business WhatsApp number."];
        }

        $result = $this->db->transaction(function ($database) use ($businessId, $phoneNumber, $whatsApp) {

            $this->setProfile('restaurant_phone', $phoneNumber, $businessId);
            $this->setProfile('restaurant_whatsapp', $whatsApp, $businessId);
            $this->setProfile('restaurant_wizard', '4', $businessId);
            $database->query("UPDATE {$this->tableName} SET restaurant_phone = ?, restaurant_whatsapp = ?, restaurant_wizard = '4' WHERE id = ?", $phoneNumber, $whatsApp, $businessId);
            return true;
        });

        if ($result) {
            return [
                "status" => true,
                "message" => "Step 3 onboarding completed.",
                "next_step" => 4,
            ];
        }
    }

    public function onboardingLast(int $businessId, $latitude, $longitude)
    {
        $restaurantData = $this->getById($businessId);
        if (empty($restaurantData)) {
            return ["status" => false, "message" => "Sorry, restaurant not found."];
        }

        if (empty($latitude) || empty($longitude)) {
            return ["status" => false, "message" => "Please provide your business location by clicking on the map."];
        }

        $result = $this->db->transaction(function ($database) use ($businessId, $latitude, $longitude) {

            $this->setProfile('restaurant_latitude', $latitude, $businessId);
            $this->setProfile('restaurant_longitude', $longitude, $businessId);
            $this->setProfile('restaurant_status', 'approved', $businessId);
            $this->setProfile('restaurant_wizard', 'complete', $businessId);
            return true;
        });

        if ($result) {
            return [
                "status" => true,
                "message" => "Step 4 onboarding completed.",
                "next_step" => null,
            ];
        }
    }

    ////////////// General Settings ////////////////

    public function setProfile($column, $value, int $restaurant_id)
    {
        $this->db->query("UPDATE restaurant SET {$column} = ? WHERE id = ?", $value, $restaurant_id);
    }

    public function setWorkingHour(array $data, int $restaurant_id): void
    {

        $opening_time_morning = $data['opening_morning'];
        $closing_time_morning = $data['closing_morning'];
        $opening_time_evening = $data['opening_evening'];
        $closing_time_evening = $data['closing_evening'];

        $this->db->query("UPDATE restaurant_hours SET
        opening_time_morning = '{$opening_time_morning}',
        closing_time_morning = '{$closing_time_morning}',
        opening_time_evening = '{$opening_time_evening}',
        closing_time_evening = '{$closing_time_evening}'
        WHERE restaurant_id = ?", $restaurant_id);
    }

    public function hasWorkingHour(int $restaurant_id): bool
    {
        $stmt = $this->db->query("SELECT hour_id FROM restaurant_hours WHERE restaurant_id = ? LIMIT 1", $restaurant_id);
        return $stmt->rowCount() > 0 ?? false;
    }

    public function setBankAccount(array $data, int $restaurant_id): void
    {
        $accountName = $data['account_name'];
        $accountNumber = $data['account_number'];
        $accountBank = $data['account_bank'];
        $accountIFSC = $data['account_ifsc'];

        $this->db->query("UPDATE restaurant_bank SET
        account_name = '{$accountName}',
        account_number = '{$accountNumber}',
        account_bank = '{$accountBank}',
        account_ifsc = '{$accountIFSC}'
        WHERE restaurant_id = ?", $restaurant_id);
    }

    public function addBankAccount(array $data, int $restaurant_id): void
    {
        $accountName = $data['account_name'];
        $accountNumber = $data['account_number'];
        $accountBank = $data['account_bank'];
        $accountIFSC = $data['account_ifsc'];
        $this->db->query(
            "INSERT INTO restaurant_bank",
            [
                "bank_id" => NULL,
                "restaurant_id" => $restaurant_id,
                "account_name" => $accountName,
                "account_number" => $accountNumber,
                "account_bank" => $accountBank,
                "account_ifsc" => $accountIFSC
            ]
        );
    }

    public function setCharges(array $data, int $restaurant_id): void
    {
        $platform_fee_type = $data['platform_fee_type'];
        $vat_fee_type = $data['vat_fee_type'];
        $vat_fee = (float) $data['vat_fee'];

        $this->db->query("UPDATE restaurant_charges SET
        platform_fee_type = '{$platform_fee_type}',
        vat_fee_type = '{$vat_fee_type}',
        vat_fee = {$vat_fee}
        WHERE restaurant_id = ?", $restaurant_id);
    }

    public function setSettings(string $column, $value, int $restaurant_id): void
    {
        $this->db->query("UPDATE restaurant_setting SET {$column} = ? WHERE restaurant_id = ?", $value, $restaurant_id);
    }

    public function addPaymentRequest(string $payment_request, int $restaurant_id): void
    {
        $restaurantData = $this->getById($restaurant_id, 'restaurant_country');
        $this->db->query("INSERT INTO restaurant_payment_request", [
            "payment_request_id" => NULL,
            "restaurant_id" => $restaurant_id,
            "type" => $payment_request,
            "country" => $restaurantData->restaurant_country,
        ]);
    }

    /////////////////////////////////////////// API REFERENCE ///////////////////////////////////////////

    /**
     * Retrieves data based on the given restaurant ID and action.
     *
     * @param int $id The ID of the restaurant.
     * @param string $action The action to perform.
     * @return array
     */
    public function getData(int $id, string $action): array|null
    {
        if (empty($action)) {
            @header("HTTP/1.1 401 Unauthorized");
            return ["status" => false, "message" => "Unauthorized access detected."];
        }

        if (empty($id)) {
            @header("HTTP/1.1 400 Bad Request");
            return ["status" => false, "message" => "Sorry, not restaurant id provided."];
        }

        $restaurantData = $this->getById($id, 'id');
        if(empty($restaurantData)){
            @header("HTTP/1.1 404 Not Found");
            return ["status" => false, "message" => "Sorry, this restaurant was not found."];
        }

        if ($action === 'profile') {
            $restaurantData = $this->getById($id);
            $restaurantDirectory = \UPLOADS['restaurant_dir'];
            $restaurantArray = [
                "id" => $restaurantData->id,
                "uuid" => $restaurantData->restaurant_uuid ?? 0,
                "avatar" => $restaurantDirectory . '/profile/' . $restaurantData->restaurant_avatar,
                "cover" => $restaurantDirectory . '/cover/' . $restaurantData->restaurant_cover,
                "name" => $restaurantData->restaurant_name,
                "owner" => $restaurantData->restaurant_owner,
                "slug" => $restaurantData->restaurant_slug,
                "email" => $restaurantData->restaurant_email,
                "phone" => $restaurantData->restaurant_phone,
                "whatsapp" => $restaurantData->restaurant_whatsapp ?? "",
                "address" => $restaurantData->restaurant_address,
                "currency" => $restaurantData->restaurant_currency,
                "status" => $restaurantData->restaurant_status
            ];

            return $restaurantArray;
        }

        if ($action === 'restaurant-settings') {
            $restaurantSetting = $this->getSettings($id);
            $restaurantHours = $this->getWorkingHours($id);
            $restaurantCharges = $this->getCharges($id);
            $dataArray = [
                "id" => $id,
                "delivery" => [
                    "is_active" => (bool) $restaurantSetting->delivery_allow,
                    "food_preparation_time" => $restaurantSetting->delivery_food_prepare,
                    "delivery_distance" => (float) $restaurantSetting->delivery_distance,
                    "minimum_order_price" => (float) $restaurantSetting->delivery_minimum_order_price
                ],
                "dineIn" => [
                    "is_active" => (bool) $restaurantSetting->dinein_allow,
                    "minimum_order_price" => (float) $restaurantSetting->dinein_minimum_order_price,
                    "dine_in_tables" => $restaurantSetting->dinein_table
                ],
                "takeaway" => [
                    "is_active" => (bool) $restaurantSetting->takeaway_allow,
                    "minimum_order_price" => (float) $restaurantSetting->takeaway_minimum_order_price
                ],
                "openingHour" => [
                    "morning" => ["openingTime" => $restaurantHours->opening_time_morning, "closingTime" => $restaurantHours->closing_time_morning],
                    "evening" => ["openingTime" => $restaurantHours->opening_time_evening, "closingTime" => $restaurantHours->closing_time_evening]
                ],
                "fees" => [
                    "vat_fee" => (float) $restaurantCharges->vat_fee,
                    "vat_fee_type" => $restaurantCharges->vat_fee_type,
                    "platform_fee_type" => $restaurantCharges->platform_fee_type
                ],
                "vegetarian" => (bool) $restaurantSetting->vegetarian_allow,
                "non_vegetarian" => (bool) $restaurantSetting->non_vegetarian_allow
            ];

            return $dataArray;
        }

        if ($action === 'restaurant-cuisine') {
            $cuisine = new Cuisine;
            $query = $cuisine->getCuisineAll($id);
            $dataArray = [];

            foreach($query as $val){
                $dataArray[] = [
                    "id" => $val->cuisine_id,
                    "name" => $val->cuisine_title,
                    "is_active" => (bool) $val->is_exist
                ];
            }

            return ['status' => true, 'data' => $dataArray];
        }

        if ($action === 'restaurant-payment') {
            $restaurantBank = $this->getBank($id);
            $restaurantSetting = $this->getSettings($id, 'allow_online_payment, allow_cash_payment');
            $requestData = $this->getPaymentRequest($id);
            $isRequest = !empty($requestData) ? true : false;

            $dataArray = [
                "id" => $id,
                "request" => $isRequest,
                "online" => [
                    "is_active" => $restaurantSetting->allow_online_payment == 'true' ? true : false,
                    "account_name" => $restaurantBank->account_name ?? '',
                    "account_number" => $restaurantBank->account_number ?? '',
                    "account_ifsc" => $restaurantBank->account_ifsc ?? '',
                    "account_bank" => $restaurantBank->account_bank ?? ''
                ],
                "cash" => [
                    "is_active" => $restaurantSetting->allow_cash_payment == 'true' ? true : false,
                ]
            ];

            Helper::jsonResult($dataArray);
        }

        if ($action === 'restaurant-location') {
            $restaurantData = $this->getById($id, 'restaurant_latitude, restaurant_longitude, restaurant_address');
            $dataArray = [
                "id" => $id,
                "latitude" => $restaurantData->restaurant_latitude,
                "longitude" => $restaurantData->restaurant_longitude,
                "address" => $restaurantData->restaurant_address,
            ];

            return $dataArray;
        }

        if ($action === 'restaurant-region') {
            $restaurantData = $this->getById($id, 'restaurant_country');
            $dataArray = [
                "id" => $id,
                "country" => $restaurantData->restaurant_country ?? '',
            ];

            return $dataArray;
        }

        if (in_array($action, ['daily-discount-dine-in', 'daily-discount-delivery', 'daily-discount-takeaway'])) {
            $discount = new Discount;
            $section = Helper::getPrefixAfterHyphen($action, 'daily-discount-');
            $restaurantDiscount = $discount->getDiscountAll($id, $section);

            $discountArray = [];
            foreach($restaurantDiscount as $val){
                $discountArray[] = [
                    'day' => $val->discount_day,
                    'period' => $val->discount_period,
                    'minimum_amount' => (float) $val->discount_minimum,
                    'percentage' => (float) $val->discount_percent,
                ];
            }

            $dataArray = [
                "id" => $id,
                "discounts" => $discountArray
            ];

            return $dataArray;
        }

        if ($action === 'delivery-discount') {
            $discount = new Discount;
            $restaurantDiscount = $discount->getDeliveryFeeDiscountAll($id);
            $discountArray = [];
            foreach($restaurantDiscount as $val){
                $discountArray[] = [
                    'day' => $val->discount_day,
                    'period' => $val->discount_period,
                    'minimum_amount' => (float) $val->discount_minimum,
                    'percentage' => (float) $val->discount_percent,
                ];
            }

            $dataArray = [
                "id" => $id,
                "discounts" => $discountArray
            ];

            return $dataArray;
        }

        if($action === 'count-menu-dish'){
            $menu = new Menu;
            // get count of both menu and dishes from the database
            $countData = $menu->countAllMenuDishes($id);
            return ['menu' => $countData['menu'], 'dishes' => $countData['dishes']];
        }

        return ["status" => false, "message" => "Sorry, no action was provided."];
    }

    public function getReviews(int $id, string $action):array
    {
        if (empty($action)) {
            @header("HTTP/1.1 401 Unauthorized");
            return ["status" => false, "message" => "Unauthorized access detected."];
        }

        if (empty($id)) {
            @header("HTTP/1.1 400 Bad Request");
            return ["status" => false, "message" => "Sorry, not restaurant id provided."];
        }

        $restaurantData = $this->getById($id, 'id');
        if(empty($restaurantData)){
            @header("HTTP/1.1 404 Not Found");
            return ["status" => false, "message" => "Sorry, this restaurant was not found."];
        }

        $review  = new Reviews;
        $customer = new Customer;

        if($action === 'count'){
            $countData = $review->countAll($id);
            $reviews = [
                'total' => $countData->total ?? 0,
                'unseen' => $countData->total_unseen ?? 0
            ];

            return ['status' => true, 'data' => $reviews];
        }

        if($action === 'all'){
            $reviewData = $review->getAll($id);
            $reviewStats = $review->getStatistic($id);

            // Calculate statistics
            $totalRatings = 0;
            $sumRatings = 0;
            $ratingCounts = [1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0];
            $reviewArray = [];

            foreach($reviewData as $val){
                $reviewId = (int) $val->review_id;
                $customerId = (int) $val->customer_id;
                $orderId = (int) $val->order_id;
                $rating = (float) $val->rating_value;
                $comment = $val->rating_text;
                $replyComment = $val->reply_text ?? '';
                $isSeen = $val->rating_seen;

                $customerData = $customer->getById($customerId);
                $customerName = $customerData->first_name . ' ' . $customerData->last_name;

                $reviewArray[] = [
                    'review_id' => $reviewId,
                    'review_customer' => $customerName,
                    'review_order' => 'ZP975784874',
                    'review_rating' => (float) $rating,
                    'review_text' => $comment,
                    'review_reply' => $replyComment,
                    'review_seen' => $isSeen == 'true' ? true : false,
                    'review_at' => Helper::timeAgo($val->created_at),
                ];

                // set review as seen for the restaurant owner
                $review->setAsRead($reviewId, $id);
            }

            $data = [
                'rating_total' => $reviewStats->total_rating,
                'rating_average' => $reviewStats->average_rating,
                'rating_percent_1' => (float) $reviewStats->percent_rating_1,
                'rating_percent_2' => (float) $reviewStats->percent_rating_2,
                'rating_percent_3' => (float) $reviewStats->percent_rating_3,
                'rating_percent_4' => (float) $reviewStats->percent_rating_4,
                'rating_percent_5' => (float) $reviewStats->percent_rating_5,
                'reviews' => $reviewArray,
            ];
            return ['status' => true, 'data' => $data];
        }

        return ["status" => false, "message" => "Sorry, no action was provided."];
    }

    /**
     * Executes different actions based on the given action parameter.
     *
     * @param string $action The action to be performed.
     * @return array
    */
    public function runSetting(string $action): array
    {
        if (empty($action)) {
            return ["status" => false, "message" => "Unauthorized access detected."];
        }

        $postData = Helper::decodePostData();
        if(in_array($action, ['profile-image', 'profile-cover'])){
            $postData = $_POST;
        }

        if (empty($postData)) {
            return ["status" => false, "message" => "Sorry, no action was provided."];
        }

        $partnerId = (int) $postData['id'];
        $restaurantData = $this->getById($partnerId, 'id, restaurant_name, restaurant_avatar, restaurant_cover');
        if (empty($restaurantData)) {
            return ["status" => false, "message" => "Sorry, but this restaurant does not exist."];
        }

        if ($action === 'location') {
            $latitude = $postData['latitude'];
            $longitude = $postData['longitude'];
            $address = $postData['address'];

            if (empty($latitude) || empty($longitude)) {
                return ["status" => false, "message" => "Sorry, but latitude and longitude are required."];
            }

            if (empty($address)) {
                return ["status" => false, "message" => "Sorry, but  restaurant address is required."];
            }

            $this->setProfile('restaurant_latitude', $latitude, $partnerId);
            $this->setProfile('restaurant_longitude', $longitude, $partnerId);
            $this->setProfile('restaurant_address', $address, $partnerId);
            return ["status" => true, "message" => "Restaurant location has been updated successfully."];
        }

        if ($action === 'region') {

            $restaurantCountry = $postData['country'];
            if (empty($restaurantCountry)) {
                return ["status" => false, "message" => "Sorry, but country is required."];
            }

            $this->setProfile('restaurant_country', $restaurantCountry, $partnerId);
            return ["status" => true, "message" => "Restaurant region has been updated successfully."];
        }

        // if ($action === 'payment-cash') {
        //     $cashActive = $postData['isActive'];

        //     if(!in_array($cashActive, ['true', 'false'])){
        //         return ["status" => false, "message" => "Sorry, but cash payment data is required."];
        //     }

        //     $restaurant->setSettings('allow_cash_payment', $cashActive, $partnerId);

        //     return ["status" => true, "message" => "Cash payment settings has been updated successfully."];
        // }

        if ($action === 'payment-request') {
            $requestType = $postData['type'];

            if(empty($requestType)){
                return ["status" => false, "message" => "Sorry, but request type is required."];
            }

            $requestData = $this->getPaymentRequest($partnerId);
            if(empty($requestData)){
                $this->addPaymentRequest($requestType, $partnerId);
                return ["status" => true, "message" => "Your request has been submitted successfully."];
            }else{
                return ["status" => false, "message" => "Sorry, but you have already submitted a request."];
            }
        }

        if ($action === 'payment-online') {

            $onlineArray = [
                "account_name" => $postData['account_name'],
                "account_number" => $postData['account_number'] ?? '',
                "account_bank" => $postData['account_bank'] ?? '',
                "account_ifsc" => $postData['account_ifsc'],
            ];

            if ($this->hasBankAccount($partnerId)) {
                $this->setBankAccount($onlineArray, $partnerId);
            } else {
                $this->addBankAccount($onlineArray, $partnerId);
            }

            return ["status" => true, "message" => "Online payment settings has been updated successfully."];
        }

        if ($action === 'cuisine') {
            $cuisine = new Cuisine;
            $cuisineId = (int) $postData['cuisine_id'] ?? 0;
            $cuisineStatus = $postData['toggle'] ?? null;

            if (empty($cuisineId)) {
                return ["status" => false, "message" => "Sorry, but cuisine is required."];
            }

            if(empty($cuisineStatus) && $cuisineStatus != false ){
                return ["status" => false, "message" => "Sorry, but cuisine status is required, to know the action."];
            }

            $isExist = $cuisine->existCuisine($cuisineId);
            if(!$isExist){
                return ["status" => false, "message" => "Sorry, but this cuisine does not exist."];
            }

            $cuisine->setCuisine($cuisineId, $partnerId, $cuisineStatus);
            return ["status" => true, "message" => "Cuisine data has been updated successfully."];
        }

        if ($action === 'setting') {

            $deliveryData = $postData['delivery'];
            $dineInData = $postData['dineIn'];
            $takeAwayData = $postData['takeAway'];
            $feesData = $postData['fees'];
            $openingHourData = $postData['openingHour'];
            $vegetarian = $postData['vegetarian'];
            $nonVegetarian = $postData['non_vegetarian'];

            if (empty($deliveryData)) {
                return ["status" => false, "message" => "Sorry, but delivery data seems to be missing."];
            }

            if (empty($dineInData)) {
                return ["status" => false, "message" => "Sorry, but dine in data seems to be missing."];
            }

            if (empty($takeAwayData)) {
                return ["status" => false, "message" => "Sorry, but take away data seems to be missing."];
            }

            if (empty($openingHourData)) {
                return ["status" => false, "message" => "Sorry, but restaurant opening hour data seems to be missing."];
            }

            if (empty($feesData)) {
                return ["status" => false, "message" => "Sorry, but restaurant fees data seems to be missing."];
            }

            if (empty($vegetarian) && $vegetarian != false) {
                return ["status" => false, "message" => "Sorry, but restaurant vegetarian data seems to be missing."];
            }

            if (empty($nonVegetarian) && $nonVegetarian != false) {
                return ["status" => false, "message" => "Sorry, but restaurant non vegetarian data seems to be missing."];
            }

            // DELIVERY SETTINGS
            $this->setSettings('delivery_allow', $deliveryData['isActive'], $partnerId);
            $this->setSettings('delivery_food_prepare', $deliveryData['foodPreparationTime'], $partnerId);
            $this->setSettings('delivery_distance', (float) $deliveryData['deliveryDistance'], $partnerId);
            $this->setSettings('delivery_minimum_order_price', $deliveryData['minimumOrderPrice'], $partnerId);

            // DINE IN SETTINGS
            $this->setSettings('dinein_allow', $dineInData['isActive'], $partnerId);
            $this->setSettings('dinein_table', $dineInData['dineInTables'], $partnerId);
            $this->setSettings('dinein_minimum_order_price', $dineInData['minimumOrderPrice'], $partnerId);

            // TAKEAWAY SETTINGS
            $this->setSettings('takeaway_allow', $takeAwayData['isActive'], $partnerId);
            $this->setSettings('takeaway_minimum_order_price', $takeAwayData['minimumOrderPrice'], $partnerId);

            // VAT & PLATFORM FEES
            $feeArray = [
                'platform_fee_type' => $feesData['platform_fee_type'],
                'vat_fee_type' => $feesData['vat_fee_type'],
                'vat_fee' => (float) $feesData['vat_fee'],
            ];
            $this->setCharges($feeArray, $partnerId);

            // WORKING HOURS
            $openingHourArray = [
                'opening_morning' => $openingHourData['morning']['openingTime'],
                'closing_morning' => $openingHourData['morning']['closingTime'],
                'opening_evening' => $openingHourData['evening']['openingTime'],
                'closing_evening' => $openingHourData['evening']['closingTime'],
            ];
            $this->setWorkingHour($openingHourArray, $partnerId);

            // VEGETARIAN && NON VEGETARIAN
            $this->setSettings('vegetarian_allow', $vegetarian, $partnerId);
            $this->setSettings('non_vegetarian_allow', $nonVegetarian, $partnerId);

            return ["status" => true, "message" => "Restaurant settings has been updated successfully."];
        }

        if ($action === 'daily-discount') {
            $discount = new Discount;
            $discountType = $postData['type'];
            $discountArray = $postData['discounts'];

            if (!$discount->hasDiscount($partnerId, $discountType)) {
                $discount->addDiscount($discountType, $discountArray, $partnerId);
            } else {
                $discount->setDiscount($discountType, $discountArray, $partnerId);
            }

            return ["status" => true, "message" => "Restaurant daily discount has been updated successfully."];
        }

        if ($action === 'delivery-discount') {
            $discount = new Discount;
            $discountArray = $postData['discounts'];

            if (!$discount->hasDeliveryDiscount($partnerId)) {
                $discount->addDeliveryDiscount($discountArray, $partnerId);
            } else {
                $discount->setDiscountDelivery($discountArray, $partnerId);
            }

            return ["status" => true, "message" => "Restaurant delivery discount has been updated successfully."];
        }

        if ($action === 'profile-image') {
            $photo = $_FILES['photo']['name'] ?? $postData['photo'] ?? '';
            $isDefault = $postData['is_default'] ?? '';

            if (empty($photo)) {
                return ["status" => false, "message" => "Sorry, but profile image seems to be missing."];
            }

            if(empty($isDefault) && ($isDefault != 'true' || $isDefault != 'false')) {
                return ["status" => false, "message" => "Sorry, but invalid default value provided."];
            }

            $result = $this->db->transaction(function ($database) use ($partnerId, $restaurantData, $photo, $isDefault) {
                $uploads = new Uploads;
                $profileDirectory = UPLOADS['restaurant_upload'] . '/profile/';

                if($isDefault == 'false') {
                    // delete the previous profile image
                    $uploads->deleteExistingFile("{$profileDirectory}", $restaurantData->restaurant_avatar);

                    // upload image and convert to webp
                    $profileName = mt_rand(1000000, 999999999) . '.' . pathinfo($_FILES['photo']['name'], PATHINFO_EXTENSION);
                    $uploads->uploadFile('photo', $profileDirectory, $profileName);
                    $profilePhoto = $uploads->convertImageToWebp($profileName, "{$profileDirectory}", "{$profileDirectory}");
                    // delete the original image uploaded to the server
                    $uploads->deleteExistingFile("{$profileDirectory}", $profileName);

                }elseif($isDefault == 'true' && (Helper::startsWith($photo, 'zp_photo_female') || Helper::startsWith($photo, 'zp_photo_male'))) {
                    $profilePhoto = $photo;
                }

                $this->setProfile('restaurant_avatar', $profilePhoto, $partnerId);
                return true;
            });

            if($result){
                return ["status" => true, "message" => "Profile image has been updated successfully."];
            }else{
                return ["status" => false, "message" => "Sorry, an error has occurred. Please try again later."];
            }
        }

        if ($action === 'profile-cover') {
            $cover = $_FILES['cover'] ?? '';

            if (empty($cover)) {
                return ["status" => false, "message" => "Sorry, but profile cover image seems to be missing."];
            }

            $result = $this->db->transaction(function ($database) use ($partnerId, $restaurantData, $cover) {
                $uploads = new Uploads;
                $coverDirectory = UPLOADS['restaurant_upload'] . '/cover/';

                // delete the previous cover image
                $uploads->deleteExistingFile("{$coverDirectory}", $restaurantData->restaurant_cover);

                // upload image and convert to webp
                $fileHandler = new FileHandler;
                $coverName = mt_rand(1000000, 999999999) . '.' . pathinfo($_FILES['cover']['name'], PATHINFO_EXTENSION);
                $uploads->uploadFile('cover', $coverDirectory, $coverName);
                $coverPhoto = $uploads->convertImageToWebp($coverName, "{$coverDirectory}", "{$coverDirectory}");

                // delete the original image uploaded to the server
                $uploads->deleteExistingFile("{$coverDirectory}", $coverName);

                $this->setProfile('restaurant_cover', $coverPhoto, $partnerId);
                return true;
            });

            if($result){
                return ["status" => true, "message" => "Profile cover has been updated successfully."];
            }else{
                return ["status" => false, "message" => "Sorry, an error has occurred. Please try again later."];
            }
        }

        if ($action === 'profile') {

            $ownerName = $postData['ownerName'] ?? '';
            $restaurantName = $postData['restaurantName'] ?? '';
            $phoneNumber = $postData['phoneNumber'] ?? '';
            $whatsappNumber = $postData['whatsappNumber'] ?? '';
            $currency = $postData['currency'] ?? '';
            $type = $postData['type'] ?? '';

            $errorArray = [
                $ownerName => 'Please provide your owner name eg. Johnny Marvis',
                $restaurantName => 'Please provide your restaurant name',
                $phoneNumber => 'Please provide your phone number',
                $whatsappNumber => 'Please provide your whatsapp number',
                $currency => 'Please provide your currency',
                $type => 'Please provide your type of restaurant',
            ];

            if (empty($ownerName)) {
                return ["status" => false, "message" => $errorArray[$ownerName]];
            }

            if (empty($restaurantName)) {
                return ["status" => false, "message" => $errorArray[$restaurantName]];
            }

            if ($this->hasName($restaurantName) && $restaurantData->id != $partnerId) {
                return ["status" => false, "message" => "Sorry, but this restaurant name has already been taken."];
            }

            if (empty($phoneNumber)) {
                return ["status" => false, "message" => $errorArray[$phoneNumber]];
            }

            if (empty($whatsappNumber)) {
                return ["status" => false, "message" => $errorArray[$whatsappNumber]];
            }

            if (empty($currency)) {
                return ["status" => false, "message" => $errorArray[$currency]];
            }

            if (empty($type)) {
                return ["status" => false, "message" => $errorArray[$type]];
            }

            $this->setProfile('restaurant_owner', $ownerName, $partnerId);
            $this->setProfile('restaurant_name', $restaurantName, $partnerId);
            $this->setProfile('restaurant_phone', $phoneNumber, $partnerId);
            $this->setProfile('restaurant_whatsapp', $whatsappNumber, $partnerId);
            $this->setProfile('restaurant_currency', $currency, $partnerId);
            $this->setProfile('restaurant_type', $type, $partnerId);

            return ["status" => true, "message" => "Profile updated successfully."];
        }

        if ($action === 'toggle-restaurant') {
            $restaurantStatus = $postData['status'];
            if (empty($restaurantStatus)) {
                return ["status" => false, "message" => "Please provide your restaurant status if open or closed."];
            }

            $this->setProfile('restaurant_active', $restaurantStatus, $partnerId);
            return ["status" => true, "message" => "Restaurant status has been set to " . Helper::capitalize($restaurantStatus)];
        }

        return ["status" => false, "message" => "Sorry, but no action was provided."];
    }

    public function runReviews(int $id, string $action): array
    {

        if (empty($action)) {
            @header("HTTP/1.1 401 Unauthorized");
            return ["status" => false, "message" => "Unauthorized access detected."];
        }

        if (empty($id)) {
            @header("HTTP/1.1 400 Bad Request");
            return ["status" => false, "message" => "Sorry, not restaurant id provided."];
        }

        $restaurantData = $this->getById($id, 'id');
        if(empty($restaurantData)){
            @header("HTTP/1.1 404 Not Found");
            return ["status" => false, "message" => "Sorry, this restaurant was not found."];
        }

        $review  = new Reviews;
        $postData = Helper::decodePostData();

        if($action === 'reply'){

            $reply = $postData['text'];
            $reviewId = (int) $postData['review_id'] ?? 0;
            $reviewData = $review->getById($reviewId, $id);

            if(empty($reply)){
                return ['status' => false, 'message' => 'Please provide your reply.'];
            }

            if(empty($reviewId)){
                return ['status' => false, 'message' => 'Sorry, but review id was not provided.'];
            }

            if(empty($reviewData)){
                return ['status' => false, 'message' => 'Sorry, but review data was not found.'];
            }

            $review->addReply($reply, $reviewId, $id);
            return ['status' => true, 'message' => 'Reply added successfully.'];

        }

        return ["status" => false, "message" => "Sorry, no action was provided."];
    }

    /**
     * Retrieves dishes based on the given parameters.
     *
     * @param int $id The ID of the restaurant.
     * @param string $action The action to perform.
     * @param string|int $data Additional data (optional).
     * @return array An array containing the status and message of the operation.
     */
    public function getDishes(int $id, string $action, string|int $data = ''): array
    {
        if (empty($action)) {
            return ["status" => false, "message" => "Unauthorized access detected."];
        }

        if (empty($id)) {
            return ["status" => false, "message" => "Sorry, not restaurant id provided."];
        }

        $restaurantData = $this->getById($id, 'id, restaurant_email');
        $restaurantEmail = $restaurantData->restaurant_email;

        $dish = new Dish;
        if(empty($restaurantData)){
            return ["status" => false, "message" => "Sorry, this restaurant was not found."];
        }

        if($action === 'search'){
            $searchTerm = $_GET['term'] ?? '';

            if(empty($searchTerm)){
                return ["status" => false, "message" => "Sorry, but you didn't provide any search term."];
            }

            $searchArray = [];
            $searchData = $dish->getBySearching($searchTerm, $id);
            if(empty($searchData)){
                return ["status" => false, "message" => "Sorry, but no results were found."];
            }

            foreach($searchData as $val){
                $searchArray[] = [
                    "dish_id" => (int) $val->dish_id,
                    "dish_title" => $val->dish_title,
                    "dish_slug" => $val->dish_slug,
                    "dish_price" => empty($val->dish_sale_price) ? (float) $val->dish_regular_price : (float) $val->dish_sale_price,
                    "dish_image" => $this->getDishUpload($restaurantEmail, $val->dish_image, true),
                    "dish_type" => $val->dish_type,
                    "dish_status" => $val->dish_status == 'available' ? true : false,
                ];
            }

            return ["status" => true, "data" => $searchArray];
        }

        if($action === 'count-uncategorized'){
            $count = $dish->countUncategorized($id);
            return ["status" => true, "data" => $count];
        }

        if($action === 'uncategorized-dishes'){
            $uncategorizedDishes = $dish->getAllUncategorized($id);
            $uncategorizedArray = [];
            if(!empty($uncategorizedDishes)){
                foreach($uncategorizedDishes as $val){
                    $dishPrice = empty($val->dish_sale_price) ? (float) $val->dish_regular_price : (float) $val->dish_sale_price;
                    $dishRegularPrice = (float) $val->dish_regular_price;
                    $dishDiscountPrice = (float) $val->dish_sale_price;
                    $uncategorizedArray[] = [
                        "dish_id" => \intval($val->dish_id),
                        "dish_title" => $val->dish_title,
                        "dish_slug" => $val->dish_slug,
                        "dish_price" => $dishPrice,
                        "dish_regular_price" => $dishRegularPrice,
                        "dish_discount_price" => $dishDiscountPrice,
                        "dish_image" => $this->getDishUpload($restaurantEmail, $val->dish_image, true),
                        "dish_type" => $val->dish_type,
                        "dish_quantity" => \intval($val->dish_quantity),
                        "dish_weight" => (float) $val->dish_weight,
                        "dish_sorting" => \intval($val->dish_sorting),
                        "dish_description" => $val->dish_description,
                        "dish_status" => $val->dish_status == 'available' ? true : false
                    ];
                }
            }
            return ["status" => true, "data" => $uncategorizedArray];
        }

        if(\in_array($action, ['all', 'uncategorized', 'available', 'unavailable', 'vegetarian', 'non-vegetarian', 'mixed'])){
            $customization = new Customizations;

            $menuDishData = $dish->getAllMenuDishes($id);
            $dishMenuArray = [];

            if(!empty($menuDishData)){
                foreach($menuDishData as $val){

                    $dishArray = [];
                    $dishes = $dish->getAll((int) $val->menu_id, $id, $action);
                    $countDishes = count($dishes);
                    $menuStatus = false;
                    $countToggleOn = 0;

                    foreach($dishes as $value){
                        $dishId = (int) $value->dish_id;
                        $dishTitle = $value->dish_title;
                        $dishSlug = $value->dish_slug;
                        $dishWeight = (float) $value->dish_weight;
                        $dishQuantity = (int) $value->dish_quantity;
                        $dishPrice = empty($value->dish_sale_price) ? (float) $value->dish_regular_price : (float) $value->dish_sale_price;
                        $dishSalePrice = (float) $value->dish_sale_price;
                        $dishRegularPrice = (float) $value->dish_regular_price;
                        $dishDescription = $value->dish_description;
                        $dishImage = $this->getDishUpload($restaurantEmail, $value->dish_image, true);
                        $dishType = $value->dish_type;
                        $dishStatus = $value->dish_status == 'available' ? true : false;
                        $dishSorting = (int) $value->dish_sorting;
                        $dishPreparationPrice = (float) $value->dish_prepare_price;


                        if($value->dish_status == 'available'){
                            $countToggleOn++;
                        }

                        $dishAvailabilityArray = [];
                        $dishAvailability = $dish->getAllAvailability((int) $value->dish_id, $id);
                        foreach($dishAvailability as $availability){
                            $dishAvailabilityArray[] = [
                                'day' => $availability->working_day,
                                'hour' => $availability->working_hour,
                                'toggle' => $availability->working_status == 'available' ? true : false
                            ];
                        }

                        // Customization category array
                        $customizedCategoryArray = [];
                        $customizedCategory = $customization->getAllCategoryByDishId($dishId, $id);
                        foreach($customizedCategory as $customCategory){
                            $categoryId = (int) $customCategory->category_id;
                            $customCategoryStatus = false;

                            // Customization items array
                            $customizedItemsArray = [];
                            $customizedItems = $customization->getAllItems($categoryId, $id, 'all');
                            $countCustomizedItems = count($customizedItems);
                            $countCustomizedToggle = 0;

                            foreach($customizedItems as $customItem){
                                if($customItem->item_status == 'available'){
                                    $countCustomizedToggle++;
                                }

                                $customizedItemsArray[] = [
                                    "item_id" => (int) $customItem->item_id,
                                    "item_title" => $customItem->item_title,
                                    "item_slug" => $customItem->item_slug,
                                    "item_quantity" => (int) $customItem->item_quantity,
                                    "item_type" => $customItem->item_type,
                                    "item_regular_price" => (float) $customItem->item_regular_price,
                                    "item_sale_price" => (float) $customItem->item_sale_price,
                                    "item_price" =>  empty($customItem->item_sale_price) ? (float) $customItem->item_regular_price : (float) $customItem->item_sale_price,
                                    "item_weight" => (float) $customItem->item_weight,
                                    "item_description" => $customItem->item_description,
                                    "item_sorting" => (int) $customItem->item_sorting,
                                    "item_status" => $customItem->item_status == 'available' ? true : false,
                                    "item_image" => $this->getCustomizedDishUpload($restaurantEmail, $customItem->item_image, true)
                                ];
                            }

                            if(($countCustomizedToggle == $countCustomizedItems) && $countCustomizedItems >= 1){
                                $customCategoryStatus = true;
                            }

                            $customizedCategoryArray[] = [
                                "category_id" => (int) $customCategory->category_id,
                                "category_title" => $customCategory->category_title,
                                "category_slug" => $customCategory->category_slug,
                                "category_sorting" => (int) $customCategory->category_sorting,
                                "category_type" => $customCategory->category_type,
                                "selectable_items" => (int) $customCategory->selectable_item,
                                "customized_status" => $customCategoryStatus,
                                "customized_items" => $customizedItemsArray
                            ];
                        }

                        $dishArray[] = [
                            "dish_id" => $dishId,
                            "dish_title" => $dishTitle,
                            "dish_slug" => $dishSlug,
                            "dish_type" => $dishType,
                            "dish_weight" => $dishWeight,
                            "dish_sorting" => $dishSorting,
                            "dish_quantity" => $dishQuantity,
                            "dish_description" => $dishDescription,
                            "dish_image" => $dishImage,
                            "dish_price" => $dishPrice,
                            "dish_regular_price" => $dishRegularPrice,
                            "dish_discount_price" => $dishSalePrice,
                            "dish_preparation_price" => $dishPreparationPrice,
                            "dish_status" => $dishStatus,
                            "dish_availability" => $dishAvailabilityArray,
                            "dish_customization_total" => count($customizedCategory),
                            "dish_customization" => $customizedCategoryArray
                        ];
                    }

                    if(($countToggleOn == $countDishes) && $countDishes >= 1){
                        $menuStatus = true;
                    }

                    $dishMenuArray[] = [
                        "menu_id" => intval($val->menu_id),
                        "menu_title" => $val->menu_title,
                        "menu_slug" => $val->menu_slug,
                        "menu_type" => $val->menu_type,
                        "menu_sorting" => intval($val->menu_sorting),
                        "menu_status" => $val->menu_status == 'available' ? true : false,
                        "dish_total" => intval($val->total_dish),
                        "dish_toggle" => $menuStatus,
                        "dish_array" => $dishArray
                    ];
                }
            }

            return ["status" => true, "data" => $dishMenuArray];
        }

        return ["status" => false, "message" => "Sorry, but no action was provided."];
    }

    public function getCustomization(int $id, string $action, ?string $data = ''): array
    {
        if (empty($action)) {
            return ["status" => false, "message" => "Unauthorized access detected."];
        }

        if (empty($id)) {
            return ["status" => false, "message" => "Sorry, not restaurant id provided."];
        }

        $restaurantData = $this->getById($id, 'id, restaurant_email');
        $restaurantEmail = $restaurantData->restaurant_email;

        if(empty($restaurantData)){
            return ["status" => false, "message" => "Sorry, this restaurant was not found."];
        }

        $dish = new Dish;
        $customization = new Customizations;

        if($action === 'all-customized-category'){
            //$customizedCategoryArray = [];
            $customizedCategory = $customization->getAllCategory($id);

            foreach($customizedCategory as $val){
                $customizedCategoryArray[] = [
                    "category_id" => (int) $val->category_id,
                    "dish_id" => (int) $val->dish_id,
                    "category_title" => $val->category_title,
                    "category_slug" => $val->category_slug,
                    "category_type" => $val->category_type,
                    "category_sorting" => (int) $val->category_sorting,
                    "selectable_items" => (int) $val->selectable_item
                ];
            }
            return ["status" => true, 'data' => $customizedCategoryArray];
        }

        if($action === 'category'){
            $categoryId = (int) $data ?? 0;

            if(empty($categoryId)){
                return ["status" => false, "message" => "Sorry, customized category was not provided."];
            }

            $categoryData = $customization->getCategoryById($categoryId, $id);
            if(empty($categoryData)){
                return ["status" => false, "message" => "Sorry, this customized category was not found."];
            }

            $itemArray = $customization->getItemsByCategoryId($categoryId, $id);
            if(empty($itemArray)){
                return ["status" => true, "data" => []];
            }

            $customizedItemArray = [];

            foreach($itemArray as $value){
                $itemId = intval($value->item_id);

                $itemAvailabilityArray = [];
                $itemAvailability = $customization->getAllItemAvailability($itemId, $id);
                foreach($itemAvailability as $availability){
                    $dishAvailabilityArray[] = [
                        'day' => $availability->working_day,
                        'hour' => $availability->working_hour,
                        'toggle' => $availability->working_status == 'available' ? true : false
                    ];
                }

                $customizedItemArray[] = [
                    "item_id" => $itemId,
                    "item_title" => $value->item_title,
                    "item_slug" => $value->item_slug,
                    "item_type" => $value->item_type,
                    "item_weight" => empty($value->item_weight) ? 0 : $value->item_weight,
                    "item_sorting" => intval($value->item_sorting),
                    "item_quantity" => intval($value->item_quantity),
                    "item_description" => $value->item_description,
                    "item_image" => $this->getCustomizedDishUpload($restaurantEmail, $value->item_image),
                    "item_price" => empty($value->item_sale_price) ? $value->item_regular_price : $value->item_sale_price,
                    "item_regular_price" => $value->item_regular_price,
                    "item_discount_price" => empty($value->item_sale_price) ? 0 : $value->item_sale_price,
                    "item_status" => $value->item_status == 'available' ? true : false,
                    "item_availability" => $itemAvailabilityArray
                ];
            }

            $totalSideItems = count($itemArray);
            $categoryArray = [
                "category_id" => intval($categoryData->category_id),
                "category_title" => $categoryData->category_title,
                "category_slug" => $categoryData->category_slug,
                "category_type" => $categoryData->category_type,
                "category_sorting" => intval($categoryData->category_sorting),
                "item_total" => $totalSideItems,
                "item_array" => $customizedItemArray
            ];

            return ["status" => true, "data" => $categoryArray];
        }

        if($action === 'dish-category'){
            $dishId = (int) $data ?? 0;

            if(empty($dishId)){
                return ["status" => false, "message" => "Sorry, dish was not provided."];
            }

            $dishData = $dish->getById($dishId, $id, 'dish_id');
            $customizedArray = $customization->getAllCategoryByDishId($dishId, $id);
            if(empty($dishData)){
                return ["status" => false, "message" => "Sorry, this dish was not found."];
            }

            if(empty($customizedArray)){
                return ["status" => true, "data" => []];
            }

            $categoryArray = [];
            foreach($customizedArray as $val){

                $categoryStatus = false;
                $countToggleOn = 0;
                $itemArray = [];

                $categoryId = (int) $val->category_id;
                $item = $customization->getAllItems($categoryId, $id);

                foreach($item as $value){

                    if($value->item_status == 'available'){
                        $countToggleOn++;
                    }

                    $itemAvailabilityArray = [];
                    $itemAvailability = $customization->getAllItemAvailability((int) $value->item_id, $id);
                    foreach($itemAvailability as $availability){
                        $dishAvailabilityArray[] = [
                            'day' => $availability->working_day,
                            'hour' => $availability->working_hour,
                            'toggle' => $availability->working_status == 'available' ? true : false
                        ];
                    }

                    $itemPrice = empty($value->item_sale_price) ? (float) $value->item_regular_price : (float) $value->item_sale_price;
                    $itemRegularPrice = (float) $value->item_regular_price;
                    $itemDiscountPrice = empty($value->item_sale_price) ? 0 : (float) $value->item_sale_price;
                    $itemDailyQuantity = intval($value->item_quantity);
                    $itemWeight = empty($value->item_weight) ? 0 : (float) $value->item_weight;
                    $itemSorting = intval($value->item_sorting);

                    $itemArray[] = [
                        "item_id" => intval($value->item_id),
                        "item_title" => $value->item_title,
                        "item_slug" => $value->item_slug,
                        "item_type" => $value->item_type,
                        "item_weight" => $itemWeight,
                        "item_sorting" => $itemSorting,
                        "item_quantity" => $itemDailyQuantity,
                        "item_description" => $value->item_description,
                        "item_image" => $this->getCustomizedDishUpload($restaurantEmail, $value->item_image),
                        "item_price" => $itemPrice,
                        "item_regular_price" => $itemRegularPrice,
                        "item_discount_price" => $itemDiscountPrice,
                        "item_status" => $value->item_status == 'available' ? true : false,
                        "item_availability" => $itemAvailabilityArray
                    ];
                }

                if($countToggleOn == count($item)){
                    $categoryStatus = true;
                }

                $totalSideItems = intval(count($item));
                $categoryArray[] = [
                    "category_id" => intval($val->category_id),
                    "category_title" => $val->category_title,
                    "category_slug" => $val->category_slug,
                    "category_type" => $val->category_type,
                    "category_sorting" => intval($val->category_sorting),
                    "selectable_items" => \intval($val->selectable_item),
                    "item_total" => $totalSideItems,
                    "customized_status" => $categoryStatus,
                    "customized_items" => $itemArray
                ];
            }

            return ["status" => true, "data" => $categoryArray];
        }

        if(\in_array($action, ['all', 'available', 'unavailable', 'vegetarian', 'non-vegetarian', 'mixed'])){
            $sideItemCategoryData = $customization->getAllCategory($id);
            $sideItemCategoryArray = [];

            if(!empty($sideItemCategoryData)){
                foreach($sideItemCategoryData as $val){

                    $itemArray = [];
                    $item = $customization->getAllItems((int) $val->category_id, $id, $action);
                    $categoryStatus = false;
                    $countToggleOn = 0;

                    foreach($item as $value){

                        if($value->item_status == 'available'){
                            $countToggleOn++;
                        }

                        $itemAvailabilityArray = [];
                        $itemAvailability = $customization->getAllItemAvailability((int) $value->item_id, $id);
                        foreach($itemAvailability as $availability){
                            $dishAvailabilityArray[] = [
                                'day' => $availability->working_day,
                                'hour' => $availability->working_hour,
                                'toggle' => $availability->working_status == 'available' ? true : false
                            ];
                        }

                        $itemArray[] = [
                            "item_id" => intval($value->item_id),
                            "item_title" => $value->item_title,
                            "item_slug" => $value->item_slug,
                            "item_type" => $value->item_type,
                            "item_weight" => empty($value->item_weight) ? 0 : $value->item_weight,
                            "item_sorting" => intval($value->item_sorting),
                            "item_quantity" => intval($value->item_quantity),
                            "item_description" => $value->item_description,
                            "item_image" => $this->getCustomizedDishUpload($restaurantEmail, $value->item_image),
                            "item_price" => empty($value->item_sale_price) ? $value->item_regular_price : $value->item_sale_price,
                            "item_regular_price" => $value->item_regular_price,
                            "item_discount_price" => empty($value->item_sale_price) ? 0 : $value->item_sale_price,
                            "item_status" => $value->item_status == 'available' ? true : false,
                            "item_availability" => $itemAvailabilityArray
                        ];
                    }

                    if($countToggleOn == count($item)){
                        $categoryStatus = true;
                    }

                    $totalSideItems = intval(count($item));
                    $sideItemCategoryArray[] = [
                        "category_id" => intval($val->category_id),
                        "category_title" => $val->category_title,
                        "category_slug" => $val->category_slug,
                        "category_type" => $val->category_type,
                        "category_sorting" => intval($val->category_sorting),
                        "item_total" => $totalSideItems,
                        "item_toggle" => $categoryStatus,
                        "item_array" => $itemArray
                    ];
                }
            }

            return ["status" => true, "data" => $sideItemCategoryArray];
        }

        return ["status" => false, "message" => "Sorry, but no action was provided."];
    }

    /**
     * Retrieves menu data based on the provided restaurant ID and action.
     *
     * @param int $id The ID of the restaurant.
     * @param string $action The action to perform.
     * @param string|int $data Additional data for specific actions.
     * @return array response with menu data based on the action.
     */
    public function getMenu(int $id, string $action, string|int $data = ''): array
    {
        if (empty($action)) {
            return ["status" => false, "message" => "Unauthorized access detected."];
        }

        if (empty($id)) {
            return ["status" => false, "message" => "Sorry, not restaurant id provided."];
        }

        $restaurantData = $this->getById($id, 'id');
        $menu = new Menu;

        if(empty($restaurantData)){
            return ["status" => false, "message" => "Sorry, this restaurant was not found."];
        }

        if(\in_array($action, ['all', 'available', 'unavailable', 'vegetarian', 'non-vegetarian', 'mixed'])){
            $menuData = $menu->getAll($id, $action);
            $menuArray = [];

            foreach($menuData as $value){
                $menuArray[] = [
                    "menu_id" => (int) $value->menu_id,
                    "menu_title" => $value->menu_title,
                    "menu_slug" => $value->menu_slug,
                    "menu_type" => $value->menu_type,
                    "menu_sorting" => \intval($value->menu_sorting),
                    "menu_toggle" => $value->menu_status == 'available' ? true : false
                ];
            }

            return ["status" => true, "data" => $menuArray];
        }

        if($action === 'category'){
            $menuId = (int) $data ?? 0;
            if(empty($menuId)){
                return ["status" => false, "message" => "Sorry, but an invalid menu id was provided."];
            }

            $menuData = $menu->getById($menuId, $id, 'menu_title, menu_slug, menu_sorting, menu_type, menu_status');
            if(empty($menuData)){
                return ["status" => false, "message" => "Sorry, this menu was not found."];
            }

            $menuArray[] = [
                "menu_title" => $menuData->menu_title,
                "menu_slug" => $menuData->menu_slug,
                "menu_type" => $menuData->menu_type,
                "menu_sorting" => $menuData->menu_sorting,
                "menu_toggle" => $menuData->menu_status == 'available' ? true : false
            ];

            return ["status" => true, "data" => $menuArray];
        }

        if($action === 'search'){
            $searchTerm = $_GET['term'] ?? '';

            if(empty($searchTerm)){
                return ["status" => false, "message" => "Sorry, but you didn't provide any search term."];
            }

            $searchArray = [];
            $searchData = $menu->getBySearching($searchTerm, $id);
            if(empty($searchData)){
                return ["status" => false, "message" => "Sorry, but no results were found."];
            }

            foreach($searchData as $val){
                $searchArray[] = [
                    "menu_id" => (int) $val->menu_id,
                    "menu_title" => $val->menu_title,
                    "menu_slug" => $val->menu_slug,
                    "menu_type" => $val->menu_type,
                ];
            }

            return ["status" => true, "data" => $searchArray];
        }

        return ["status" => false, "message" => "Sorry, no action was provided."];
    }

    /**
     * Update data based on the provided action.
     *
     * @param string $action The action to be performed
     * @return array The status and message of the update operation
     */
    public function updateData(string $action): array
    {
        if (empty($action)) {
            return ["status" => false, "message" => "Unauthorized access detected."];
        }

        if(!in_array($action, ['dish-image', 'customized-item-image'])){
            $postData = Helper::decodePostData();
        }else{
            $postData = $this->helper->sanitize_post();
        }

        if (empty($postData)) {
            return ["status" => false, "message" => "Sorry, no action was provided."];
        }

        $partnerId = intval($postData['id'] ?? 0);
        $restaurantData = $this->getById($partnerId, 'id, restaurant_email');
        $restaurantEmail = $restaurantData->restaurant_email;

        $dishDefaultDirectory = $this::$uploadDirectory . "/{$restaurantEmail}/" . $this::$defaultImages;
        $dishCompressedDirectory = $this::$uploadDirectory . "/{$restaurantEmail}/" . $this::$compressedImages;
        
        $menu = new Menu;
        $dish = new Dish;
        $customization = new Customizations;

        if (empty($restaurantData)) {
            return ["status" => false, "message" => "Sorry, but this restaurant does not exist."];
        }

        if($action === 'menu'){
            $menuId = (int) $postData['menu_id'] ?? 0;
            $menuName = $postData['name'] ?? '';
            $menuType = $postData['type'] ?? '';
            $menuToggle = $postData['toggle'] ?? '';

            if(empty($menuName)){
                return ["status" => false, "message" => "Please provide your menu name."];
            }

            if(empty($menuType)){
                return ["status" => false, "message" => "Please provide your menu type. eg. mixed, veg, non-veg."];
            }

            if(empty($menuToggle) && $menuToggle != true && $menuToggle != false){
                return ["status" => false, "message" => "Please provide your menu toggle. eg. true, false."];
            }

            if(!in_array($menuType, ['mixed', 'none', 'vegan', 'non_vegan', 'mixed'])){
                return ["status" => false, "message" => "Sorry, but this menu type is not supported."];
            }

            $isMenuExist = $menu->isNameUsed($menuId, $partnerId, $menuName);
            if($isMenuExist){
                return ["status" => false, "message" => "Sorry, but this menu name has already been used."];
            }

            $menu->setMenu($postData, $partnerId);
            return ["status" => true, "message" => "Menu updated successfully."];
        }

        if($action === 'arrange-menu'){
            $menuCategory = $postData['category'] ?? [];
            if(empty($menuCategory)){
                return ["status" => false, "message" => "Please provide at least one category."];
            }

            $menuArrangement = [];
            $menuIdNotExist = 0;
            foreach($menuCategory as $val){
                $menuId = (int) $val['menu_id'] ?? 0;
                $menuData = $menu->getById($menuId, $partnerId, 'menu_id');

                if(empty($menuData)){
                    $menuIdNotExist++;
                }

                $menuArrangement[] = [
                    "menu_id" => $val['menu_id'],
                    "menu_sort" => $val['menu_sorting']
                ];
            }

            if($menuIdNotExist > 0){
                return ["status" => false, "message" => "Sorry, but {$menuIdNotExist} menu(s) does not exist."];
            }

            $menu->arrangeMenu($menuArrangement, $partnerId);

            return ["status" => true, "message" => "Menu arrangement updated successfully."];
        }

        if($action === 'mark-menu'){
            $menuArray = $postData['menu_id'] ?? [];
            $action = $postData['action'] ?? '';

            if(empty($menuArray)){
                return ["status" => false, "message" => "Please mark at least one menu."];
            }

            if(empty($action)){
                return ["status" => false, "message" => "Please provide your action. eg. unavailable, available."];
            }

            if(!\in_array($action, ['available', 'unavailable', 'delete'])){
                return ["status" => false, "message" => "Sorry, but this action is not supported."];
            }

            $menuIdNotExist = 0;
            foreach($menuArray as $val){
                $menuId = (int) $val;
                $menuData = $menu->getById($menuId, $partnerId, 'menu_id');

                if(empty($menuData)){
                    $menuIdNotExist++;
                }
            }

            if($menuIdNotExist > 0){
                return ["status" => false, "message" => "Sorry, but {$menuIdNotExist} menu(s) does not exist."];
            }

            if(\in_array($action, ['available', 'unavailable'])){
                $menu->bulkStatus($partnerId, $menuArray, $action);
            }elseif($action === 'delete'){
                $menu->bulkDelete($partnerId, $menuArray);
            }

            $actionText = ["delete" => "Selected menu(s) has been deleted.", "available" => "Selected menu(s) has been marked as available.", "unavailable" => "Selected menu(s) has been marked as unavailable."];
            return ["status" => true, "message" => $actionText[$action]];

        }

        if($action === 'mark-dish'){
            $menuId = (int) $postData['menu_id'] ?? 0;
            $action = $postData['action'] ?? '';

            if(empty($menuId)){
                return ["status" => false, "message" => "Please mark at least one menu."];
            }

            if(empty($action)){
                return ["status" => false, "message" => "Please provide your action. eg. unavailable, available."];
            }

            if(!\in_array($action, ['available', 'unavailable', 'delete'])){
                return ["status" => false, "message" => "Sorry, but this action is not supported."];
            }

            $menuData = $menu->getById($menuId, $partnerId, 'menu_id');
            $countDishMenu = $dish->countAllByMenuId($menuId, $partnerId);
            if(empty($menuData)){
                return ["status" => false, "message" => "Sorry, but menu category does not exist."];
            }

            if($countDishMenu < 1){
                return ["status" => false, "message" => "Sorry, but menu category has no dish."];
            }

            if(\in_array($action, ['available', 'unavailable'])){
                $dish->bulkDishStatus($partnerId, $menuId, $action);
            }elseif($action === 'delete'){
                $dish->bulkDelete($menuId, $partnerId, $restaurantEmail);
            }

            $actionText = ["delete" => "Selected dishes has been deleted.", "available" => "Selected dishes has been marked as available.", "unavailable" => "Selected dishes has been marked as unavailable."];
            return ["status" => true, "message" => $actionText[$action]];

        }

        if($action === 'arrange-dishes'){
            $menuId = (int) $postData['menu_id'] ?? 0;
            $dishArray = $postData['dishes'] ?? [];

            if(empty($menuId)){
                return ["status" => false, "message" => "Please select a menu category."];
            }

            if(empty($dishArray)){
                return ["status" => false, "message" => "Dishes are required."];
            }

            $dishIdNotExist = 0;
            foreach($dishArray as $val){
                $dishesData = $dish->getById((int) $val['dish_id'], $partnerId, 'dish_id');
                if(empty($dishesData)){
                    $dishIdNotExist++;
                }
            }

            if($dishIdNotExist > 0){
                return ["status" => false, "message" => "Sorry, but {$dishIdNotExist} dish(s) does not exist."];
            }

            $results = $this->db->transaction(function ($database) use ($dishArray, $menuId, $partnerId){

                foreach($dishArray as $val){
                    $dishId = (int) $val['dish_id'];
                    $dishSorting = (int) $val['dish_sorting'];

                    $database->query("UPDATE restaurant_dish SET dish_sorting = ? WHERE dish_id = ? AND restaurant_id = ?", $dishSorting, $dishId, $partnerId);
                }

                return true;
            });

            if($results){
                return ["status" => true, "message" => "Dishes arranged successfully."];
            }else{
                return ["status" => false, "message" => "Something went wrong. Please try again later."];
            }
        }

        if($action === 'toggle-dish'){
            $dishId = (int) $postData['dish_id'] ?? 0;
            $toggle = $postData['action'] ?? '';

            if(empty($dishId)){
                return ["status" => false, "message" => "Please select a dish."];
            }

            if(!isset($toggle) || ($toggle !== true && $toggle !== false)){
                return ["status" => false, "message" => "Please provide your action. eg. unavailable, available."];
            }

            $dishData = $dish->getById($dishId, $partnerId, 'dish_id');
            if(empty($dishData)){
                return ["status" => false, "message" => "Sorry, but this dish does not exist."];
            }

            $toggleStatus = $toggle == true ? 'available' : 'unavailable';
            $dish->toggleStatus($dishId, $partnerId, $toggleStatus);
            return ["status" => true, "message" => "Dish status updated successfully."];
        }

        if($action === 'toggle-menu-dish'){
            $menuId = (int) $postData['menu_id'] ?? 0;
            $toggle = $postData['action'] ?? '';

            if(empty($menuId)){
                return ["status" => false, "message" => "Please mark at a menu category"];
            }

            if(!isset($toggle) || ($toggle !== true && $toggle !== false)){
                return ["status" => false, "message" => "Please provide your action. eg. unavailable, available."];
            }

            $menuData = $menu->getById($menuId, $partnerId, 'menu_id');
            if(empty($menuData)){
                return ["status" => false, "message" => "Sorry, but this menu category does not exist."];
            }

            $toggleStatus = $toggle == true ? 'available' : 'unavailable';
            $dish->toggleMenuDishStatus($menuId, $partnerId, $toggleStatus);
            return ["status" => true, "message" => "Menu dish status updated successfully."];
        }

        if($action === 'assign-dish'){
            $menuId = (int) $postData['menu_id'] ?? 0;
            $dishArray = $postData['dish'] ?? [];

            if(empty($menuId)){
                return ["status" => false, "message" => "Please select a menu category."];
            }

            if(empty($dishArray)){
                return ["status" => false, "message" => "Please mark at least one dish."];
            }

            $dishIdNotExist = 0;
            foreach($dishArray as $val){
                $dishId = (int) $val;
                $dishesData = $dish->getById($dishId, $partnerId, 'dish_id');
                if(empty($dishesData)){
                    $dishIdNotExist++;
                }
            }

            if($dishIdNotExist > 0){
                return ["status" => false, "message" => "Sorry, but {$dishIdNotExist} dish(s) does not exist."];
            }

            $results = $this->db->transaction(function ($database) use ($dishArray, $menuId, $partnerId) {
                $database->query("UPDATE restaurant_dish SET menu_id = ? WHERE restaurant_id = ? AND dish_id IN (" . implode(',', $dishArray) . ") ", $menuId, $partnerId);
                return true;
            });

            if($results){
                return ["status" => true, "message" => "Dish(s) assigned successfully."];
            }else{
                return ["status" => false, "message" => "Sorry, but an error has occurred."];
            }
        }

        if($action === 'dish-image'){
            $dishId = (int) $postData['dish_id'] ?? 0;
            $dishBanner = $_FILES['dish_banner'] ?? '';

            if(empty($dishId)){
                return ["status" => false, "message" => "Please provide your dish id."];
            }

            $dishData = $dish->getById($dishId, $partnerId, 'dish_id, dish_title, dish_image');
            if(empty($dishData)){
                return ["status" => false, "message" => "Sorry, but this dish does not exist."];
            }

            if(empty($dishBanner)){
                return ["status" => false, "message" => "Please upload your dish banner."];
            }

            $result = $this->db->transaction(function ($database) use ($dishDefaultDirectory, $dishCompressedDirectory, $dish, $partnerId, $dishId, $dishBanner, $dishData) {                
                $uploads = new Uploads;

                // delete the default images
                $uploads->deleteExistingFile($dishData->dish_image, $dishDefaultDirectory . 'dish/');
                // delete the compressed webp images as well
                $webImage = $this->getWebpName($dishData->dish_image);
                $uploads->deleteExistingFile($webImage, $dishCompressedDirectory . 'dish/');


                // upload image and convert to webp
                $dishPhoto = mt_rand(1000000, 99999999) . '.' . pathinfo($dishBanner['name'], PATHINFO_EXTENSION);
                $uploads->uploadFile('dish_banner', $dishDefaultDirectory . 'dish/', $dishPhoto);
                $uploads->convertImageToWebp($dishPhoto, $dishDefaultDirectory . 'dish/', $dishCompressedDirectory . 'dish/');

                $database->query("UPDATE restaurant_dish SET dish_image = ?
                WHERE dish_id = ? AND restaurant_id = ?", $dishPhoto, $dishId, $partnerId);

                return true;
            });

            if($result){
                return ["status" => true, "message" => "Dish image updated successfully."];
            }else{
                return ["status" => false, "message" => "Sorry, but an error has occurred."];
            }
        }

        if($action === 'dish'){
            $dishId = (int) $postData['dish_id'] ?? 0;
            $menuId = (int) $postData['menu_id'] ?? 0;
            $dishTitle = $postData['dish_title'] ?? '';
            $dishType = $postData['dish_type'] ?? '';
            $dishRegularPrice = $postData['dish_regular_price'] ?? 0;
            $dishDiscountPrice = $postData['dish_discount_price'] ?? 0;
            $dishDailyQuantity = $postData['dish_daily_quantity'] ?? 0;
            $dishPreparationCost = $postData['dish_preparation_cost'] ?? 0;
            $dishWeight = $postData['dish_weight'] ?? 0;
            $dishStatus = $postData['dish_status'] ?? '';
            $dishDescription = $postData['dish_description'] ?? '';
            $dishAvailability = $postData['dish_availability'] ?? '';

            if(empty($dishId)){
                return ["status" => false, "message" => "Please provide your dish id."];
            }

            $dishData = $dish->getById($dishId, $partnerId, 'dish_id, dish_title, dish_image');
            $menuData = $menu->getById($menuId, $partnerId, 'menu_id');

            if(empty($dishData)){
                return ["status" => false, "message" => "Sorry, but this dish id does not exist."];
            }

            if(empty($menuId)){
                return ["status" => false, "message" => "Please select a menu category."];
            }

            if(empty($menuData)){
                return ["status" => false, "message" => "Sorry, but selected menu was not found."];
            }

            if(empty($dishTitle)){
                return ["status" => false, "message" => "Please provide your dish name."];
            }

            if($dishData->dish_title == $dishTitle && $dishId != $dishData->dish_id){
                return ["status" => false, "message" => "Sorry, but this dish name already exists."];
            }

            if(empty($dishType)){
                return ["status" => false, "message" => "Please provide your dish type. eg. Vegetarian, Non-Vegetarian, Mixed."];
            }

            if(empty($dishRegularPrice) || !is_numeric($dishRegularPrice)){
                return ["status" => false, "message" => "Please provide your dish regular price."];
            }

            if(empty($dishDailyQuantity) && ($dishDailyQuantity != '0' || $dishDailyQuantity != '')){
                return ["status" => false, "message" => "Please provide your dish daily quantity."];
            }

            if(empty($dishPreparationCost) && ($dishPreparationCost != 0)){
                return ["status" => false, "message" => "Please provide your dish preparation cost."];
            }

            if(empty($dishWeight) && $dishWeight != '0'){
                return ["status" => false, "message" => "Please provide your dish weight."];
            }

            if(empty($dishStatus) && ($dishStatus != 'true' || $dishStatus != 'false')){
                return ["status" => false, "message" => "Please provide your dish status. eg. true, false."];
            }

            if(empty($dishDescription)){
                return ["status" => false, "message" => "Please provide your dish description."];
            }

            if(!in_array($dishType, ['vegan', 'non_vegan', 'mixed', 'none'])){
                return ["status" => false, "message" => "Sorry, but this dish type is not allowed."];
            }

            if(empty($dishAvailability)){
                return ["status" => false, "message" => "Please provide your dish availability"];
            }

            if(count($dishAvailability) < 7){
                return ["status" => false, "message" => "Please provide your dish availability for all days"];
            }

            $result = $this->db->transaction(function ($database) use ($partnerId, $dish, $dishId, $menuId, $dishTitle, $dishType, $dishWeight, $dishRegularPrice, $dishDiscountPrice, $dishPreparationCost, $dishDailyQuantity, $dishDescription, $dishStatus, $dishAvailability)
            {
                $dishSlug = Helper::slugify($dishTitle);
                $dishWeight = (float) $dishWeight;
                $dishRegularPrice = (float) $dishRegularPrice;
                $dishDiscountPrice = (float) $dishDiscountPrice;
                $dishPreparationCost = (float) $dishPreparationCost;
                $dishDailyQuantity = (int) $dishDailyQuantity;
                $dishStatus = $dishStatus == true ? 'available' : 'unavailable';

                $database->query("UPDATE restaurant_dish SET
                    menu_id = '{$menuId}',
                    dish_title = '{$dishTitle}',
                    dish_slug = '{$dishSlug}',
                    dish_type = '{$dishType}',
                    dish_quantity = '{$dishDailyQuantity}',
                    dish_regular_price = '{$dishRegularPrice}',
                    dish_sale_price = '{$dishDiscountPrice}',
                    dish_prepare_price = '{$dishPreparationCost}',
                    dish_description = '{$dishDescription}',
                    dish_weight = '{$dishWeight}',
                    dish_status = '{$dishStatus}'
                WHERE restaurant_id = ? AND dish_id = ? ", $partnerId, $dishId);

                foreach($dishAvailability as $val){
                    $workingDay = $val['day'];
                    $workingHour = $val['hour'];
                    $workingStatus = $val['toggle'] == true ? 'available' : 'unavailable';

                    $availabilityData = $dish->getAvailabilityByDay($workingDay, $dishId, $partnerId);
                    if(!empty($availabilityData)){

                        $database->query("UPDATE restaurant_dish_days SET
                        working_hour = '{$workingHour}',
                        working_status = '{$workingStatus}'
                        WHERE restaurant_id = ? AND dish_id = ? AND working_day = ? ", $partnerId, $dishId, $workingDay);
                    }else{
                        $database->query("INSERT INTO restaurant_dish_days", [
                            'dish_day_id' => NULL,
                            'dish_id' => $dishId,
                            'restaurant_id' => $partnerId,
                            'working_day' => $workingDay,
                            'working_hour' => $workingHour,
                            'working_status' => $workingStatus,
                        ]);
                    }
                }

                return true;
            });

            if($result){
                return ["status" => true, "message" => "Dish updated successfully."];
            }else{
                return ["status" => false, "message" => "Sorry, but something went wrong. Please try again later."];
            }
        }

        if($action === 'customized-item'){
            $itemId = (int) $postData['item_id'] ?? 0;
            $categoryId = (int) $postData['category_id'] ?? 0;
            $itemTitle = $postData['item_title'] ?? '';
            $itemType = $postData['item_type'] ?? '';
            $itemRegularPrice = $postData['item_regular_price'] ?? 0;
            $itemDiscountPrice = $postData['item_discount_price'] ?? 0;
            $itemDailyQuantity = $postData['item_daily_quantity'] ?? 0;
            $itemWeight = $postData['item_weight'] ?? 0;
            $itemStatus = $postData['item_status'] ?? '';
            $itemDescription = $postData['item_description'] ?? '';
            $itemAvailability = $postData['item_availability'] ?? '';

            if(empty($itemId)){
                return ["status" => false, "message" => "Please provide your side item credentials."];
            }

            $itemData = $customization->getItemById($itemId, $partnerId, 'item_title, item_image');
            $categoryData = $customization->getCategoryById($categoryId, $partnerId, 'category_id');
            if(empty($itemData)){
                return ["status" => false, "message" => "Sorry, but this side item does not exist.", 'is_exist' => false];
            }

            if(empty($itemData->item_image)){
                return ["status" => false, "message" => "Please upload your side item image first."];
            }

            if(empty($categoryId)){
                return ["status" => false, "message" => "Please select a side item category."];
            }

            if(empty($itemTitle)){
                return ["status" => false, "message" => "Please provide your side item name."];
            }

            if(empty($itemType)){
                return ["status" => false, "message" => "Please provide your side item type. eg. Vegetarian, Non-Vegetarian or Mixed."];
            }

            if(empty($itemRegularPrice) || !is_numeric($itemRegularPrice)){
                return ["status" => false, "message" => "Please provide your side item regular price."];
            }

            if(empty($itemDailyQuantity) && ($itemDailyQuantity != '0' || $itemDailyQuantity != '')){
                return ["status" => false, "message" => "Please provide your side item daily quantity."];
            }

            if(empty($itemWeight) && $itemWeight != '0'){
                return ["status" => false, "message" => "Please provide your side item weight."];
            }

            if(empty($itemStatus) && ($itemStatus != 'true' || $itemStatus != 'false')){
                return ["status" => false, "message" => "Please provide your side item availability status. eg. true, false."];
            }

            if(empty($itemDescription)){
                return ["status" => false, "message" => "Please provide your side item description."];
            }

            if($customization->isItemTitleUsed($itemTitle, $itemId, $partnerId)){
                return ["status" => false, "message" => "Sorry, but you cannot use this side item title."];
            }

            if(empty($categoryData)){
                return ["status" => false, "message" => "Sorry, but selected side item category was not found."];
            }

            if(!in_array($itemType, ['vegan', 'non_vegan', 'mixed', 'none'])){
                return ["status" => false, "message" => "Sorry, but this side item type is not allowed."];
            }

            if(empty($itemAvailability)){
                return ["status" => false, "message" => "Please provide your side item days availability"];
            }

            if(count($itemAvailability) < 7){
                return ["status" => false, "message" => "Please provide your side item availability for all days"];
            }

            $result = $this->db->transaction(function ($database) use ($customization, $partnerId, $itemId, $categoryId, $itemTitle, $itemType, $itemRegularPrice, $itemDiscountPrice, $itemDailyQuantity, $itemWeight, $itemStatus, $itemDescription, $itemAvailability) {
                $itemSlug = Helper::slugify($itemTitle);
                $itemWeight = (float) $itemWeight;
                $itemRegularPrice = (float) $itemRegularPrice;
                $itemDiscountPrice = (float) $itemDiscountPrice;
                $itemDailyQuantity = (int) $itemDailyQuantity;
                $itemStatus = $itemStatus == true ? 'available' : 'unavailable';

                $database->query("UPDATE restaurant_customized_item SET
                category_id = ?,
                item_title = ?,
                item_slug = ?,
                item_type = ?,
                item_regular_price = ?,
                item_sale_price = ?,
                item_quantity = ?,
                item_weight = ?,
                item_status = ?,
                item_description = ?
                WHERE item_id = ? AND restaurant_id = ?",
                $categoryId, $itemTitle, $itemSlug, $itemType, $itemRegularPrice, $itemDiscountPrice, $itemDailyQuantity, $itemWeight, $itemStatus, $itemDescription, $itemId, $partnerId);

                foreach($itemAvailability as $key => $value){
                    $workingDay = $value['day'];
                    $workingHour = $value['hour'];
                    $workingStatus = $value['toggle'] == true ? 'available' : 'unavailable';

                    $availabilityData = $customization->getItemAvailabilityByDay($workingDay, $itemId, $partnerId);
                    if(!empty($availabilityData)){
                        $database->query("UPDATE restaurant_customized_days SET
                        working_hour = '{$workingHour}',
                        working_status = '{$workingStatus}'
                        WHERE restaurant_id = ? AND item_id = ? AND working_day = ?",
                        $partnerId, $itemId, $workingDay);
                    }else{
                        $database->query("INSERT INTO restaurant_customized_days", [
                            'days_id' => NULL,
                            'item_id' => $itemId,
                            'restaurant_id' => $partnerId,
                            'working_day' => $value['day'],
                            'working_hour' => $value['hour'],
                            'working_status' => $value['toggle']  == true ? 'available' : 'unavailable'
                        ]);
                    }
                }

                return true;
            });

            if($result){
                return ["status" => true, "message" => "Side item updated successfully."];
            }else{
                return ["status" => false, "message" => "Sorry, but something went wrong. Please try again later."];
            }
        }

        if($action === 'customized-item-image'){
            $itemId = (int) $postData['item_id'] ?? 0;
            $itemBanner = $_FILES['item_banner'] ?? '';

            if(empty($itemId)){
                return ["status" => false, "message" => "Please provide side item credentials."];
            }

            $itemData = $customization->getItemById($itemId, $partnerId, 'item_id, item_title, item_image');
            if(empty($itemData)){
                return ["status" => false, "message" => "Sorry, but this side item does not exist."];
            }

            if(empty($itemBanner)){
                return ["status" => false, "message" => "Please upload your side item banner."];
            }

            $result = $this->db->transaction(function ($database) use ($dishDefaultDirectory, $dishCompressedDirectory, $customization, $partnerId, $itemId, $itemBanner, $itemData) {
                $uploads = new Uploads;
                $dishDefaultDir = $dishDefaultDirectory . 'side-item/';
                $dishCompressedDir = $dishCompressedDirectory . 'side-item/';

                // delete previous image
                $uploads->deleteExistingFile($dishDefaultDir, $itemData->item_image);

                // delete previous webp image
                $webpName = $this->getWebpName($itemData->item_image);
                $uploads->deleteExistingFile($dishCompressedDir, $webpName);

                // upload image and convert to webp
                $itemPhoto = mt_rand(1000000, 999999999) . '.' . pathinfo($itemBanner['name'], PATHINFO_EXTENSION);
                $uploads->uploadFile('item_banner', $dishDefaultDir, $itemPhoto);
                // convert uploaded image to webp
                $uploads->convertImageToWebp($itemPhoto, $dishDefaultDir, $dishCompressedDir);

                $database->query("UPDATE restaurant_customized_item SET
                item_image = ?
                WHERE item_id = ? AND restaurant_id = ?", $itemPhoto, $itemId, $partnerId);

                return true;
            });

            if($result){
                return ["status" => true, "message" => "Side item image updated successfully."];
            }else{
                return ["status" => false, "message" => "Sorry, but an error has occurred."];
            }
        }

        if($action === 'arrange-customized-item'){
            $itemIdNotExist = 0;
            $itemSortingNotInteger = 0;
            $categoryId = (int) $postData['category_id'] ?? 0;
            $sortingArray = $postData['item'] ?? [];

            $categoryData = $customization->getCategoryById($categoryId, $partnerId, 'category_id');
            if(empty($categoryId)){
                return ["status" => false, "message" => "Sorry but customized category is required."];
            }

            if(empty($categoryData)){
                return ["status" => false, "message" => "Sorry but customized category was not found."];
            }

            if(empty($sortingArray)){
                return ["status" => false, "message" => "Sorry but customized item list is empty."];
            }

            foreach($sortingArray as $val){
                $itemId = (int) $val['item_id'] ?? 0;
                $itemSorting = $val['item_sorting'] ?? 0;

                $itemData = $customization->getItemById($itemId, $partnerId, 'item_id');
                if(empty($itemData)){
                    $itemIdNotExist++;
                }

                if(!is_numeric($itemSorting)){
                    $itemSortingNotInteger++;
                }
            }

            if(!empty($itemIdNotExist)){
                return ["status" => false, "message" => "Sorry but {$itemIdNotExist} customized item was not found."];
            }

            if(!empty($itemSortingNotInteger)){
                return ["status" => false, "message" => "Sorry but {$itemSortingNotInteger} customized item sorting is invalid."];
            }

            $results = $this->db->transaction(function ($database) use ($categoryId, $sortingArray, $partnerId) {

                foreach($sortingArray as $val){
                    $itemId = (int) $val['item_id'] ?? 0;
                    $itemSorting = $val['item_sorting'] ?? 0;

                    $database->query("UPDATE restaurant_customized_item SET item_sorting = ?
                    WHERE item_id = ? AND (restaurant_id = ? AND category_id = ?)", $itemSorting, $itemId, $partnerId, $categoryId);
                }

                return true;
            });

            if($results){
                return ["status" => true, "message" => "Customized item sorting updated successfully."];
            }else{
                return ["status" => false, "message" => "Sorry, but an error has occurred."];
            }
        }

        if($action === 'mark-customized'){
            $categoryId = (int) $postData['category_id'] ?? 0;
            $markAs = $postData['action'] ?? '';

            if(empty($categoryId)){
                return ["status" => false, "message" => "Please select a customized category."];
            }

            if(empty($markAs)){
                return ["status" => false, "message" => "Please provide your action for this request."];
            }

            if(!in_array($markAs, ['available', 'unavailable', 'delete'])){
                return ["status" => false, "message" => "Please provide your action. eg. available, unavailable, delete."];
            }

            $categoryData = $customization->getCategoryById($categoryId, $partnerId, 'category_id');
            $itemArray = $customization->getAllItems($categoryId, $partnerId, 'all', 'item_id');
            if(empty($categoryData)){
                return ["status" => false, "message" => "Sorry, but this customized category does not exist."];
            }

            if(empty($itemArray)){
                return ["status" => false, "message" => "Sorry, but customized dishes were not found in this category."];
            }

            $result = $this->db->transaction(function ($database) use ($categoryId, $markAs, $partnerId) {

                if(in_array($markAs, ['available', 'unavailable'])){
                    $database->query("UPDATE restaurant_customized_item SET item_status = ?
                    WHERE (restaurant_id = ? AND category_id = ?) AND item_status != ?", $markAs, $partnerId, $categoryId, $markAs);
                }

                return true;
            });

            if($markAs === 'delete'){
                foreach($itemArray as $val){
                    $itemId = (int) $val->item_id;
                    $customization->deleteItemDish($itemId, $partnerId, $restaurantEmail);
                }
            }

            $actionMessage = [
                'delete' => 'These customized items has been deleted successfully.',
                'available' => 'These customized items has been marked as available.',
                'unavailable' => 'These customized items has been marked as unavailable.',
            ];

            if($result){
                return ["status" => true, "message" => $actionMessage[$markAs]];
            }else{
                return ["status" => false, "message" => "Sorry, but an error has occurred."];
            }
        }

        if($action === 'toggle-customized-item'){
            $itemId = (int) $postData['item_id'] ?? 0;
            $toggle = $postData['action'] ?? '';

            if(empty($itemId)){
                return ["status" => false, "message" => "Please select a side item dish."];
            }

            if(!isset($toggle) || ($toggle !== true && $toggle !== false)){
                return ["status" => false, "message" => "Please provide your action. eg. unavailable, available."];
            }

            $itemData = $customization->getItemById($itemId, $partnerId, 'item_id');
            if(empty($itemData)){
                return ["status" => false, "message" => "Sorry, but this side item does not exist."];
            }

            $toggleStatus = $toggle == true ? 'available' : 'unavailable';
            $customization->toggleItemStatus($toggleStatus, $itemId, $partnerId);
            return ["status" => true, "message" => "Side item status updated successfully."];
        }

        if($action === 'customized-category'){
            $categoryId = (int) $postData['category_id'] ?? 0;
            $categoryName = $postData['category_title'] ?? '';
            $categoryType = $postData['category_type'] ?? '';
            $selectableItems = (int) $postData['selectable_items'] ?? 0;

            if(empty($categoryId)){
                Helper::jsonResult(["status" => false, "message" => "Please provide your side item category."]);
            }

            if(empty($categoryName)){
                Helper::jsonResult(["status" => false, "message" => "Please provide your side item category name."]);
            }

            if(empty($categoryType)){
                Helper::jsonResult(["status" => false, "message" => "Please provide your category type. eg. veg, non-veg or mixed."]);
            }

            if(!in_array($categoryType, ['vegan', 'non_vegan', 'mixed', 'none'])){
                Helper::jsonResult(["status" => false, "message" => "Sorry, but this category type is not supported."]);
            }

            if(empty($selectableItems)){
                Helper::jsonResult(["status" => false, "message" => "Please provide number of selectable items."]);
            }

            $isCategoryUsed = $customization->isCategoryNameUsed($categoryId, $partnerId, $categoryName);
            if($isCategoryUsed){
                Helper::jsonResult(["status" => false, "message" => "Sorry, but this category name is already used."]);
            }

            $results = $this->db->transaction(function ($database) use ($categoryId, $categoryName, $categoryType, $selectableItems, $partnerId) {

                $categorySlug = Helper::slugify($categoryName);
                $database->query("UPDATE restaurant_customized_category SET
                category_title = ?,
                category_type = ?,
                category_slug = ?,
                selectable_item = ?
                WHERE category_id = ? AND restaurant_id = ?",
                $categoryName, $categoryType, $categorySlug, $selectableItems, $categoryId, $partnerId);

                return true;
            });

            if($results){
                return ["status" => true, "message" => "Side item category updated successfully."];
            }else{
                return ["status" => false, "message" => "Sorry, but an error has occurred."];
            }
        }

        if($action === 'arrange-customized-category'){
            $categoryIdNotExist = 0;
            $categorySortingNotInteger = 0;
            $sortingArray = $postData['category'] ?? [];

            if(empty($sortingArray)){
                return ["status" => false, "message" => "Sorry but customized category list is empty."];
            }

            foreach($sortingArray as $val){
                $categoryId = (int) $val['category_id'];
                $categorySorting = $val['category_sorting'];

                $categoryData =  $customization->getCategoryById($categoryId, $partnerId, 'category_id');
                if(empty($categoryData)){
                    $categoryIdNotExist++;
                }

                if(!is_int($categorySorting)){
                    $categorySortingNotInteger++;
                }
            }

            if($categoryIdNotExist > 0){
                return ["status" => false, "message" => "Sorry, but {$categoryIdNotExist} customized category does not exist."];
            }

            if($categorySortingNotInteger > 0){
                return ["status" => false, "message" => "Sorry, but {$categorySortingNotInteger} customized category sorting is invalid."];
            }

            $results = $this->db->transaction(function ($database) use ($sortingArray, $partnerId) {

                foreach($sortingArray as $val){
                    $categoryId = (int) $val['category_id'];
                    $categorySorting = (int) $val['category_sorting'];

                    $database->query("UPDATE restaurant_customized_category SET category_sorting = ? WHERE category_id = ? AND restaurant_id = ?", $categorySorting, $categoryId, $partnerId);
                }

                return true;
            });

            if($results){
                return ["status" => true, "message" => "Customized category arranged successfully."];
            }else{
                return ["status" => false, "message" => "Sorry, but an error has occurred."];
            }


        }

        return ["status" => false, "message" => "Sorry, but there's data to provide."];
    }

    /**
     * A description of the entire PHP function.
     *
     * @param string $action The action to create the data.
     * @return array
     */
    public function createData(string $action): array
    {
        if (empty($action)) {
            return ["status" => false, "message" => "Unauthorized access detected."];
        }

        if(!in_array($action, ['upload-dish-image', 'upload-customized-item-image'])){
            $postData = Helper::decodePostData();
        }else{
            $postData = $this->helper->sanitize_post();
        }

        if (empty($postData)) {
            return ["status" => false, "message" => "Sorry, no action was provided."];
        }

        $partnerId = intval($postData['id']);
        $restaurantData = $this->getById($partnerId, 'id, restaurant_email');
        $restaurantEmail = $restaurantData->restaurant_email;

        $dishDefaultDirectory = $this::$uploadDirectory . "/{$restaurantEmail}/" . $this::$defaultImages;
        $dishCompressedDirectory = $this::$uploadDirectory . "/{$restaurantEmail}/" . $this::$compressedImages;

        $menu = new Menu;
        $dish = new Dish;
        $customization = new Customizations;

        if (empty($restaurantData)) {
            return ["status" => false, "message" => "Sorry, but this restaurant does not exist."];
        }

        if($action === 'menu'){
            $menuName = $postData['name'] ?? '';
            $menuType = $postData['type'] ?? '';

            if(empty($menuName)){
                Helper::jsonResult(["status" => false, "message" => "Please provide your menu name."]);
            }

            if(empty($menuType)){
                Helper::jsonResult(["status" => false, "message" => "Please provide your menu type. eg. mixed, veg, non-veg."]);
            }

            if(!in_array($menuType, ['mixed', 'none', 'vegan', 'non_vegan', 'mixed'])){
                Helper::jsonResult(["status" => false, "message" => "Sorry, but this menu type is not supported."]);
            }

            $isMenuExist = $menu->isExist($menuName, $partnerId);
            if($isMenuExist){
                Helper::jsonResult(["status" => false, "message" => "Sorry, but this menu name has already been taken."]);
            }

            $menu->addMenu($postData, $partnerId);
            Helper::jsonResult(["status" => true, "message" => "Menu added successfully."]);
        }

        if($action === 'generate-dish-id'){
            $dishData = $dish->generateId($partnerId);
            return $dishData;
        }

        if($action === 'upload-dish-image'){
            $dishId = (int) $postData['dish_id'] ?? 0;
            $dishBanner = $_FILES['dish_banner'] ?? '';

            if(empty($dishId)){
                return ["status" => false, "message" => "Please provide your dish id."];
            }

            $dishData = $dish->getById($dishId, $partnerId, 'dish_id, dish_title, dish_image');
            if(empty($dishData)){
                return ["status" => false, "message" => "Sorry, but this dish does not exist.", 'is_exist' => false];
            }

            // if(!empty($dishData->dish_image) && !empty($dishData->dish_title)){
            //     return ["status" => false, "message" => "Sorry, but this dish data has been used, please create a new one.", 'is_exist' => true];
            // }

            if(empty($dishBanner)){
                return ["status" => false, "message" => "Please upload your dish banner."];
            }

            $result = $this->db->transaction(function ($database) use ($dishDefaultDirectory, $dishCompressedDirectory, $dish, $partnerId, $dishId, $dishBanner, $dishData) {
                $uploads = new Uploads;

                // delete existing image
                $uploads->deleteExistingFile($dishCompressedDirectory . 'dish/', $dishData->dish_image);

                // delete the compressed webp image
                $webpName = $this->getWebpName($dishData->dish_image);
                $uploads->deleteExistingFile($dishCompressedDirectory . 'dish/', $webpName);

                // upload image and convert to webp
                $dishPhoto = mt_rand(1000000, 999999999) . '.' . pathinfo($dishBanner['name'], PATHINFO_EXTENSION);
                $uploads->uploadFile('dish_banner', $dishDefaultDirectory . 'dish/', $dishPhoto);
                $uploads->convertImageToWebp($dishPhoto, $dishDefaultDirectory . 'dish/', $dishCompressedDirectory . 'dish/');

                $database->query("UPDATE restaurant_dish SET dish_image = ?
                WHERE dish_id = ? AND restaurant_id = ?", $dishPhoto, $dishId, $partnerId);

                return true;
            });

            if($result){
                return ["status" => true, "message" => "Dish image uploaded successfully."];
            }else{
                return ["status" => false, "message" => "Sorry, but something went wrong. Please try again later."];
            }
        }

        if($action === 'create-dish'){
            $dishId = (int) $postData['dish_id'] ?? 0;
            $menuId = (int) $postData['menu_id'] ?? 0;
            $dishTitle = $postData['dish_title'] ?? '';
            $dishType = $postData['dish_type'] ?? '';
            $dishRegularPrice = $postData['dish_regular_price'] ?? 0;
            $dishDiscountPrice = $postData['dish_discount_price'] ?? 0;
            $dishDailyQuantity = $postData['dish_daily_quantity'] ?? 0;
            $dishPreparationCost = $postData['dish_preparation_cost'] ?? 0;
            $dishWeight = $postData['dish_weight'] ?? 0;
            $dishStatus = $postData['dish_status'] ?? '';
            $dishDescription = $postData['dish_description'] ?? '';
            $dishAvailability = $postData['dish_availability'] ?? '';

            if(empty($dishId)){
                return ["status" => false, "message" => "Please provide your dish id."];
            }

            $dishData = $dish->getById($dishId, $partnerId, 'dish_title, dish_image');
            if(empty($dishData)){
                return ["status" => false, "message" => "Sorry, but this dish id does not exist.", 'is_exist' => false];
            }

            if(empty($dishData->dish_image)){
                return ["status" => false, "message" => "Please upload your dish image first."];
            }

            // if(!empty($dishData->dish_image) && !empty($dishData->dish_title)){
            //     return ["status" => false, "message" => "Sorry, but this dish data has been used, please create a new one.", 'is_exist' => true];
            // }

            if(empty($menuId)){
                return ["status" => false, "message" => "Please select a menu category."];
            }

            if(empty($dishTitle)){
                return ["status" => false, "message" => "Please provide your dish name."];
            }

            if(empty($dishType)){
                return ["status" => false, "message" => "Please provide your dish type. eg. Vegetarian, Non-Vegetarian, Mixed."];
            }

            if(empty($dishRegularPrice) || !is_numeric($dishRegularPrice)){
                return ["status" => false, "message" => "Please provide your dish regular price."];
            }

            if(empty($dishDailyQuantity) && ($dishDailyQuantity != '0' || $dishDailyQuantity != '')){
                return ["status" => false, "message" => "Please provide your dish daily quantity."];
            }

            if(empty($dishPreparationCost) && ($dishPreparationCost != 0)){
                return ["status" => false, "message" => "Please provide your dish preparation cost."];
            }

            if(empty($dishWeight) && $dishWeight != '0'){
                return ["status" => false, "message" => "Please provide your dish weight."];
            }

            if($dishStatus == '' && ($dishStatus != 'true' || $dishStatus != 'false')){
                return ["status" => false, "message" => "Please provide your dish status. eg. true, false."];
            }

            if(empty($dishDescription)){
                return ["status" => false, "message" => "Please provide your dish description."];
            }

            if($dish->isNameExist($dishTitle, $partnerId)){
                return ["status" => false, "message" => "Sorry, but this dish name has already been used."];
            }

            $menuData = $menu->getById((int) $menuId, $partnerId, 'menu_id');
            if(empty($menuData)){
                return ["status" => false, "message" => "Sorry, but selected menu was not found."];
            }

            if(!in_array($dishType, ['vegan', 'non_vegan', 'mixed', 'none'])){
                return ["status" => false, "message" => "Sorry, but this dish type is not allowed."];
            }

            if(empty($dishAvailability)){
                return ["status" => false, "message" => "Please provide your dish availability"];
            }

            if(count($dishAvailability) < 7){
                return ["status" => false, "message" => "Please provide your dish availability for all days"];
            }

            $result = $this->db->transaction(function ($database) use ($dish, $partnerId, $dishId, $menuId, $dishTitle, $dishType, $dishWeight, $dishRegularPrice, $dishDiscountPrice, $dishPreparationCost, $dishDailyQuantity, $dishDescription, $dishStatus, $dishAvailability
            ) {
                $dishSlug = Helper::slugify($dishTitle);
                $dishSorted = $dish->getNextSorting($menuId, $partnerId)->next_sorting;
                $dishWeight = (float) $dishWeight;
                $dishRegularPrice = (float) $dishRegularPrice;
                $dishDiscountPrice = (float) $dishDiscountPrice;
                $dishPreparationCost = (float) $dishPreparationCost;
                $dishDailyQuantity = (int) $dishDailyQuantity;
                $dishStatus = $dishStatus == true ? 'available' : 'unavailable';

                $database->query("UPDATE restaurant_dish SET
                    menu_id = '{$menuId}',
                    dish_title = '{$dishTitle}',
                    dish_slug = '{$dishSlug}',
                    dish_type = '{$dishType}',
                    dish_quantity = '{$dishDailyQuantity}',
                    dish_regular_price = '{$dishRegularPrice}',
                    dish_sale_price = '{$dishDiscountPrice}',
                    dish_prepare_price = '{$dishPreparationCost}',
                    dish_sorting = '{$dishSorted}',
                    dish_description = '{$dishDescription}',
                    dish_weight = '{$dishWeight}',
                    dish_status = '{$dishStatus}'
                WHERE restaurant_id = ? AND dish_id = ? ", $partnerId, $dishId);

                foreach($dishAvailability as $val){
                    $database->query("INSERT INTO restaurant_dish_days", [
                        'dish_day_id' => NULL,
                        'dish_id' => $dishId,
                        'restaurant_id' => $partnerId,
                        'working_day' => $val['day'],
                        'working_hour' => $val['hour'],
                        'working_status' => $val['toggle'] == true ?  'available' : 'unavailable',
                    ]);
                }

                // release dish id
                $dish->releaseDishId($dishId, $partnerId);

                return true;
            });

            if($result){
                return ["status" => true, "message" => "Dish added successfully."];
            }else{
                return ["status" => false, "message" => "Sorry, but something went wrong. Please try again later."];
            }
        }

        if($action === 'customized-category'){
            $dishId = (int) $postData['dish_id'] ?? 0;
            $categoryName = $postData['category_title'] ?? '';
            $categoryType = $postData['category_type'] ?? '';
            $selectableItems = (int) $postData['selectable_items'] ?? 0;

            $dishData = $dish->getById($dishId, $partnerId, 'dish_id');
            if(empty($dishId)){
                return ['status' => false, 'message' => 'Sorry but dish is required.'];
            }

            if(empty($dishData)){
                return ['status' => false, 'message' => 'Sorry but dish not found.'];
            }

            if(empty($categoryName)){
                return ["status" => false, "message" => "Please provide your category name."];
            }

            if(empty($categoryType)){
                return ["status" => false, "message" => "Please provide your category type. eg. veg, non-veg or mixed."];
            }

            if(!in_array($categoryType, ['vegan', 'non_vegan', 'mixed', 'none'])){
                return ["status" => false, "message" => "Sorry, but this category type is not supported."];
            }

            if(empty($selectableItems)){
                return ["status" => false, "message" => "Please provide your selectable items."];
            }

            if($customization->isCategoryExist($partnerId, $categoryName)){
                return ["status" => false, "message" => "Sorry, but this category name has already been taken."];
            }

            $results = $this->db->transaction(function ($database) use ($customization, $partnerId, $dishId, $categoryName, $categoryType, $selectableItems){

                $categorySlug = Helper::slugify($categoryName);
                $categorySorting = $customization->getCategoryNextSorting($dishId, $partnerId)->next_sorting;

                $database->query("INSERT INTO restaurant_customized_category", [
                    'category_id' => NULL,
                    "dish_id" => $dishId,
                    'restaurant_id' => $partnerId,
                    'selectable_item' => $selectableItems,
                    'category_title' => $categoryName,
                    'category_slug' => $categorySlug,
                    'category_type' => $categoryType,
                    'category_sorting' => $categorySorting,
                ]);

                return true;
            });

            if($results){
                return ["status" => true, "message" => "Category customization added successfully."];
            }else{
                return ["status" => false, "message" => "Sorry, but something went wrong. Please try again later."];
            }
        }

        if($action === 'generate-customized-itemid'){
            $dishId = (int) $postData['dish_id'] ?? 0;

            $dishData = $dish->getById($dishId, $partnerId, 'dish_id');
            if(empty($dishId)){
                return ['status' => false, 'message' => 'Sorry but dish is required.'];
            }

            if(empty($dishData)){
                return ['status' => false, 'message' => 'Sorry but dish not found.'];
            }

            $itemData = $customization->generateItemId($dishId, $partnerId);
            return $itemData;
        }

        if($action === 'upload-customized-item-image'){
            $itemId = (int) $postData['item_id'] ?? 0;
            $itemBanner = $_FILES['item_banner'] ?? '';

            if(empty($itemId)){
                return ["status" => false, "message" => "Please provide your side item credentials."];
            }

            $itemData = $customization->getItemById($itemId, $partnerId, 'item_id, item_title, item_image');
            if(empty($itemData)){
                return ["status" => false, "message" => "Sorry, but this side item dish does not exist.", 'is_exist' => false];
            }

            if(!empty($itemData->item_image) && !empty($itemData->item_title)){
                return ["status" => false, "message" => "Sorry, but this side item data has been used, please create a new one.", 'is_exist' => true];
            }

            if(empty($itemBanner)){
                return ["status" => false, "message" => "Please upload your side item banner."];
            }

            $result = $this->db->transaction(function ($database) use ($dishDefaultDirectory, $dishCompressedDirectory, $customization, $partnerId, $itemId, $itemBanner, $itemData) {
                $uploads = new Uploads;

                // delete the previous image on the server
                $uploads->deleteExistingFile($dishDefaultDirectory . 'side-item/', $itemData->item_image);
                // delete the compressed webp image on the server
                $webName = $this->getWebpName($itemData->item_image);
                $uploads->deleteExistingFile($dishCompressedDirectory . 'side-item/', $webName);

                // upload image and convert to webp
                $itemPhoto = mt_rand(1000000, 99999999999) . '.' . pathinfo($itemBanner['name'], PATHINFO_EXTENSION);
                $uploads->uploadFile('item_banner', $dishDefaultDirectory . 'side-item/', $itemPhoto);
                $uploads->convertImageToWebp($itemPhoto, $dishDefaultDirectory . 'side-item/', $dishCompressedDirectory . 'side-item/');

                $database->query("UPDATE restaurant_customized_item SET item_image = ?
                WHERE item_id = ? AND restaurant_id = ?", $itemPhoto, $itemId, $partnerId);

                return true;
            });

            if($result){
                return ["status" => true, "message" => "Side item dish image uploaded successfully."];
            }else{
                return ["status" => false, "message" => "Sorry, but something went wrong. Please try again later."];
            }
        }

        if($action === 'create-customized-item'){
            $itemId = (int) $postData['item_id'] ?? 0;
            $categoryId = (int) $postData['category_id'] ?? 0;
            $itemTitle = $postData['item_title'] ?? '';
            $itemType = $postData['item_type'] ?? '';
            $itemRegularPrice = $postData['item_regular_price'] ?? 0;
            $itemDiscountPrice = $postData['item_discount_price'] ?? 0;
            $itemDailyQuantity = $postData['item_daily_quantity'] ?? 0;
            $itemWeight = $postData['item_weight'] ?? 0;
            $itemStatus = $postData['item_status'] ?? '';
            $itemDescription = $postData['item_description'] ?? '';
            $itemAvailability = $postData['item_availability'] ?? '';

            if(empty($itemId)){
                return ["status" => false, "message" => "Please provide your side item credentials."];
            }

            $itemData = $customization->getItemById($itemId, $partnerId, 'item_title, item_image');
            if(empty($itemData)){
                return ["status" => false, "message" => "Sorry, but this side item does not exist.", 'is_exist' => false];
            }

            if(empty($itemData->item_image)){
                return ["status" => false, "message" => "Please upload your side item image first."];
            }

            if(!empty($itemData->item_image) && !empty($itemData->item_title)){
                return ["status" => false, "message" => "Sorry, but this side item data has been used, please create a new one.", 'is_exist' => true];
            }

            if(empty($categoryId)){
                return ["status" => false, "message" => "Please select a customized item category."];
            }

            if(empty($itemTitle)){
                return ["status" => false, "message" => "Please provide your side item name."];
            }

            if(empty($itemType)){
                return ["status" => false, "message" => "Please provide your side item type. eg. Vegetarian, Non-Vegetarian or Mixed."];
            }

            if(empty($itemRegularPrice) || !is_numeric($itemRegularPrice)){
                return ["status" => false, "message" => "Please provide your side item regular price."];
            }

            if(empty($itemDailyQuantity) && ($itemDailyQuantity != '0' || $itemDailyQuantity != '')){
                return ["status" => false, "message" => "Please provide your side item daily quantity."];
            }

            if(empty($itemWeight) && $itemWeight != '0'){
                return ["status" => false, "message" => "Please provide your side item weight."];
            }

            if(empty($itemStatus) && ($itemStatus != 'true' || $itemStatus != 'false')){
                return ["status" => false, "message" => "Please provide your side item availability status. eg. true, false."];
            }

            if(empty($itemDescription)){
                return ["status" => false, "message" => "Please provide your side item description."];
            }

            if($customization->isItemNameExist($itemTitle, $partnerId)){
                return ["status" => false, "message" => "Sorry, but this side item title has already been used."];
            }

            $categoryData = $customization->getCategoryById($categoryId, $partnerId, 'category_id');
            if(empty($categoryData)){
                return ["status" => false, "message" => "Sorry, but selected side item category was not found."];
            }

            if(!in_array($itemType, ['vegan', 'non_vegan', 'mixed', 'none'])){
                return ["status" => false, "message" => "Sorry, but this side item type is not allowed."];
            }

            if(empty($itemAvailability)){
                return ["status" => false, "message" => "Please provide your side item days availability"];
            }

            if(count($itemAvailability) < 7){
                return ["status" => false, "message" => "Please provide your side item availability for all days"];
            }

            $result = $this->db->transaction(function ($database) use ($customization, $partnerId, $itemId, $categoryId, $itemTitle, $itemType, $itemRegularPrice, $itemDiscountPrice, $itemDailyQuantity, $itemWeight, $itemStatus, $itemDescription, $itemAvailability) {
                $itemSlug = Helper::slugify($itemTitle);
                $itemSorted = $customization->getItemNextSorting($categoryId, $partnerId)->next_sorting;
                $itemWeight = (float) $itemWeight;
                $itemRegularPrice = (float) $itemRegularPrice;
                $itemDiscountPrice = (float) $itemDiscountPrice;
                $itemDailyQuantity = (int) $itemDailyQuantity;
                $itemStatus = $itemStatus == true ? 'available' : 'unavailable';

                $database->query("UPDATE restaurant_customized_item SET
                category_id = ?,
                item_title = ?,
                item_slug = ?,
                item_type = ?,
                item_regular_price = ?,
                item_sale_price = ?,
                item_quantity = ?,
                item_weight = ?,
                item_sorting = ?,
                item_status = ?,
                item_description = ?,
                created_at = ?,
                is_reserved = 'false'
                WHERE item_id = ? AND restaurant_id = ?",
                $categoryId, $itemTitle, $itemSlug, $itemType, $itemRegularPrice, $itemDiscountPrice, $itemDailyQuantity, $itemWeight, $itemSorted, $itemStatus, $itemDescription, DATENOW, $itemId, $partnerId);

                foreach($itemAvailability as $key => $value){
                    $database->query("INSERT INTO restaurant_customized_days", [
                        'days_id' => NULL,
                        'item_id' => $itemId,
                        'restaurant_id' => $partnerId,
                        'working_day' => $value['day'],
                        'working_hour' => $value['hour'],
                        'working_status' => $value['toggle']  == true ? 'available' : 'unavailable'
                    ]);
                }

                return true;
            });

            if($result){
                return ["status" => true, "message" => "Side item created successfully."];
            }else{
                return ["status" => false, "message" => "Sorry, but something went wrong. Please try again later."];
            }
        }

        return ["status" => false, "message" => "Sorry, but this action is not supported."];
    }

    /**
     * Deletes data based on the given action.
     *
     * @param string $action The action to perform the deletion.
     * @return array
     */
    public function deleteData(string $action): array
    {
        if (empty($action)) {
            return ["status" => false, "message" => "Unauthorized access detected."];
        }

        $postData = Helper::decodePostData();

        if (empty($postData)) {
            return ["status" => false, "message" => "Sorry, no action was provided."];
        }

        $partnerId = (int) $postData['id'];
        $restaurantData = $this->getById($partnerId, 'id, restaurant_name, restaurant_email');
        $restaurantEmail = $restaurantData->restaurant_email ?? '';

        if (empty($restaurantData)) {
            return ["status" => false, "message" => "Sorry, but this restaurant does not exist."];
        }

        $menu = new Menu;
        $dish = new Dish;
        $customization = new Customizations;

        if($action === 'menu'){
            $menuId = (int) $postData['menu_id'] ?? 0;
            if(empty($menuId)){
                return ["status" => false, "message" => "Sorry, but this menu seems to be missing."];
            }

            $menuData = $menu->getById($menuId, $partnerId);
            if(empty($menuData)){
                return ["status" => false, "message" => "Sorry, but this menu does not exist."];
            }

            $menu->deleteMenu($menuId, $partnerId, $restaurantEmail);
            return ["status" => true, "message" => "Menu deleted successfully."];
        }

        if($action === 'dish'){

            $dishId = (int) $postData['dish_id'] ?? 0;
            if(empty($dishId)){
                return ["status" => false, "message" => "Sorry, but this dish seems to be missing."];
            }

            $menuData = $dish->getById($dishId, $partnerId, 'dish_id, dish_image');
            if(empty($menuData)){
                return ["status" => false, "message" => "Sorry, but this dish does not exist."];
            }

            $dish->deleteDish($dishId, $partnerId, $restaurantEmail);
            return ["status" => true, "message" => "This dish has been deleted successfully."];
        }

        if($action === 'customized-item'){

            $itemId = (int) $postData['item_id'] ?? 0;
            if(empty($itemId)){
                return ["status" => false, "message" => "Sorry, but this customized dish seems to be missing."];
            }

            $itemData = $customization->getItemById($itemId, $partnerId, 'item_id, item_image');
            if(empty($itemData)){
                return ["status" => false, "message" => "Sorry, but this customized item dish does not exist."];
            }

            $customization->deleteItemDish($itemId, $partnerId, $restaurantEmail);
            return ["status" => true, "message" => "Customized item has been deleted successfully."];
        }

        if($action === 'customized-category'){
            $categoryId = (int) $postData['category_id'] ?? 0;
            if(empty($categoryId)){
                return ["status" => false, "message" => "Sorry, but this customized item category seems to be missing."];
            }

            $categoryData = $customization->getCategoryById($categoryId, $partnerId, 'category_id');
            if(empty($categoryData)){
                return ["status" => false, "message" => "Sorry, but this customized category does not exist."];
            }

            $customization->deleteCategory($categoryId, $partnerId, $restaurantEmail);
            return ['status' => true, 'message' => 'Customized item category and item dishes has been deleted successfully.'];
        }

        return ["status" => false, "message" => "Sorry, no action was provided."];
    }

    /**
     * Sets up the wizard for a restaurant onboarding process.
     *
     * @param string $action The action to perform in the wizard.
     * @return array
     */
    public function setupWizard(string $action): array
    {

        if (empty($action)) {
            return ["status" => false, "message" => "Unauthorized access detected."];
        }

        $postData = Helper::decodePostData();

        if (empty($postData)) {
            return ["status" => false, "message" => "Please provide your details."];
        }

        $partnerId = (int) $postData['id'];
        $restaurantData = $this->getById($partnerId, 'id, restaurant_name');
        if (empty($restaurantData)) {
            return ["status" => false, "message" => "Sorry, but this restaurant does not exist."];
        }

        if ($this->isOnboardingCompleted($partnerId)) {
            return ["status" => false, "message" => "You've already completed the onboarding process."];
        }

        if ($action === 'business-info') {

            $partnerName = $postData['name'];
            $partnerType = Helper::trim($postData['type']);
            $partnerType = Helper::lower($partnerType);

            $response = $this->onboardingFirst($partnerId, $partnerName, $partnerType);
            return $response;
        }

        if ($action === 'opening-hours') {
            $workingHours = $postData['openingHours'];

            $response = $this->onboardingSecond($partnerId, $workingHours);
            return $response;
        }

        if ($action === 'contact-info') {
            $phoneNumber = $postData['phoneNumber'];
            $whatsappNumber = $postData['whatsappNumber'];

            $response = $this->onboardingThird($partnerId, $phoneNumber, $whatsappNumber);
            return $response;
        }

        if ($action === 'location') {
            $partnerLatitude = $postData['latitude'];
            $partnerLongitude = $postData['longitude'];

            $response = $this->onboardingLast($partnerId, $partnerLatitude, $partnerLongitude);
            return $response;
        }

        return ['status' => false, 'message' => 'Sorry, no action was provided.'];
    }
}
