<?php

namespace App\Http\Controllers\Admin\Orders;

use App\Helpers\UUIDHelper;
use App\Http\Controllers\Controller;
use App\Models\Consignment;
use App\Models\ConsignmentItem;
use App\Models\File;
use App\Models\Inventory;
use App\Models\Order;
use App\Models\OrderGroup;
use App\Models\PaymentMeta;
use App\Models\PendingPayment;
use App\Models\Setting;
use App\Models\Store;
use App\Models\Transaction;
use App\Models\User;
use App\Notifications\CancelRequestConsignment;
use App\Notifications\OrderCancellation;
use App\Notifications\OrderRejected;
use App\Notifications\OrderSent;
use App\Notifications\OrderStartProcess;
use App\Notifications\RequestConsignment;
use App\Notifications\SellerReturnConsignmentItem;
use App\Notifications\UserReturnConsignmentItem;
use App\Services\Admin\Orders\OrdersService;
use App\Services\Cart\CartService;
use App\Services\UPG\DigipayService;
use App\Services\UPG\SnapppayService;
use App\Services\UPG\TorobpayService;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Inertia\Inertia;

class OrdersController extends Controller
{
    use UUIDHelper;

    // properties
    protected SnapppayService $snapppayService;
    protected DigipayService $digipayService;
    protected TorobpayService $torobpayService;

    public function __construct(SnapppayService $snapppayService, DigipayService $digipayService, TorobpayService $torobpayService)
    {
        $this->snapppayService = $snapppayService;
        $this->digipayService = $digipayService;
        $this->torobpayService = $torobpayService;
    }

    /**
     * show order details
     */
    public function show(Order $order, CartService $cartService)
    {
        // order group
        $orderGroup = $order->orderGroup;

        $taxAmount = 0;

        /** get dynamic tax amount form va_tax_percent in order model */
        // selected address
        $selectedAddress = $order->address != null ? unserialize($order->address) : null;
        // consignments information array
        $consignmentsInformation = $cartService->sepratedConsignmentInformation($order, $selectedAddress, true);
        // tax amount
        $taxAmount = $consignmentsInformation['financial']['taxAmount'];
        /**** end ****/

        // order
        $order = [
            'id' => $order->id,
            'uuid' => $order->uuid,
            'order_group_uuid' => $order->orderGroup->uuid,
            'send_by' => $order->send_by,
            'get_address' => $order->get_address,
            'is_all_item_cancelled' => $order->is_all_item_cancelled,
            'is_ready_to_send' => $order->is_ready_to_send,
            'post_tracking_code' => $order->post_tracking_code,
            'is_awaiting_request_from_seller' => $order->is_awaiting_request_from_seller,
            'is_awaiting_seller' => $order->is_awaiting_seller,
            'is_awaiting_receipt_from_seller' => $order->is_awaiting_receipt_from_seller,

            'get_total_bill' => $order->get_total_bill,

            'get_shares' => $order->get_shares,
            'get_consolidated_shares' => $order->get_consolidated_shares,

            'get_discount' => $order->get_discount,
            'va_tax_percent' => $order->va_tax_percent,
            'tax_amount' => $taxAmount,
            'get_send_method' => $order->get_send_method,
            'send_time' => $order->send_time,
            'description' => $order->description,
            'jalali_created_at' => $order->jalali_created_at,
            'start_process' => $order->start_process,
            'status' => $order->status,

            'consignments' => Consignment::where('order_id', $order->id)->with([
                'store',
                'consignmentItems.product',
                'consignmentItems.store',
                'consignmentItems.storage'
            ])->orderByRaw('store_id IS NULL DESC')->get()->map(fn($consignment) => [
                'id' => $consignment->id,
                'uuid' => $consignment->uuid,
                'has_awaiting_request_from_seller' => $consignment->has_awaiting_request_from_seller,
                'is_all_product_sent' => $consignment->is_all_product_sent,
                'is_products_awaiting_receipt_from_seller' => $consignment->is_products_awaiting_receipt_from_seller,
                'tracking_code' => $consignment->tracking_code,
                'get_address' => $consignment->get_address,
                'status' => $consignment->status,

                'consignment_items' => $consignment->consignmentItems->map(fn($item) => [
                    'id' => $item->id,
                    'get_props' => $item->get_props,
                    'get_options' => $item->get_options,
                    'get_full_count_price' => $item->get_full_count_price,
                    'count' => $item->count,
                    'price' => $item->price,
                    'discount' => $item->discount,
                    'get_shares' => $item->get_shares,
                    'reason' => $item->reason,
                    'status' => $item->status,

                    'storage' => $item->storage != null ? [
                        'id' => $item->storage->id,
                        'name' => $item->storage->name,
                    ] : [],
                    'store' => $item->store != null ? [
                        'id' => $item->store->id,
                        'uuid' => $item->store->uuid,
                        'name' => $item->store->name,
                    ] : null,
                    'product' => [
                        'id' => $item->product->id,
                        'title' => $item->product->title,
                        'slug' => $item->product->slug,
                        'get_images' => $item->product->get_images,
                        'commission' => $item->product->commission,
                    ],
                ]),
                'store' => $consignment->store != null ? [
                    'id' => $consignment->store->id,
                    'uuid' => $consignment->store->uuid,
                    'name' => $consignment->store->name,
                ] : null,
            ]),
            'user' => [
                'id' => $order->user->id,
                'get_name' => $order->user->get_name,
                'phone' => $order->user->phone,
            ],
        ];

        // get main payment meta
        $paymentMeta = PaymentMeta::where('store_id', null)->first();

        // order payment transaction
        $paymentTransaction = Transaction::where('transaction_id', $orderGroup->payment_transaction_uuid)->first();
        $returnResponse = [];
        if ($paymentTransaction) {
            $returnResponse = json_decode($paymentTransaction->return_response, true);
            $returnResponse = is_array($returnResponse) ? $returnResponse : [];
        }

        // check snapppay
        $isSnapppay = false;
        if ($paymentTransaction && $paymentTransaction->payment_gateway == 'snapppay') {
            $isSnapppay = true;
        }

        // check digipay upg
        $isDigipayUpg = false;
        if ($paymentTransaction && $paymentTransaction->payment_gateway == 'digipay' && array_key_exists('type', $returnResponse) && in_array((int)$returnResponse['type'], [5, 11, 13, 24])) {
            $isDigipayUpg = true;
        }

        // check azki
        $isAzki = false;
        if ($paymentTransaction && $paymentTransaction->payment_gateway == 'azki') {
            $isAzki = true;
        }

        // check torobpay
        $isTorobpay = false;
        if ($paymentTransaction && $paymentTransaction->payment_gateway == 'torobpay') {
            $isTorobpay = true;
        }

        return Inertia::render('Admin/Orders/Show', [
            'order' => $order,
            'paymentMeta' => $paymentMeta,
            'payment_transaction' => $paymentTransaction,
            'card_receipt_file' => $orderGroup->type == 'card_to_card' ? route('private_media', $orderGroup->receipt_file_id) : null,
            'is_pay_with_wallet' => $paymentTransaction ? false : true,
            'is_order_accepted' => $orderGroup->payment_status == 'awaiting' ? false : true,
            'is_snapppay' => $isSnapppay,
            'is_digipay_upg' => $isDigipayUpg,
            'is_azki' => $isAzki,
            'is_torobpay' => $isTorobpay,
        ]);
    }

    /**
     * processing orders
     */
    public function processing(Request $request, OrdersService $ordersService)
    {
        return Inertia::render('Admin/Orders/Processing', [
            'orderGroups' => $ordersService->getProcessingOrders($request),
        ]);
    }

    /**
     * completed orders
     */
    public function completed(Request $request, OrdersService $ordersService)
    {
        return Inertia::render('Admin/Orders/Completed', [
            'orderGroups' => $ordersService->getCompletedOrders($request),
        ]);
    }

    /**
     * awaiting orders
     */
    public function awaiting(Request $request, OrdersService $ordersService)
    {
        return Inertia::render('Admin/Orders/Awaiting', [
            'orderGroups' => $ordersService->getAwaitingOrders($request),
        ]);
    }

    /**
     * send sticker
     */
    public function send_sticker(Order $order)
    {
        $address = unserialize($order->address);

        if ($address['type'] != 'user') {
            return redirect()->route('admin.dashboard');
        }

        return Inertia::render('Admin/Orders/SendSticker', [
            'order_group_id' => $order->orderGroup->uuid,
            'order_id' => $order->uuid,
            'order_user_name' => $order->user->name,
            'address' => $address['address'],
        ]);
    }

    /**
     * manage awaiting order status
     */
    public function manage_status(Request $request, OrderGroup $order_group)
    {
        $request->validate([
            'status' => 'required'
        ]);

        try {
            $status = DB::transaction(function () use ($request, $order_group) {
                if ($request->status == 'accept') {
                    // update consignment item storage inventory
                    foreach ($order_group->orders as $order) {
                        // get consignment and items
                        $consignments = $order->consignments()->with('consignmentItems')->get();
                        $consignmentItems = $consignments->flatMap(fn($c) => $c->consignmentItems);

                        foreach ($consignmentItems as $consignmentItem) {
                            $inventory = Inventory::where('id', $consignmentItem->inventory_id)->lockForUpdate()->first();
                            if ($inventory) {
                                $finalCount = max(0, $inventory->count - $consignmentItem->count);
                                $inventory->update(['count' => $finalCount]);
                            }
                        }
                    }

                    // change payment status of order group
                    $order_group->update([
                        'payment_status' => 'accepted'
                    ]);

                    // send notification to seller
                    foreach ($order_group->orders as $childOrder) {
                        if ($childOrder->consignments()->where('store_id', '!=', null)->count() > 0 && $childOrder->consignments()->where('send_type', 'direct')->count() > 0) {
                            $firstConsignment = $childOrder->consignments()->first();
                            $firstConsignment->store->user->notify(new RequestConsignment($childOrder->uuid));
                        }
                    }

                    // return result
                    return 'accepted';
                } else if ($request->status == 'reject') {
                    // delete payment transaction (charge wallet)
                    Transaction::where('transaction_id', $order_group->payment_transaction_uuid)->delete();
                    // delete order decrease transaction
                    $order_group->transaction()->delete();

                    // delete receipt file
                    if ($order_group->receipt_file_id) {
                        $receiptFile = File::find($order_group->receipt_file_id);
                        if ($receiptFile && $receiptFile->url) {
                            $relativePath = ltrim(str_replace('/private_media/', '', $receiptFile->url), '/');
                            Storage::disk('private_media')->delete($relativePath);
                            $receiptFile->delete();
                        }
                    }

                    // delete order group
                    $order_group->delete();

                    // return result
                    return 'rejected';
                }
            });
        } catch (\Exception $e) {
            return redirect()->back()->withErrors([$e->getMessage()]);
        }

        if ($status == 'accepted') {
            return redirect()->back()->with('message', [__('messages.order_accepted')]);
        } else if ($status == 'rejected') {
            // send reject notification to cistomer
            $order_group->user->notify(new OrderRejected($order_group->uuid));

            return redirect()->back()->withErrors([__('messages.order_rejected')]);
        } else {
            return redirect()->back()->withErrors([__('messages.unauthorized')]);
        }
    }

    /**
     * request consignment from seller
     */
    public function request_from_seller(Request $request, Consignment $consignment)
    {
        $request->validate([
            'address' => 'required',
        ]);

        // check order group status
        if ($consignment->order->orderGroup->payment_status == 'awaiting') {
            return redirect()->back()->withErrors([__('messages.unauthorized')]);
        }

        // seller
        $user = User::find($consignment->store->user_id);
        if ($user == null) {
            return redirect()->back()->withErrors([__('messages.unknown_error')]);
        }

        $consignment->update([
            'address' => serialize($request->address),
            'status' => 'awaiting_seller',
        ]);

        foreach ($consignment->consignmentItems()->where('status', 'awaiting_request_from_seller')->get() as $item) {
            $item->update([
                'status' => 'awaiting_seller',
            ]);
        }

        /** Report Action */
        $this->report(__("messages.report_request_consignment", ['consignment_uuid' => $consignment->uuid, 'order_uuid' => $consignment->order->uuid]), 'user', $user);

        // notification
        $user->notify(new RequestConsignment($consignment->uuid));

        return redirect()->back()->with('message', [__('messages.consignment_requested_form_seller')]);
    }

    /**
     *  cancel request consignment from seller
     */
    public function cancel_request_from_seller(Request $request, Consignment $consignment)
    {
        // check order group status
        if ($consignment->order->orderGroup->payment_status == 'awaiting') {
            return redirect()->back()->withErrors([__('messages.unauthorized')]);
        }

        // seller
        $user = User::find($consignment->store->user_id);
        if ($user == null) {
            return redirect()->back()->withErrors([__('messages.unknown_error')]);
        }

        if ($consignment->status != 'awaiting_seller') {
            return redirect()->back()->withErrors([__('messages.unknown_error')]);
        }

        $consignment->update([
            'address' => null,
            'status' => 'awaiting_request_from_seller',
        ]);

        foreach ($consignment->consignmentItems()->where('status', 'awaiting_seller')->get() as $item) {
            $item->update([
                'status' => 'awaiting_request_from_seller',
            ]);
        }

        /** Report Action */
        $this->report(__("messages.report_cancel_request_consignment", ['consignment_uuid' => $consignment->uuid, 'order_uuid' => $consignment->order->uuid]), 'user', $user);

        return redirect()->back()->with('message', [__('messages.consignment_cancelled_requested_form_seller')]);
    }

    /**
     * request consignment from seller
     */
    public function received_from_seller(Request $request, Consignment $consignment)
    {
        // check order group status
        if ($consignment->order->orderGroup->payment_status == 'awaiting') {
            return redirect()->back()->withErrors([__('messages.unauthorized')]);
        }

        // seller
        $user = User::find($consignment->store->user_id);
        if ($user == null) {
            return redirect()->back()->withErrors([__('messages.unknown_error')]);
        }

        if ($consignment->consignmentItems()->where('status', 'awaiting_request_from_seller')->count() > 0) {
            return redirect()->back()->withErrors([__('messages.unknown_error')]);
        }

        if ($consignment->consignmentItems()->where('status', 'awaiting_seller')->count() > 0) {
            return redirect()->back()->withErrors([__('messages.unknown_error')]);
        }

        foreach ($consignment->consignmentItems()->where('status', 'awaiting_receipt_from_seller')->get() as $item) {
            $item->update([
                'status' => 'ready_to_send',
            ]);
        }

        $consignment->update([
            'status' => 'delivered_to_main_storage',
        ]);

        /** Report Action */
        $this->report(__("messages.report_received_consignment", ['consignment_uuid' => $consignment->uuid, 'order_uuid' => $consignment->order->uuid]), 'user', $user);

        return redirect()->back()->with('message', [__('messages.consignment_received_form_seller')]);
    }

    /**
     * cancel consignment item
     */
    public function cancel_item(Request $request, ConsignmentItem $consignmentItem, CartService $cartService)
    {
        if (!$request->has('count')) {
            $request->validate([
                'reason' => 'required',
            ]);
        }

        /** @var App\Models\User $user */
        $user = auth()->user();

        // check order group status
        if ($consignmentItem->consignment->order->orderGroup->payment_status == 'awaiting') {
            return redirect()->back()->withErrors([__('messages.unauthorized')]);
        }

        // check consignment item status
        if (in_array($consignmentItem->status, ['delivered', 'sent', 'cancelled', 'returned'])) {
            return redirect()->back()->withErrors([__('messages.unauthorized')]);
        }

        // order payment transaction
        $transactionId = $consignmentItem->consignment?->order?->orderGroup?->payment_transaction_uuid;
        $paymentTransaction = $transactionId ? Transaction::where('transaction_id', $transactionId)->first() : null;

        // payment gateway return response
        $returnResponse = [];
        if ($paymentTransaction) {
            $returnResponse = json_decode($paymentTransaction->return_response, true);
            $returnResponse = is_array($returnResponse) ? $returnResponse : [];
        }

        // check snapppay
        $isSnapppay = false;
        if ($paymentTransaction && $paymentTransaction->payment_gateway == 'snapppay') {
            $isSnapppay = true;
        }

        // check digipay upg
        $isDigipayUpg = false;
        if ($paymentTransaction && $paymentTransaction->payment_gateway == 'digipay' && array_key_exists('type', $returnResponse) && in_array((int)$returnResponse['type'], [5, 11, 13, 24])) {
            $isDigipayUpg = true;
        }

        // check azki
        $isAzki = false;
        if ($paymentTransaction && $paymentTransaction->payment_gateway == 'azki') {
            $isAzki = true;
        }

        // check torobpay
        $isTorobpay = false;
        if ($paymentTransaction && $paymentTransaction->payment_gateway == 'torobpay') {
            $isTorobpay = true;
        }

        // check for UPG gateways
        if ($isDigipayUpg) {
            return redirect()->back()->withErrors([__('messages.unauthorized')]);
        }

        // prev status
        $prevStatus = $consignmentItem->status;

        // consignment
        $consignment = $consignmentItem->consignment;

        try {
            DB::transaction(function () use ($consignmentItem, $request, $user, $cartService, $paymentTransaction, $isSnapppay, $isTorobpay) {
                /** count or all cancel */
                if (($isSnapppay || $isTorobpay) && $request->has('count') && ctype_digit((string) $request->count)) {
                    if ((int)$request->count <= 0) {
                        throw new \Exception(__('messages.count_cant_zero'));
                    }

                    if ((int)$request->count < $consignmentItem->count) {
                        // lock inventory row
                        $inventory = Inventory::where('id', $consignmentItem->inventory_id)->lockForUpdate()->first();
                        if ($inventory != null) {
                            $inventory->update([
                                'count' => $inventory->count + (int)$request->count,
                            ]);
                        }

                        // cancelling item
                        $consignmentItem->update([
                            'count' => $consignmentItem->count - (int)$request->count,
                        ]);
                    } else {
                        throw new \Exception(__('messages.consignment_item_count_for_cancel_is_more_than_real_count'));
                    }
                } else {
                    // lock inventory row
                    $inventory = Inventory::where('id', $consignmentItem->inventory_id)->lockForUpdate()->first();
                    if ($inventory != null) {
                        $inventory->update([
                            'count' => $inventory->count + $consignmentItem->count,
                        ]);
                    }

                    // cancelling item
                    $consignmentItem->update([
                        'reason' => $request->reason,
                        'status' => 'cancelled'
                    ]);
                }
                /** end */

                /** check for all item cancelled or not */
                $consignment = $consignmentItem->consignment;
                $order = $consignment->order;
                $cancelledItemsCount = $consignment->consignmentItems()->where('status', 'cancelled')->count();
                $totalItemsCount = $consignment->consignmentItems()->count();
                if ($cancelledItemsCount === $totalItemsCount) {
                    $consignment->update(['status' => 'cancelled']);

                    /** Report Action */
                    $this->report(
                        __("messages.report_consignment_cancelled", [
                            'consignment_uuid' => $consignment->uuid,
                            'order_uuid' => $order->uuid
                        ]),
                        'user',
                        $user
                    );
                } else {
                    /** Report Action */
                    $this->report(
                        __("messages.report_consignment_item_cancelled", [
                            'consignment_uuid' => $consignment->uuid,
                            'order_uuid' => $order->uuid
                        ]),
                        'user',
                        $user
                    );
                }
                /** end */

                /** update discount coupon */
                if ($order->discount != null) {
                    // discount
                    $discount = $order->discount ? unserialize($order->discount) : null;

                    // delete old discount
                    $order->update([
                        'discount' => null
                    ]);

                    // refresh order model
                    $order->refresh();

                    // selected address
                    $selectedAddress = $order->address != null ? unserialize($order->address) : null;
                    // consignments information array
                    $consignmentsInformation = $cartService->sepratedConsignmentInformation($order, $selectedAddress, true);

                    // calculate discount amount
                    $amount = 0;
                    $discountPrice = ($consignmentsInformation['financial']['totalFinalPrice'] * $discount['information']['percent']) / 100;
                    if ($discountPrice <= $discount['information']['max_amount']) {
                        $amount = $discountPrice;
                    } else {
                        $amount = $discount['information']['max_amount'];
                    }

                    // add discount to order
                    $discount = [
                        'information' => [
                            'id' => $discount['information']['id'],
                            'title' => $discount['information']['title'],
                            'code' => $discount['information']['code'],
                            'percent' => $discount['information']['percent'],
                            'max_amount' => $discount['information']['max_amount'],
                        ],
                        'amount' => $amount,
                    ];

                    $order->update([
                        'discount' => serialize($discount)
                    ]);
                }
                /** end */

                /** snapppay update or cancell */
                $order->refresh();
                $this->snapppayService->snapppay($order->orderGroup);
                /** end */

                /** torobpay update or cancell */
                $order->refresh();
                $this->torobpayService->torobpay($order->orderGroup);
                /** end */
            });
        } catch (\Exception $e) {
            return redirect()->back()->withErrors([$e->getMessage()]);
        }

        // send notification to store seller
        if ($consignmentItem->store !== null && in_array($prevStatus, ['ready_to_send', 'awaiting_receipt_from_seller'])) {
            $consignmentItem->refresh();
            $consignmentItem->store->user->notify(new CancelRequestConsignment($consignment->uuid, 'single'));
        }

        return redirect()->back()->with('message', [__('messages.consignment_item_cancelled')]);
    }


    /**
     * return consignment item
     */
    public function return_item(Request $request, ConsignmentItem $consignmentItem)
    {
        /** @var App\Models\User $user */
        $user = auth()->user();

        // check order group status
        if ($consignmentItem->consignment->order->orderGroup->payment_status == 'awaiting') {
            return redirect()->back()->withErrors([__('messages.unauthorized')]);
        }

        // check consignment item status
        if ($consignmentItem->status != 'sent') {
            return redirect()->back()->withErrors([__('messages.unauthorized')]);
        }

        DB::transaction(function () use ($consignmentItem, $user) {
            // customer
            $customer = $consignmentItem->consignment->order->user;

            // seller and affiliate shares
            $sellerShare = $consignmentItem->get_shares['seller'];
            $affiliateShare = $consignmentItem->get_shares['affiliate'];

            // add inventory count with lock
            $inventory = Inventory::where('id', $consignmentItem->inventory_id)->lockForUpdate()->first();
            if ($inventory != null) {
                $inventory->update([
                    'count' => $inventory->count + $consignmentItem->count,
                ]);
            }

            // cancelling item
            $consignmentItem->update([
                'status' => 'returned'
            ]);

            // check for send and delivered count
            $sentCount = $consignmentItem->consignment->consignmentItems()->where('status', 'sent')->count();
            $deliveredCount = $consignmentItem->consignment->consignmentItems()->where('status', 'delivered')->count();
            if ($sentCount == 0 && $deliveredCount == 0) {
                // change consignment status to returned
                $consignmentItem->consignment->update([
                    'status' => 'returned'
                ]);

                // change order to returned for seller direct send
                if ($consignmentItem->consignment->send_type == 'direct') {
                    $consignmentItem->consignment->order->update([
                        'status' => 'returned'
                    ]);
                }
            }

            // change order status to returned
            $order = $consignmentItem->consignment->order;
            $hasActiveItems = $order->consignments()->whereHas('consignmentItems', function ($q) {
                $q->whereIn('status', ['sent', 'delivered']);
            })->exists();

            if (!$hasActiveItems) {
                $order->update([
                    'status' => 'returned'
                ]);
            }

            // Deduction for payment to affiliate
            if ($consignmentItem->affiliate !== null) {
                $affiliatePendingPayment = PendingPayment::where('user_id', $consignmentItem->affiliate)
                    ->where('order_id', $consignmentItem->consignment->order->id)
                    ->where('status', 'awaiting')
                    ->first();

                if ($affiliatePendingPayment) {
                    if ($affiliatePendingPayment->amount - $affiliateShare == 0) {
                        $affiliatePendingPayment->delete();
                    } else {
                        $affiliatePendingPayment->update([
                            'amount' => $affiliatePendingPayment->amount - $affiliateShare
                        ]);
                    }
                }
            }

            // Deduction for payment to seller
            if ($consignmentItem->store !== null) {
                $sellerPendingPayment = PendingPayment::where('user_id', $consignmentItem->store->user->id)
                    ->where('order_id', $consignmentItem->consignment->order->id)
                    ->where('status', 'awaiting')
                    ->first();

                if ($sellerPendingPayment) {
                    if ($consignmentItem->consignment->send_type == 'direct' && $consignmentItem->consignment->order->status == 'returned') {
                        $sellerPendingPayment->delete();
                    } else {
                        if ($sellerPendingPayment->amount - $sellerShare == 0) {
                            $sellerPendingPayment->delete();
                        } else {
                            $sellerPendingPayment->update([
                                'amount' => $sellerPendingPayment->amount - $sellerShare
                            ]);
                        }
                    }
                }

                // notification to seller
                $consignmentItem->store->user->notify(new SellerReturnConsignmentItem($consignmentItem->consignment->uuid));
            }

            // paid price
            $paidPrice = $consignmentItem->price * $consignmentItem->count;

            // calculate returned items tax amount
            $vaTaxPercent = $order->va_tax_percent;
            $taxAmount = $vaTaxPercent > 0 ? (($paidPrice * $vaTaxPercent) / 100) : 0;

            // return returned amount to customer wallet
            $wallet = $customer->wallet()->lockForUpdate()->first();
            $wallet->update([
                'amount' => $wallet->amount + ($paidPrice + $taxAmount),
            ]);

            // add returned paid price to customer wallet transaction
            $customer->transactions()->create([
                'amount' => ($paidPrice + $taxAmount),
                'transaction_id' => $this->generateUniqueRandomNumber(9, \App\Models\Transaction::class, 'transaction_id'),
                'description' => __('messages.transaction_user_order_returned_for_item_return', [
                    'order' => $consignmentItem->consignment->order->uuid
                ]),
                'type' => 'user_order_returned',
                'status' => 'accepted'
            ]);

            $customer->notify(new UserReturnConsignmentItem($consignmentItem->consignment->order->uuid));

            /** Report Action */
            $this->report(
                __("messages.report_consignment_item_returned", [
                    'consignment_uuid' => $consignmentItem->consignment->uuid,
                    'order_uuid' => $consignmentItem->consignment->order->uuid
                ]),
                'user',
                $user
            );
        });

        return redirect()->back()->with('message', [__('messages.consignment_item_cancelled')]);
    }


    /**
     * change order status
     */
    public function change_status(Request $request, Order $order)
    {
        $request->validate([
            'status' => 'required',
        ]);

        /** @var App\Models\User $user */
        $user = auth()->user();

        // check order group status
        if ($order->orderGroup->payment_status == 'awaiting') {
            return redirect()->back()->withErrors([__('messages.unauthorized')]);
        }

        // check consignment item status
        if ($order->status != 'registered') {
            return redirect()->back()->withErrors([__('messages.unauthorized')]);
        }

        // check for UPG gateways
        $paymentTransaction = Transaction::where('transaction_id', $order->orderGroup->payment_transaction_uuid)->first();

        // customer
        $customer = $order->user;

        // start process
        if ($request->status == 'start_process') {
            try {
                // change in order model
                $order->update([
                    'start_process' => true,
                ]);

                // sent notification
                $customer->notify(new OrderStartProcess(
                    $order->orderGroup->uuid,
                    $order->uuid
                ));

                return redirect()->back()->with('message', [__('messages.order_start_process')]);
            } catch (\Exception $e) {
                return redirect()->back()->withErrors([$e->getMessage()]);
            }
        }

        try {
            DB::transaction(function () use ($request, $order, $user, $customer, $paymentTransaction) {
                if ($order->fresh()->status != 'registered') {
                    throw new \Exception(__('messages.unauthorized'));
                }

                // sent
                if ($request->status == 'sent' && !$order->is_all_item_cancelled && $order->send_by == null) {
                    if ($order->is_ready_to_send) {
                        if ($order->get_address['type'] != 'shop') {
                            $request->validate([
                                'tracking_code' => 'required',
                            ]);
                        }

                        /** update consignment and consignmentItems status and information */
                        $consignments = $order->consignments()->where('status', '!=', 'cancelled')->get();
                        foreach ($consignments as $consignment) {
                            $consignment->update([
                                'status' => $order->get_address['type'] != 'shop' ? 'sent_to_customer' : 'delivered',
                            ]);
                            foreach ($consignment->consignmentItems()->where('status', '!=', 'cancelled')->get() as $consignmentItem) {
                                $consignmentItem->update([
                                    'shop_share' => $consignmentItem->get_shares['shop'],
                                    'seller_share' => $consignmentItem->get_shares['seller'],
                                    'affiliate_share' => $consignmentItem->get_shares['affiliate'],
                                    'status' =>  $order->get_address['type'] != 'shop' ? 'sent' : 'delivered',
                                ]);
                            }
                        }
                        /** end */

                        /** update order */
                        $order->update([
                            'post_tracking_code' => $order->get_address['type'] != 'shop' ? $request->tracking_code : '0',
                            'status' => $order->get_address['type'] != 'shop' ? 'sent' : 'delivered',
                            'sent_at' => now()
                        ]);
                        /** end */

                        /** handle consolidated shares */
                        foreach ($order->get_consolidated_shares['seller'] as $share) {
                            $seller = Store::find($share['information']['id'])?->user;
                            if ($seller) {
                                $seller->pendingPayments()->create([
                                    'order_id' => $order->id,
                                    'amount' => $share['share'],
                                    'data' => serialize(['consignment_uuid' => $share['consignment']]),
                                    'type' => 'seller',
                                    'status' => 'awaiting',
                                ]);
                            }
                        }
                        foreach ($order->get_consolidated_shares['affiliate'] as $share) {
                            $affiliate = User::find($share['information']['id']);
                            if ($affiliate) {
                                $affiliate->pendingPayments()->create([
                                    'order_id' => $order->id,
                                    'amount' => $share['share'],
                                    'data' => serialize(['product' => $share['product']]),
                                    'type' => 'affiliate',
                                    'status' => 'awaiting',
                                ]);
                            }
                        }
                        /** end */

                        /** refund cancelled items to customer wallet */
                        if ($paymentTransaction && ($paymentTransaction->payment_gateway == "snapppay" || $paymentTransaction->payment_gateway == "torobpay")) {
                            // dont refund (UPG Direct cancellation)
                        } else {
                            if ($order->get_total_bill['cancel']['price'] > 0) {
                                // calculate cancelled items tax amount
                                $vaTaxPercent = $order->va_tax_percent;
                                $taxAmount = $vaTaxPercent > 0 ? (($order->get_total_bill['cancel']['price'] * $vaTaxPercent) / 100) : 0;

                                if ($customer->wallet) {
                                    $customer->wallet->update([
                                        'amount' => $customer->wallet->amount + ($order->get_total_bill['cancel']['price'] + $taxAmount),
                                    ]);
                                }

                                $customer->transactions()->create([
                                    'amount' => ($order->get_total_bill['cancel']['price'] + $taxAmount),
                                    'transaction_id' => $this->generateUniqueRandomNumber(9, \App\Models\Transaction::class, 'transaction_id'),
                                    'description' => __('messages.transaction_user_order_returned_some_item', ['order' => $order->uuid]),
                                    'type' => 'user_order_returned',
                                    'status' => 'accepted'
                                ]);
                            }
                        }
                        /** end */

                        /** delivery digipay upg */
                        $this->digipayService->digipayDelivery($order->orderGroup, $request->tracking_code);
                        /** end */

                        // register report
                        $this->report(__("messages.report_order_sent", ['uuid' => $order->uuid]), 'user', $user);
                    }
                }

                // cancelled
                if ($request->status == 'cancelled') {
                    $request->validate([
                        'reason' => 'required',
                    ]);

                    /** calculate paid price */
                    $getDiscountCodeAmount = $order->get_discount != null ? $order->get_discount['amount'] : 0;
                    $paidPrice = $order->get_total_bill['price'] + $order->get_total_bill['send_price'] - $getDiscountCodeAmount;
                    /** end */

                    /** update order and consignment and consignmentItems inventory count and status / add cancellation reason */
                    $consignments = $order->consignments;
                    foreach ($consignments as $consignment) {
                        $consignment->update(['status' => 'cancelled']);
                        foreach ($consignment->consignmentItems as $consignmentItem) {
                            // add inventory count
                            if ($consignmentItem->status != 'cancelled' && $consignmentItem->inventory != null) {
                                $consignmentItem->inventory->update([
                                    'count' => $consignmentItem->inventory->count + $consignmentItem->count,
                                ]);
                            }
                            $consignmentItem->update([
                                'reason' => $request->reason,
                                'status' => 'cancelled',
                            ]);
                        }
                    }
                    $order->update(['status' => 'cancelled']);
                    /** end */

                    /** Customer Club Points Deduction */
                    try {
                        $clubSetting = Setting::where('key', 'customer_club')->first();
                        $club = $clubSetting ? @unserialize($clubSetting->value) : ['price' => 0, 'score' => 0];
                        $score = ($club['price'] > 0 && $club['score'] > 0)
                            ? round(($paidPrice / str_replace(',', '', $club['price'])) * str_replace(',', '', $club['score']))
                            : 0;

                        $customer->scores()->create([
                            'score' => $score,
                            'description' => __('messages.sentence.decrease_points_for_orders') . ' ' . $order->uuid,
                            'type' => 'decrease',
                        ]);
                    } catch (\Exception $e) {
                    }
                    /** end */

                    /** handle UPG gateways */
                    if ($paymentTransaction) {
                        if (in_array($paymentTransaction->payment_gateway, ['snapppay', 'digipay', 'torobpay'])) {
                            /** snapppay update or cancel */
                            $order->refresh();
                            $this->snapppayService->snapppay($order->orderGroup);
                            /** end */

                            /** digipay refund */
                            $order->refresh();
                            $this->digipayService->digipayRefund($order->orderGroup, $paidPrice, $request->reason);
                            /** end */

                            /** torobpay update or cancel */
                            $order->refresh();
                            $this->torobpayService->torobpay($order->orderGroup);
                            /** end */
                        } else {
                            $this->refundToWallet($customer, $paidPrice, $order);
                        }
                    } else {
                        $this->refundToWallet($customer, $paidPrice, $order);
                    }
                    /** end */

                    // register report
                    $this->report(__("messages.report_order_cancelled", ['uuid' => $order->uuid]), 'user', $user);
                }
            });
        } catch (\Exception $e) {
            return redirect()->back()->withErrors([$e->getMessage()]);
        }

        /** send notifications */
        // sent notification
        if ($request->status == 'sent') {
            $customer->notify(new OrderSent(
                $order->orderGroup->uuid,
                $order->uuid,
                $request->tracking_code ?? null,
                $order->get_total_bill['cancel']['price'] > 0
            ));
            return redirect()->back()->with('message', [__('messages.order_sent')]);
        }
        // cancell notification
        if ($request->status == 'cancelled') {
            $customer->notify(new OrderCancellation($order->orderGroup->uuid, $order->uuid));
            return redirect()->back()->with('message', [__('messages.order_cancelled')]);
        }
        /** end */

        // return result
        return redirect()->back()->withErrors([__('messages.unknown_error')]);
    }

    /**
     * refund to wallet
     */
    protected function refundToWallet($customer, $paidPrice, $order)
    {
        // calculate cancelled items tax amount
        $vaTaxPercent = $order->va_tax_percent;
        $taxAmount = $vaTaxPercent > 0 ? (($paidPrice * $vaTaxPercent) / 100) : 0;

        if ($customer->wallet) {
            $customer->wallet->update([
                'amount' => $customer->wallet->amount + ($paidPrice + $taxAmount),
            ]);
        }
        $customer->transactions()->create([
            'amount' => ($paidPrice + $taxAmount),
            'transaction_id' => $this->generateUniqueRandomNumber(9, \App\Models\Transaction::class, 'transaction_id'),
            'description' => __('messages.transaction_user_order_returned', ['order' => $order->uuid]),
            'type' => 'user_order_returned',
            'status' => 'accepted'
        ]);
    }

    /**
     * order sales factor
     */
    public function sales_factor(Order $order, CartService $cartService)
    {
        /** get dynamic tax amount form va_tax_percent in order model */
        // selected address
        $selectedAddress = $order->address != null ? unserialize($order->address) : null;
        // consignments information array
        $consignmentsInformation = $cartService->sepratedConsignmentInformation($order, $selectedAddress, true);
        // tax amount
        $taxAmount = $consignmentsInformation['financial']['taxAmount'];
        /**** end ****/

        $orderConsignmentItems = [];

        $consignments = $order->consignments()->where(function ($query) {
            $query->where('status', '!=', 'cancelled')->where('status', '!=', 'returned');
        })->get();

        foreach ($consignments as $consignment) {
            $orderConsignmentItems = array_merge($orderConsignmentItems, $consignment->consignmentItems()->where(function ($query) {
                $query->where('status', '!=', 'cancelled')->where('status', '!=', 'returned');
            })->get()->map(fn($item) => [
                'id' => $item->id,
                'title' => $item->title,
                'get_props' => $item->get_props,
                'get_options' => $item->get_options,
                'price' => $item->price,
                'discount' => $item->discount,
                'count' => $item->count,
                'product' => $item->product != null ? [
                    'id' => $item->product->id,
                    'uuid' => $item->product->uuid,
                    'title' => $item->product->title,
                ] : null,
            ])->toArray());
        }

        return Inertia::render('Admin/Orders/SalesFactor', [
            'order' => array_merge($order->safe, ['tax_amount' => $taxAmount]),
            'consignmentItems' => $orderConsignmentItems,
            'user_national_number' => $order->user->national_number
        ]);
    }

    /**
     * order thermal sales factor
     */
    public function thermal_sales_factor(Order $order, CartService $cartService)
    {
        /** get dynamic tax amount form va_tax_percent in order model */
        // selected address
        $selectedAddress = $order->address != null ? unserialize($order->address) : null;
        // consignments information array
        $consignmentsInformation = $cartService->sepratedConsignmentInformation($order, $selectedAddress, true);
        // tax amount
        $taxAmount = $consignmentsInformation['financial']['taxAmount'];
        /**** end ****/

        $orderConsignmentItems = [];

        $consignments = $order->consignments()
            ->whereNotIn('status', ['cancelled', 'returned'])
            ->get();

        foreach ($consignments as $consignment) {
            $items = $consignment->consignmentItems()
                ->whereNotIn('status', ['cancelled', 'returned'])
                ->get()
                ->map(fn($item) => [
                    'id' => $item->id,
                    'title' => $item->title,
                    'get_props' => $item->get_props,
                    'get_options' => $item->get_options,
                    'price' => $item->price,
                    'discount' => $item->discount,
                    'count' => $item->count,
                    'product' => $item->product ? [
                        'id' => $item->product->id,
                        'uuid' => $item->product->uuid,
                        'title' => $item->product->title
                    ] : null
                ])
                ->toArray();

            $orderConsignmentItems = array_merge($orderConsignmentItems, $items);
        }

        return Inertia::render('Admin/Orders/ThermalSalesFactor', [
            'order' => array_merge($order->safe, ['tax_amount' => $taxAmount]),
            'consignmentItems' => $orderConsignmentItems,
            'user_national_number' => $order->user->national_number,
        ]);
    }
}