<?php

namespace App\Libs\Services;


use App\Exceptions\ServiceException;
use App\Models\GenericBackoffice\Meal;
use App\Models\GenericBackoffice\MealFood;
use App\Models\User;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\DB;
use Throwable;


class FoodService
{

    /**
     * @return Collection
     */
    public function listBackendMeals(): Collection
    {
        $today = today();
        return Meal::full()->select('*')
            ->where('title', '>=', $today)
            ->where('website_objects.status', 'published')
            ->orderBy('title', 'asc')
            ->with([
                'mealFood' => function ($query) {
                    $query->orderBy('position', 'asc')->with([
                        'food'  => function ($query) {
                            $query->full()->select('*')->where('website_objects.status', 'published');
                        }
                    ])->whereHas('food', function ($query) {
                        $query->full()->where('website_objects.status', 'published');
                    })->leftJoin('user_picked_meal_food', 'meal_food.meal_food_id', '=', 'user_picked_meal_food.meal_food_id')
                        ->selectRaw('meal_food.*, SUM(user_picked_meal_food.quantity) as food_quantity')
                        ->groupBy('meal_food.meal_food_id');
                },
            ])
            ->get();
    }

    /**
     * Get meals list for frontend
     *
     * @param  string  $name
     * @param  string  $email
     * @param  string  $password
     * @return User
     */
    public function listFutureMeals(): Collection
    {
        $today = today();
        return Meal::full()->select('*')
            ->where('title', '>=', $today)
            ->where('website_objects.status', 'published')
            ->orderBy('title', 'asc')
            ->with($this->loadMealsFrontendRelations())
            ->get();
    }

    /**
     * Get frontend required load for frontend api
     *
     * @return \Closure[]
     */
    public function loadMealsFrontendRelations(): array
    {
        return [
            'mealFood' => function ($query) {
                $query->orderBy('position', 'asc')->with([
                    'food'  => function ($query) {
                        $query->full()->select('*')->with([
                            'allergens' => function ($query) {
                                $query->full()
                                    ->select('*')
                                    ->where('website_objects.status', 'published')
                                    ->orderBy('food_allergen.position', 'asc');
                            }
                        ])->where('website_objects.status', 'published');
                    },
                    'users' => function ($query) {
                        $query->loggedUser();
                    }
                ])->whereHas('food', function ($query) {
                    $query->full()->where('website_objects.status', 'published');
                });
            },
        ];
    }

    /**
     * User picks the food for a specific meal
     *
     * @param  User  $user
     * @param  int  $mealId
     * @param  array  $foods
     * @return Meal
     * @throws ServiceException
     * @throws Throwable
     */
    public function pickMeal(User $user, int $mealId, array $foods): Meal
    {
        $meal = Meal::full()->where('website_objects.status', 'published')->where('meals.id', $mealId)->first();
        if (!$meal->can_be_picked) {
            throw new ServiceException(trans('response.api.pick.past_meal'));
        }

        DB::beginTransaction();
        try {
            DB::table('user_picked_meal_food')
                ->where('user_id', $user->id)
                ->whereIn('meal_food_id', $meal->mealFood->modelKeys())->delete();

            foreach ($foods as $food) {
                $mealFood = $meal->mealFood()
                    ->whereHas('food', function ($query) {
                        $query->full()->where('website_objects.status', 'published');
                    })->where('food_id', $food['food_id'])
                    ->first();
                if (is_null($mealFood)) {
                    throw new ServiceException(
                        trans('response.api.pick.selected_food_not_in_meal', ['foodId' => $food['food_id']])
                    );
                }

                DB::table('user_picked_meal_food')->insert([
                    [
                        'meal_food_id' => $mealFood->meal_food_id,
                        'user_id'      => $user->id,
                        'quantity'     => $food['quantity'],
                        'created_at'   => now(),
                        'updated_at'   => now()
                    ]
                ]);
            }

            DB::commit();
        } catch (Throwable $e) {
            DB::rollBack();
            throw $e;
        }

        return $meal;
    }

    public function getMealFoodUsersDetail(int $mealFoodId): MealFood
    {
        $mealFood = MealFood::findOrFail($mealFoodId);

        $mealFood->load([
            'food'  => function ($query) {
                $query->full()->select('*');
            },
            'meal' => function ($query) {
                $query->full()->select('*');
            },
            'users' => function ($query) {
                $query->withTrashed()->orderBy('pivot_created_at', 'asc');
            }
        ]);

        return $mealFood;
    }
}
