<?php

namespace App\Http\Controllers;

use App\CatalogOfferMatcher;
use App\Facades\Feature;
use App\Filter;
use App\Http\Requests\NewCarSearchRequest;
use App\Http\Requests\ViewNewCarRequest;
use App\Http\Resources\NewCarListResource;
use App\Http\Resources\NewCarResource;
use App\Modules\PlaceholderImages\ImaginStudio;
use App\Traits\CacheObject;
use App\Traits\ModelsForMakeInSearch;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse;
use Mtc\MercuryDataModels\CatalogOffer;
use Mtc\MercuryDataModels\Filters\VehicleAttributeBooleanFilter;
use Mtc\MercuryDataModels\Filters\VehicleAttributeSelectFilter;
use Mtc\MercuryDataModels\Filters\VehicleAttributeValueMaxFilter;
use Mtc\MercuryDataModels\Filters\VehicleAttributeValueMinFilter;
use Mtc\MercuryDataModels\NewCar;
use Mtc\MercuryDataModels\VehicleAttribute;

class NewCarController extends Controller
{
    use ModelsForMakeInSearch;
    use CacheObject;

    public function search(NewCarSearchRequest $request, ?string $make = null): array
    {
        $makeModel = $make ? Filter::matchSlugToRecord('make', $make) : null;
        $vehicleModel = $request->filled('model_id')
            ? Filter::matchSlugToRecord('model', $request->input('model_id'))
            : null;

        $baseQuery = NewCar::query()
            ->whereHas('make')
            ->whereHas('model')
            ->when($makeModel, fn($query) => $query->where('make_id', $makeModel->id))
            ->when($request->filled('body_type'), fn($query) => $query->whereHas(
                'bodyStyle',
                fn($query) => $query->where('slug', $request->input('body_type'))
            ))
            ->when($request->filled('fuel_type'), fn($query) => $query->whereHas(
                'fuelTypes',
                fn($query) => $query->whereIn('slug', $request->input('fuel_type'))
            ))
            ->when($request->filled('franchise'), fn($query) => $query->whereHas(
                'franchise',
                fn($query) => $query->where('slug', $request->input('franchise'))
            ))
            ->when($request->filled('vehicle_type'), fn($query) => $query->where(
                'vehicle_type',
                $request->input('vehicle_type')
            ))
            ->whereModelSlug($request->input('model_id'))
            ->active();

        $this->applyAttributeFilters($baseQuery, $request->all());

        $cars = (clone $baseQuery)
            ->with([
                'mediaUses.media',
                'make',
                'model',
                'fuelTypes',
            ])
            ->setSortBy($request->input('sort_by'))
            ->paginate($request->input('per_page', 15));

        $catalogOffers = $this->getNewCarCatalogOffers($baseQuery);

        return [
            'make' => $makeModel?->name,
            'make_slug' => $makeModel?->slug,
            'model' => $vehicleModel?->name,
            'model_slug' => $vehicleModel?->slug,
            'models' => $makeModel ? $this->getModelsForMake(
                $makeModel->id,
                'newCars',
                null,
                $request->input('vehicle_type')
            ) : [],
            'offers' => new NewCarListResource($cars, $catalogOffers),
            'content' => [
                'title' => $makeModel
                    ? __('automotive.new_cars_for_make', ['make' => $makeModel->name])
                    : __('automotive.new_cars'),
                'description' => '',
            ],
            'imagin_studio_base_url' => Feature::isEnabled('imagin-studio-placeholders')
                ? new ImaginStudio()->getBaseUrl()
                : null,
        ];
    }

    public function show(ViewNewCarRequest $request): NewCarResource|JsonResponse
    {
        $car = $request->getNewCar();
        if (!$car) {
            abort(404);
        }
        $cache_path = 'new-car-' . $request->getRequestUri();
        return $this->cache($cache_path, 1, fn() => new NewCarResource($car)->toResponse($request));
    }

    private function applyAttributeFilters(Builder $query, array $params): void
    {
        $morphClass = (new NewCar())->getMorphClass();

        $filterableAttributes = VehicleAttribute::query()
            ->where('filterable', 1)
            ->where('model', $morphClass)
            ->get();

        foreach ($filterableAttributes as $attribute) {
            if ($attribute->type === 'boolean' && isset($params[$attribute->slug])) {
                (new VehicleAttributeBooleanFilter($attribute->slug, NewCar::class))
                    ->applyFilter($query, (array) $params[$attribute->slug]);
            } elseif (in_array($attribute->type, ['number', 'integer'])) {
                if (isset($params[$attribute->slug . '_min'])) {
                    (new VehicleAttributeValueMinFilter($attribute->slug . '_min', NewCar::class))
                        ->applyFilter($query, (array) $params[$attribute->slug . '_min']);
                }
                if (isset($params[$attribute->slug . '_max'])) {
                    (new VehicleAttributeValueMaxFilter($attribute->slug . '_max', NewCar::class))
                        ->applyFilter($query, (array) $params[$attribute->slug . '_max']);
                }
            } elseif ($attribute->type === 'select' && isset($params[$attribute->slug])) {
                (new VehicleAttributeSelectFilter($attribute->slug, NewCar::class))
                    ->applyFilter($query, (array) $params[$attribute->slug]);
            }
        }
    }

    private function getNewCarCatalogOffers(Builder $currentQuery): array
    {
        $offers = CatalogOffer::query()
            ->active()
            ->forNewCars()
            ->with(['mediaUses.media', 'rules'])
            ->get();

        return (new CatalogOfferMatcher($currentQuery))
            ->getMatchingOffers($offers)
            ->values()
            ->all();
    }
}
