<?php

namespace Modules\Pos\Services\Pos;

use Darryldecode\Cart\Exceptions\InvalidConditionException;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
use Illuminate\Support\Facades\Cache;
use Modules\Cart\Facades\PosCart;
use Modules\Category\Models\Category;
use Modules\Discount\Models\Discount;
use Modules\Menu\Models\Menu;
use Modules\Order\Enums\OrderType;
use Modules\Order\Services\Order\OrderServiceInterface;
use Modules\Order\Transformers\Api\V1\Kitchen\KitchenOrderResource;
use Modules\Payment\Enums\PaymentMethod;
use Modules\Payment\Enums\PaymentType;
use Modules\Pos\Enums\PosCashDirection;
use Modules\Pos\Enums\PosCashReason;
use Modules\Pos\Models\PosRegister;
use Modules\Pos\Transformers\Api\V1\Pos\PosCategoryResource;
use Modules\Pos\Transformers\Api\V1\Pos\PosProductResource;
use Modules\Product\Models\Product;
use Modules\User\Enums\DefaultRole;

class PosService implements PosServiceInterface
{
    /** @inheritDoc
     * @throws InvalidConditionException
     */
    public function get(): array
    {
        PosCart::clear();

        $user = auth()->user();

        $branchId = $user->effective_branch->id;
        $menu = Menu::getActiveMenu($branchId, true);

        abort_if(is_null($menu), 400, __("pos::messages.menu_is_not_active"));

        $orderTypes = $menu->branch->order_types ?: [];

        if ($user->hasRole(DefaultRole::Waiter->value) && in_array(OrderType::DineIn->value, $orderTypes)) {
            $orderTypes = [OrderType::DineIn->value];
        }

        $directions = PosCashDirection::toArrayTrans([PosCashDirection::Adjust->value]);
        $reasons = [];

        foreach ($directions as $direction) {
            $reasons[$direction['id']] = array_map(
                fn(PosCashReason $reason) => $reason->toTrans(),
                PosCashReason::getForManageCashMovement(PosCashDirection::from($direction['id']))
            );
        }

        if (count($orderTypes) > 0) {
            PosCart::addOrderType(OrdeRType::from($orderTypes[0]));
        }

        return [
            "menu" => [
                "id" => $menu->id,
                "name" => $menu->name,
            ],
            "branch" => [
                "id" => $menu->branch_id,
                "name" => $menu->branch->name,
                "currency" => $menu->branch->currency,
            ],
            "discounts" => Discount::list($menu->branch_id)->values(),
            "categories" => $this->getCategories($menu),
            "products" => $this->getProducts($menu),
            "order_types" => array_filter(
                OrderType::toArrayTrans(),
                fn($orderType) => in_array($orderType['id'], $orderTypes)
            ),
            "payment_methods" => array_filter(
                PaymentMethod::toArrayTrans(),
                fn($orderType) => in_array(
                    $orderType['id'],
                    $menu->branch->payment_methods ?: []
                )
            ),
            "payment_types" => PaymentType::toArrayTrans(),
            "pos_registers" => PosRegister::list($menu->branch_id),
            "pos_cash_movements_meta" => ["directions" => $directions, "reasons" => $reasons],
            "cart" => PosCart::instance()
        ];
    }

    /** @inheritDoc */
    public function getCategories(Menu $menu): AnonymousResourceCollection
    {
        return Cache::tags("categories")
            ->rememberForever(
                makeCacheKey([
                    'categories',
                    "menu-$menu->id",
                    'pos_tree'
                ]),
                fn() => PosCategoryResource::collection(
                    Category::query()
                        ->with(["childrenRecursive", "files"])
                        ->whereNull("parent_id")
                        ->whereMenu($menu->id)
                        ->withOutGlobalBranchPermission()
                        ->orderBy("order")
                        ->get()
                )
            );
    }

    /** @inheritDoc */
    public function getProducts(Menu $menu): AnonymousResourceCollection
    {
        return Cache::tags(["products", "categories"])
            ->rememberForever(
                makeCacheKey([
                    'products',
                    "menu-$menu->id",
                    'pos'
                ]),
                fn() => PosProductResource::collection(
                    Product::query()
                        ->with([
                            "files",
                            "categories:id,menu_id",
                            "taxes",
                            "options" => fn($query) => $query->with("values")
                        ])
                        ->whereHas(
                            'categories',
                            fn($query) => $query->whereIn('id', Category::getFullyActiveCategoryIds($menu->id))
                        )
                        ->WithOutGlobalBranchPermission()
                        ->whereMenu($menu->id)
                        ->latest()
                        ->get()
                )
            );
    }

    /** @inheritDoc */
    public function kitchenViewer(): array
    {
        $orderService = app(OrderServiceInterface::class);
        $branch = auth()->user()->effective_branch;

        return [
            "orders" => KitchenOrderResource::collection($orderService->getOrdersForKitchen()),
            "order_types" => array_filter(
                OrderType::toArrayTrans(),
                fn($orderType) => in_array($orderType['id'], $branch->order_types ?: [])
            ),
        ];
    }
}
