<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\ApiController;
use App\Http\Requests\OrderProgressUpdateRequest;
use App\Http\Requests\PosCancelRequest;
use App\Http\Requests\PosCheckoutRequest;
use App\Http\Requests\ReservationCheckoutRequest;
use App\Http\Resources\PosBillingSaleOrderResource;
use App\Http\Resources\PosCustomerResource;
use App\Http\Resources\PosFoodCategoryResource;
use App\Http\Resources\PosFoodItemResource;
use App\Http\Resources\PosGuestRoomReservationResource;
use App\Http\Resources\PosKitchenOrderResource;
use App\Http\Resources\PosModifierResource;
use App\Http\Resources\PosPaymentMethodResource;
use App\Http\Resources\PosPickupPointResource;
use App\Http\Resources\PosServiceTableResource;
use App\Http\Resources\PosSubmittedSaleOrderResource;
use App\Http\Resources\PosTaxResource;
use App\Models\Customer;
use App\Models\FoodCategory;
use App\Models\FoodItem;
use App\Models\FoodItemAttribute;
use App\Models\GuestRoomReservation;
use App\Models\Modifier;
use App\Models\PaymentMethod;
use App\Models\PickupPoint;
use App\Models\Sale;
use App\Models\ServiceTable;
use App\Models\Tax;
use App\Notifications\App\OnCancellationNotification;
use App\Notifications\App\OnCollectionNotification;
use Exception;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;

class PosController extends ApiController
{

    /**
     * Construct middleware
     */
    public function __construct()
    {
        $this->middleware('auth:sanctum');
    }

    public function products(Request $request): JsonResponse
    {
        $sort = $this->sort($request);
        $items = FoodItem::filter($request->all())
            ->orderBy($sort['column'], $sort['order'])
            ->paginate((int) $request->get('perPage', 18));
        Artisan::call('optimize:clear');
        return response()->json(
            [
                'items' => PosFoodItemResource::collection($items->items()),
                'pagination' => $this->pagination($items),
            ]
        );
    }

    public function pickupPoints(): JsonResponse
    {
        $points = PickupPoint::latest()->get();
        return response()->json(PosPickupPointResource::collection($points));
    }

    public function paymentMethods(): JsonResponse
    {
        $methods = PaymentMethod::get();
        return response()->json(PosPaymentMethodResource::collection($methods));
    }
    public function taxes(): JsonResponse
    {
        $taxes = Tax::get();
        return response()->json(PosTaxResource::collection($taxes));
    }

    public function serviceTables(): JsonResponse
    {
        $tables = ServiceTable::get();
        return response()->json(PosServiceTableResource::collection($tables));
    }

    public function reservations(): JsonResponse
    {
        $reservations = GuestRoomReservation::checkedInReservations()->get();
        return response()->json(PosGuestRoomReservationResource::collection($reservations));
    }

    public function checkIn(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'tracking' => 'required'
        ]);

        $guestRoomReservation = GuestRoomReservation::whereNull('checkin_at')->whereNull('checkout_at')->where('tracking', $validated['tracking'])->first();

        if ($guestRoomReservation) {
            $guestRoomReservation->update([
                'checkin_at' =>  $this->getCurrentTimpstamp()
            ]);
            $reservations = GuestRoomReservation::checkedInReservations()->get();
            \App\Helpers\ActivityLogger::log(__('Guest room reservation checked in successfully'), $guestRoomReservation->tracking);
            return response()->json([
                'message' => __('Checked in successfully'),
                'reservations' => PosGuestRoomReservationResource::collection($reservations)
            ]);
        }
        return response()->json([
            'message' => __('No record found! It might have already been checked in')
        ], 422);
    }

    public function modifiers(): JsonResponse
    {
        $modifiers = Modifier::get();
        return response()->json(PosModifierResource::collection($modifiers));
    }

    public function categories(Request $request): JsonResponse
    {
        $categories = FoodCategory::get();
        return response()->json(PosFoodCategoryResource::collection($categories));
    }

    public function kitchenOrders(Request $request): JsonResponse
    {
        $orders = Sale::filter($request->all())->orderForKitchen()->get();
        return response()->json([
            'orders' => PosKitchenOrderResource::collection($orders),
            'chefs' => $this->getChefs(),
        ]);
    }

    public function customers(Request $request): JsonResponse
    {
        $customers = Customer::where('id', 1)->get();
        if ($request->search) {
            $customers = Customer::filter($request->all())->limit(100)->get();
        }
        return response()->json(PosCustomerResource::collection($customers));
    }

    public function submitedOrder(Request $request): JsonResponse
    {
        $order = Sale::where('uuid', $request->uuid)->submittedOrder(config('app.modes.allow_to_edit_checked_orders'))->first();
        if ($order) {
            return response()->json(new PosBillingSaleOrderResource($order));
        }
        return response()->json([
            'message' => __('Unable to process the request, order is completed'),
        ]);
    }

    public function submiitedOrders(): JsonResponse
    {
        $orders = Sale::latest()->submittedOrder()->get();
        return response()->json(PosSubmittedSaleOrderResource::collection($orders));
    }

    public function orderProgressUpdate(OrderProgressUpdateRequest $request, Sale $sale): JsonResponse
    {
        $validated = $request->validated();
        $sale->update([
            'progress' => $request->progress,
            'items' => $request->items,
            'chef_id' => $request->chef_id,
            'is_preparing' => $request->progress > 0 ? true : false,
            'prepared_at' => $request->progress > 99 ? $this->getCurrentTimpstamp() : null,
        ]);
        \App\Helpers\ActivityLogger::log(__('Order information updated successfully'), $sale->tracking);

        return response()->json([
            'message' => __('Order information updated successfully'),
        ]);
    }
    public function reservationCheckout(ReservationCheckoutRequest $request, GuestRoomReservation $guestRoomReservation): JsonResponse
    {
        if ($guestRoomReservation->checkout_at) {
            return response()->json([
                'message' => __('Customer has already checkedout successfully'),
            ], 422);
        }
        $validated = $request->validated();
        if ($request->checkout_process) {
            \App\Helpers\ActivityLogger::log(__('Guest room reservation checked out successfully'), $guestRoomReservation->tracking);
            $validated['checkout_at'] = $this->getCurrentTimpstamp();
        }
        $guestRoomReservation->update($validated);
        \App\Helpers\ActivityLogger::log(__('Guest room reservation updated successfully'), $guestRoomReservation->tracking);
        return response()->json([
            'message' => __('Order information updated successfully'),
        ]);
    }

    public function checkout(PosCheckoutRequest $request, Sale $sale): JsonResponse
    {
        try {
            $validated = $request->validated();
            $validated['completed_at'] = $this->getCurrentTimpstamp();
            $validated['biller_id'] = auth()->user()->id;
            if (!Auth::user()->userRole->checkPermission('order_checkout')) {
                return response()->json([
                    'message' => __('You have not permit to perform this request'),
                ], 403);
            }
            foreach ($sale->items as $item) {
                $this->proccessFoodModifierStock($item);
                $this->proccessFoodItemStock($item);
            }
            if ('dining' === $sale->order_type) {
                $sale->serviceTable()->update(['is_booked' => false]);
            }
            $sale->update($validated);
            Artisan::call('optimize:clear');

            $sale->customer->notify((new OnCollectionNotification($this->channelConfigs($sale->customer), $sale))
                ->locale(config('app.locale')));
            \App\Helpers\ActivityLogger::log(__('Order checkout successfully'), $sale->tracking);
            DB::commit();
            return response()->json([
                'message' => __('Processed successfully'),
            ]);
        } catch (Exception $e) {
            DB::rollback();
            return response()->json(
                [
                    'error' => __('Something went wrong try again !'),
                    'message' => $e->getMessage(),
                ],
                500
            );
        }
    }

    public function cancelOrder(PosCancelRequest $request, Sale $sale): JsonResponse
    {
        DB::beginTransaction();
        try {
            $validated = $request->validated();
            if ('dining' === $sale->order_type) {
                $sale->serviceTable()->update(['is_booked' => false]);
            }
            $sale->update($validated);
            Artisan::call('optimize:clear');
            $sale->customer->notify((new OnCancellationNotification($this->channelConfigs($sale->customer), $sale))
                ->locale(config('app.locale')));
            \App\Helpers\ActivityLogger::log(__('Order information cancelled successfully'), $sale->tracking);
            DB::commit();
            return response()->json([
                'message' => __('Cancelled successfully'),
            ]);
        } catch (Exception $e) {
            DB::rollback();
            return response()->json(
                [
                    'error' => __('Something went wrong try again !'),
                    'message' => $e->getMessage(),
                ],
                500
            );
        }
    }

    protected function proccessFoodItemStock($item)
    {
        if ($item['food_item_id']) {
            $attribute = FoodItemAttribute::where('uuid', $item['uuid'])->first();
            if ($attribute) {
                $this->adjustIngredientStock($attribute->ingredients, $item['qty']);
            }
        } else {
            $foodItem = FoodItem::where('uuid', $item['uuid'])->first();
            if ($foodItem) {
                $this->adjustIngredientStock($foodItem->ingredients, $item['qty']);
            }
        }
    }

    protected function proccessFoodModifierStock($item)
    {
        foreach ($item['modifiers'] as $modifier) {
            $modifierObject = Modifier::where('id', $modifier['id'])->first();
            if ($modifierObject) {
                $this->adjustIngredientStock($modifierObject->ingredients, $modifier['qty']);
            }
        }
    }

    protected function adjustIngredientStock($ingredients, $qty)
    {
        foreach ($ingredients as $ingredient) {
            $usingQty = $ingredient->pivot->quantity;
            $ingredient->quantity -= $usingQty * $qty;
            $ingredient->save();
        }
    }
}
