<?php

namespace App\Domains\Catalog\Controllers;

use App\Domains\Cart\Services\CartService;
use App\Domains\Catalog\Models\CatalogItem;
use App\Domains\Catalog\Models\Category;
use App\Domains\Catalog\Models\FeaturedGroup;
use App\Domains\Catalog\Requests\CatalogItemDetailRequest;
use App\Domains\Catalog\Requests\CatalogVariantOptionsRequest;
use App\Domains\Catalog\Requests\CategoryPageRequest;
use App\Domains\Catalog\Requests\FeaturedGroupPageRequest;
use App\Domains\Catalog\Requests\SearchCatalogItemsRequest;
use App\Domains\Catalog\Requests\StoreCatalogItemRequest;
use App\Domains\Catalog\Resources\CatalogFeaturedGroupResource;
use App\Domains\Catalog\Resources\CatalogItemDetailResource;
use App\Domains\Catalog\Resources\CatalogItemResource;
use App\Domains\Catalog\Resources\CatalogSearchItemResource;
use App\Domains\Catalog\Resources\CatalogVariantOptionsResource;
use App\Domains\Catalog\Services\CatalogItemAllowanceService;
use App\Domains\Catalog\Services\CatalogService;
use App\Domains\Catalog\Services\FeaturedGroupService;
use App\Domains\Catalog\Services\VariantSelectionService;
use App\Domains\Tenant\Models\Tenant;
use App\Http\Controllers\Controller;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
use Illuminate\Support\Facades\Auth;

class CatalogController extends Controller
{
    public function index(Request $request, Tenant $tenant, FeaturedGroupService $featuredGroupService): JsonResponse
    {
        $featuredGroups = FeaturedGroup::query()
            ->where('tenant_code', $tenant->codigo)
            ->orderBy('group_order')
            ->get();

        return response()->json($featuredGroups->map(
            fn (FeaturedGroup $featuredGroup): array => (new CatalogFeaturedGroupResource(
                $featuredGroup,
                $featuredGroupService->itemsResponse($featuredGroup, 1, $this->userId($request)),
            ))->resolve()
        ));
    }

    public function search(
        SearchCatalogItemsRequest $request,
        Tenant $tenant,
        CatalogService $catalogService,
        CatalogItemAllowanceService $allowances,
    ): AnonymousResourceCollection {
        $items = $catalogService->search(
            $tenant,
            $request->validated('q'),
            $tenant->search_items_per_page,
            (int) $request->validated('page', 1),
        );
        $allowances->attach($items->getCollection(), $this->userId($request));

        return CatalogSearchItemResource::collection($items);
    }

    public function category(
        CategoryPageRequest $request,
        Tenant $tenant,
        Category $category,
        CatalogService $catalogService,
        CatalogItemAllowanceService $allowances,
    ): AnonymousResourceCollection {
        abort_unless($category->tenant_code === $tenant->codigo, 404);

        $items = $catalogService->categoryItems(
            $tenant,
            $category,
            $tenant->search_items_per_page,
            (int) $request->validated('page', 1),
        );
        $allowances->attach($items->getCollection(), $this->userId($request));

        return CatalogSearchItemResource::collection($items)->additional([
            'category' => [
                'id' => $category->id,
                'nombre' => $category->nombre,
                'categoria_id' => $category->categoria_id,
            ],
            'layout' => $tenant->search_product_layout->value,
            'group_layout' => $tenant->search_group_layout->value,
        ]);
    }

    public function featuredGroupItems(
        FeaturedGroupPageRequest $request,
        Tenant $tenant,
        FeaturedGroup $featuredGroup,
        FeaturedGroupService $featuredGroupService,
    ): JsonResponse {
        abort_unless($featuredGroup->tenant_code === $tenant->codigo, 404);

        $page = (int) $request->validated('page', 1);

        return response()->json($featuredGroupService->itemsResponse(
            $featuredGroup,
            $page,
            $this->userId($request),
        ));
    }

    public function show(
        CatalogItemDetailRequest $request,
        Tenant $tenant,
        CatalogItem $catalogItem,
        CatalogService $catalogService,
        CatalogItemAllowanceService $allowances,
    ): CatalogItemDetailResource {
        abort_unless($catalogItem->tenant_code === $tenant->codigo, 404);

        $variantId = $request->validated('variant_id');

        $item = $catalogService->getDetail(
            $catalogItem,
            $variantId === null ? null : (int) $variantId,
        );
        $allowances->attach(collect([$item]), $this->userId($request));

        return CatalogItemDetailResource::make($item);
    }

    public function variantOptions(
        CatalogVariantOptionsRequest $request,
        Tenant $tenant,
        CatalogItem $catalogItem,
        VariantSelectionService $variantSelectionService,
        CartService $cartService,
    ): CatalogVariantOptionsResource {
        abort_unless($catalogItem->tenant_code === $tenant->codigo, 404);

        $includedVariantId = null;
        $cartItemId = $request->validated('cart_item_id');
        $selectedValues = $request->validated('selected_values', []);

        if ($cartItemId !== null) {
            $cartItem = $cartService->show($tenant, $request)
                ->items
                ->firstWhere('id', (int) $cartItemId);
            abort_unless($cartItem?->catalog_item_id === $catalogItem->id, 404);
            $includedVariantId = $cartItem->variant_id;

            if ($selectedValues === [] && $cartItem->variant !== null) {
                $selectedValues = $cartItem->variant
                    ->selectorOptions($catalogItem->itemAttributes)
                    ->all();
            }
        }

        return CatalogVariantOptionsResource::make(
            $variantSelectionService->options(
                $catalogItem,
                $selectedValues,
                $includedVariantId,
            )
        );
    }

    public function store(
        StoreCatalogItemRequest $request,
        Tenant $tenant,
        CatalogService $catalogService,
    ): JsonResponse {
        $catalogItem = $catalogService->create([
            ...$request->validated(),
            'tenant_code' => $tenant->codigo,
        ]);

        return CatalogItemResource::make($catalogItem)
            ->response()
            ->setStatusCode(201);
    }

    private function userId(Request $request): ?int
    {
        $userId = $request->user()?->getAuthIdentifier() ?? Auth::guard('sanctum')->id();

        return $userId === null ? null : (int) $userId;
    }
}
