<?php

namespace App;

use App\Facades\Settings;
use App\Http\Requests\AddVehicleRequest;
use App\Http\Requests\UpdateVehicleRequest;
use App\Modules\Lookup\Contracts\VehicleLookupData;
use Mtc\MercuryDataModels\VehicleType;
use App\Traits\EnsuresVehicleAttribute;
use App\Traits\MapsTaxonomies;
use App\Events\NewVehicleImported;
use App\VehicleSpec\Jobs\FetchVehicleSpecData;
use App\VehicleSpec\VehicleSpecServiceHelper;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\QueryException;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use Mtc\ContentManager\Facades\Media;
use Mtc\ContentManager\Traits\EnsuresSlug;
use Mtc\MercuryDataModels\Services\FinanceService;
use Mtc\MercuryDataModels\Services\FinanceServiceHelper;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\VehicleSpecType;
use Mtc\MercuryDataModels\VehicleStandardEquipment;
use Mtc\MercuryDataModels\VehicleTechnicalData;
use Mtc\VehicleLookup\Contracts\VehicleStandardEquipmentItem;
use Mtc\VehicleLookup\Contracts\VehicleTechnicalDataItem;
use Mtc\VehicleLookup\VehicleLookupResponse;
use Mtc\VehicleLookup\VehicleLookupService;

class VehicleRepository
{
    use DispatchesJobs;
    use SavesSeoData;
    use SavesVehicleSpecTypeData;
    use EnsuresVehicleAttribute;
    use EnsuresSlug;
    use MapsTaxonomies;

    protected string $providerName = 'vehicle-repository';

    public function __construct(private readonly VehicleLookupService $lookupService)
    {
        //
    }

    public function create(AddVehicleRequest $request): Vehicle
    {
        if ($this->shouldFetchSpecs($request)) {
            $vehicle = $this->createVehicleWithSpecs($request);
        } else {
            /** @var Vehicle $vehicle */
            $vehicle = Vehicle::query()->create([
                'title' => $request->input('title'),
                'make_id' => $request->input('make_id'),
                'model_id' => $request->input('model_id'),
                'is_new' => $request->input('is_new') ?? 0,
                'type' => $request->input('type', VehicleType::CAR->value),
                'uuid' => 'web-' . strtolower(Str::random(24)),
            ]);

            $this->handleVariant($request, $vehicle);
            $this->syncOptionalExtras($vehicle, $request->input('optional_extras', []));
            $this->setAutoTraderPublishFlags($vehicle);
        }

        NewVehicleImported::dispatch($vehicle, [], '');

        return $vehicle;
    }

    public function update(UpdateVehicleRequest $request, Vehicle $vehicle): bool
    {
        $hadNoEquipmentBeforeUpdate = $vehicle->equipment()->doesntExist();
        DB::beginTransaction();
        try {
            $vehicle->fill($request->input());
            $vehicle->slug = $request->input('seo.slug') ?? $vehicle->slug;
            if (empty($vehicle->slug)) {
                $vehicle->slug = $this->buildSlug($vehicle);
            }
            $this->syncLabels($vehicle, collect($request->input('labels')));
            $vehicle->save();
            Media::setUsesForModel($request->input('media', []), $vehicle);
            Media::setUseOrdering(array_flip($request->input('media', [])), $vehicle);
            if (!empty($request->input('media'))) {
                $this->setInteriorExterior($request->input('media'), $request->input('media_uses'), $vehicle);
            }
            if (!empty($request->primaryMedia())) {
                Media::setPrimaryUse($request->input('media', []), $request->primaryMedia(), $vehicle);
            }
            if (Settings::get('auto-trader-hub-enabled')) {
                $vehicle->autoTraderData()->updateOrCreate([
                    'vehicle_id' => $vehicle->id,
                ], [
                    'derivative_id' => $request->input('auto_trader_data.derivative_id'),
                    'publish_advert' => $request->input('auto_trader_data.publish_advert'),
                    'publish_profile' => $request->input('auto_trader_data.publish_profile'),
                ]);
            }
            $this->saveSeo($vehicle, $request->input('seo', []));
            $this->syncFeatures($vehicle, collect($request->input('features', [])));
            $this->syncEquipment($vehicle, collect($request->input('equipment', [])));
            $this->syncSpecs($vehicle, collect($request->input('specs', [])));
            collect($request->input('extra', []))
                ->filter(fn ($attribute) => isset($attribute['value']) && empty($attribute['readonly']))
                ->each(fn ($attribute) => $this->saveAttributeValue($vehicle, $attribute));
            $this->checkFinanceSync($vehicle);
            $this->saveFinance($vehicle, $request->input('finance_examples', []));
            DB::commit();
        } catch (QueryException $exception) {
            DB::rollBack();
            $this->rethrowDuplicateAsValidation($exception);

            throw $exception;
        }

        if ($hadNoEquipmentBeforeUpdate && VehicleSpecServiceHelper::canRunForVehicle($vehicle)) {
            FetchVehicleSpecData::dispatch($vehicle);
        }

        return true;
    }

    /**
     * Turn a duplicate-entry database error into a user-facing validation error so admins
     * see which kind of item clashed rather than a generic server error. The raw SQL is
     * never exposed. Any other query error is left untouched for the caller to re-throw.
     */
    private function rethrowDuplicateAsValidation(QueryException $exception): void
    {
        if (($exception->errorInfo[1] ?? null) !== 1062) {
            return;
        }

        $message = $exception->getMessage();

        [$field, $label] = match (true) {
            str_contains($message, 'vehicle_standard_equipment') => ['equipment', 'a piece of equipment'],
            str_contains($message, 'vehicle_tech_data') => ['specs', 'a technical specification'],
            str_contains($message, 'vehicle_features') => ['features', 'a feature'],
            default => ['vehicle', 'an item'],
        };

        throw ValidationException::withMessages([
            $field => ["Could not save because {$label} is duplicated. Please make sure each entry is unique."],
        ]);
    }

    public function findVehicleByVrm(string $vrm, bool $withPreviewImage = false): array
    {
        try {
            $specService = $this->lookupService->findByVRM($vrm, 0);
            if ($lookupActiveDriver = $this->lookupService->findActiveDriver()) {
                $this->setProviderName($lookupActiveDriver);
            }
            $data = $this->mapTechnicalData($specService);
            if ($withPreviewImage) {
                $data['preview_image'] = $this->previewImage($data);
            }
            return $data;
        } catch (\Throwable $throwable) {
            Log::warning($throwable->getMessage(), [$throwable->getTrace()]);
            throw ValidationException::withMessages([
                'Failed to retrieve vehicle ' . $vrm
                .  ' it may not exist in the providers database, please fill out vehicle details manually'
            ]);
        }
    }

    public function copy(Request $request, Vehicle $origin): Vehicle
    {
        $attributes = $origin->toArray();
        $attributes['uuid'] = 'web-' . strtolower(Str::random(24));
        $attributes['stock_provider'] = null;

        /** @var Vehicle $vehicle */
        $vehicle = Vehicle::query()->create($attributes);

        $origin->specs()
            ->get()
            ->each(fn (VehicleTechnicalData $spec) => $vehicle->specs()->create($spec->toArray()));

        return $vehicle;
    }

    public function restore(int $id): bool
    {
        return DB::transaction(function () use ($id) {
            $trashed = Vehicle::query()
                ->onlyTrashed()
                ->findOrFail($id);

            // Extract the original slug
            $originalSlug = preg_replace('/--trashed-[A-Za-z0-9]+$/', '', (string) $trashed->slug);

            // Check if a page with the original slug exists
            if (Vehicle::query()->where('slug', $originalSlug)->exists()) {
                throw new \Exception("A vehicle with the original slug '$originalSlug' already exists.");
            }

            $trashed->restore();
            $trashed->update(['slug' => $originalSlug]);
            return true;
        });
    }


    public function buildSlug(Vehicle $vehicle, ?string $type = null): string
    {
        $slug = match ($type ?: Settings::get('automotive-vehicles-url_building_format')) {
            'vrm-make-model' => Str::slug(
                $vehicle->registration_number . '-' . ($vehicle->make->name ?? '') . '-' . ($vehicle->model->name ?? '')
            ),
            'title' => Str::slug($vehicle->title),
            'uuid' => Str::slug($vehicle->uuid),
            'make-model-derivative' => Str::slug(
                ($vehicle->make->name ?? '') . '-'
                . ($vehicle->model->name ?? '') . '-'
                . ($vehicle->derivative ?? '')
            ),
            default => Str::slug($vehicle->title),
        };
        return str_replace('/', '', $slug);
    }

    /**
     * Length of the random suffix appended when a generated slug collides with an existing one.
     * The make-model-derivative format is not guaranteed unique, so it uses a shorter suffix.
     */
    public function slugSuffixLength(?string $type = null): int
    {
        return match ($type ?: Settings::get('automotive-vehicles-url_building_format')) {
            'make-model-derivative' => 5,
            default => 12,
        };
    }

    public function mapTechnicalData(VehicleLookupData|VehicleLookupResponse $data): array
    {
        $make_id = !empty($data->make)
            ? $this->getMappedTaxonomy(
                TaxonomyMap::MAKE,
                $data->make,
                $data->toArray()
            ) : null;

        $model_id = !empty($data->model)
            ? $this->getMappedTaxonomy(
                TaxonomyMap::MODEL,
                $data->model,
                $data->toArray(),
                $make_id
            ) : null;

        return collect([
            'title' => trim(
                ($data->make ?? '') . ' ' .
                ($data->model ?? '') . ' ' .
                ($data->derivative ?? '')
            ),
            'registration_number' => $data->registration_number ?? null,
            'odometer_mi' => $data->mileage ?? null,
            'make_id' => $make_id,
            'model_id' => $model_id,
            'make_name' => $data->make,
            'model_name' => $data->model,
            'derivative' => $data->derivative ?? null,
            'engine_size_cc' => $data->engine_capacity_cc ?? null,
            'door_count' => $data->doors ?? null,
            'drivetrain' => $data->drivetrain ?? null,
            'vin' => $data->vin ?? null,
            'seats' => $data->seats ?? null,
            'previous_owner_count' => $data->previous_owner_count ?? null,
            'co2' => $data->co2 ?? null,
            'mpg' => $data->mpg ?? null,
            'first_registration_date' => $data->registration_date ?: null,
            'type' => $this->getVehicleType($data->vehicle_type),
            'manufacture_year' => $data->manufacture_year ?? $data->model_year ?? null,
            'colour' => $data->colour ?? null,
            'drivetrain_id' => !empty($data->drivetrain)
                ? $this->getMappedTaxonomy(
                    TaxonomyMap::DRIVETRAIN,
                    $data->drivetrain,
                    $data->toArray()
                ) : null,
            'body_style_name' => $data->body_type,
            'body_style_id' => $this->getMappedTaxonomy(
                TaxonomyMap::BODY_STYLE,
                $data->body_type ?? $data->body_style,
                $data->toArray()
            ),
            'transmission_name' => $data->transmission,
            'transmission_id' => !empty($data->transmission)
                ? $this->getMappedTaxonomy(
                    TaxonomyMap::TRANSMISSION,
                    $data->transmission,
                    $data->toArray()
                ) : null,
            'fuel_type_name' => $data->fuel_type,
            'fuel_type_id' => !empty($data->fuel_type)
                ? $this->getMappedTaxonomy(
                    TaxonomyMap::FUEL_TYPE,
                    $data->fuel_type,
                    $data->toArray()
                ) : null,
            'features' => $data->features ?? null,
            'standard_equipment' => $data->standard_equipment ?? null,
            'technical_data' => $data->technical_data ?? null,
            'battery_capacity_kwh' => $data->battery_capacity_kwh ?? null,
            'battery_charge_time' => $data->battery_charge_time ?? null,
            'battery_quick_charge_time' => $data->battery_quick_charge_time ?? null,
            'battery_quick_charge_start_level' => $data->battery_quick_charge_start_level ?? null,
            'battery_quick_charge_level' => $data->battery_quick_charge_level ?? null,
            'plug_type' => $data->plug_type ?? null,
            'rapid_charge_plug_type' => $data->rapid_charge_plug_type ?? null,
            'battery_slow_charge_description' => $data->battery_slow_charge_description ?? null,
            'battery_quick_charge_description' => $data->battery_quick_charge_description ?? null,
        ])->filter()->toArray();
    }

    public function getVehicleWarnings(): array
    {
        $notForListingSites = [
            'no_images',
            'no_primary_image',
            'no_finance',
            'no_description',
        ];

        $warningTypes = [
            'total_vehicles',
            'no_price',
            'no_make',
            'no_model',
            'no_fuel_type',
            'no_body_style',
            'no_transmission',
            'no_images',
            'no_primary_image',
            'no_finance',
            'no_description',
        ];

        if ($this->isAutoTraderApiExportEnabled()) {
            $warningTypes[] = 'at_export_error';
        }

        return collect($warningTypes)
            ->reject(fn ($type) => tenant('type') === 'listing' && in_array($type, $notForListingSites))
            ->map(fn (string $type) => $this->getWarningValue($type))
            ->filter(fn ($data_by_type) => !empty($data_by_type['values']))
            ->values()
            ->toArray();
    }

    private function isAutoTraderApiExportEnabled(): bool
    {
        return Settings::get('sales-channels-auto-trader-enabled', false)
            && Settings::get('sales-channels-auto-trader-method') !== 'ftp';
    }

    public function getHasUnmappedTaxonomies(): bool
    {
        return TaxonomyMapable::query()
            ->where('tenant', tenant('id'))
            ->where('mappable_type', 'vehicle')
            ->whereHas('taxonomyMap', fn ($query) => $query->whereNull('taxonomy_id'))
            ->exists();
    }

    private function syncLabels(Vehicle $vehicle, Collection $labels): void
    {
        $vehicle->labels()->sync($labels->pluck('id'));
    }

    private function saveFinance(Vehicle $vehicle, array $input): void
    {
        $vehicle->financeExamples()->whereNotIn('id', collect($input)->pluck('id'))->delete();
        $data = collect($input)
            ->filter(fn ($entry) => !is_numeric($entry['id']) || ($entry['provider'] ?? '') === 'manual')
            ->map(function (array $entry) {
                $entry['provider'] = 'manual';
                return $entry;
            });

        $data->each(fn ($example) => $vehicle->financeExamples()->updateOrCreate([
            'id' => $example['id']
        ], $example));
    }

    private function checkFinanceSync(Vehicle $vehicle): void
    {
        if ($this->shouldTriggerFinanceCheck($vehicle)) {
            new FinanceService()->request($vehicle, [], true);
        }
    }

    /**
     * Check whether we have enough info to trigger vehicle finance fetch
     *
     * @param Vehicle $vehicle
     * @return bool
     */
    private function shouldTriggerFinanceCheck(Vehicle $vehicle): bool
    {
        return FinanceServiceHelper::hasEnabledProvider()
            && app()->runningUnitTests() === false
            && empty($vehicle->data['stop_finance_sync'])
            && !empty($vehicle->getAttribute('cap_id'))
            && $vehicle->financeExamples()->exists() === false;
    }

    protected function setAutoTraderPublishFlags(Vehicle $vehicle): void
    {
        if (Settings::get('sales-channels-auto-trader-enabled') === false) {
            return;
        }

        if ($vehicle->autoTraderData()->exists()) {
            return;
        }

        $publishAdvert = $vehicle->is_new
            ? (bool) Settings::get('auto-trader-connect-publish-new-cars')
            : (bool) Settings::get('auto-trader-connect-publish-used-cars');

        $publishProfile = $vehicle->is_new
            ? (bool) Settings::get('auto-trader-connect-profile-new-cars')
            : (bool) Settings::get('auto-trader-connect-profile-used-cars');

        $vehicle->autoTraderData()->create([
            'publish_advert' => $publishAdvert,
            'publish_profile' => $publishProfile,
        ]);
    }

    protected function getProviderName(): string
    {
        return $this->providerName;
    }

    protected function setProviderName(string $providerName): void
    {
        $this->providerName = $providerName;
    }

    protected function handleVariant($request, Vehicle $vehicle): void
    {
        if (!$request->filled('variant')) {
            return;
        }

        $variantTypeColumn = $this->getVariantColumn($request->input('variant_type'));
        if ($variantTypeColumn && $this->lookupService->hasActiveDriver()) {
            $variant = $request->input('variant');
            $vehicleData = $this->mapTechnicalData($this->lookupService->getTechnicalData($variant));
            $vehicleData[$variantTypeColumn] = $variant;

            $vehicle->fill($vehicleData)->save();

            $this->syncStandardEquipment($vehicle, $vehicleData['standard_equipment'] ?? []);
            $this->syncTechnicalData($vehicle, $vehicleData['technical_data'] ?? []);

            if (isset($vehicleData['features']) && $vehicleData['features']->count()) {
                foreach ($vehicleData['features'] as $feature) {
                    $vehicle->features()->create([
                        'name' => $feature
                    ]);
                }
            }
        }
    }

    protected function getVariantColumn($variantType): ?string
    {
        return match ($variantType) {
            'cap' => 'cap_id',
            'auto-trader' => 'auto_trader_id',
            'motor-check' => 'motor_check_id',
            default => null,
        };
    }

    protected function shouldFetchSpecs($request): bool
    {
        return $request->filled('registration_number')
            && $this->lookupService->hasActiveDriver();
    }

    protected function createVehicleWithSpecs($request): Vehicle
    {
        $vehicleData = $this->findVehicleByVrm($request->input('registration_number'));
        $vehicleData['is_new'] = $request->input('is_new');
        $vehicleData['uuid'] = 'web-' . strtolower(Str::random(24));
        /** @var Vehicle $vehicle */
        $vehicle = Vehicle::query()->create($vehicleData);

        $this->syncStandardEquipment($vehicle, $vehicleData['standard_equipment'] ?? []);
        $this->syncTechnicalData($vehicle, $vehicleData['technical_data'] ?? []);
        $this->syncOptionalExtras($vehicle, $request->input('optional_extras', []));
        $this->storeUnmappedTaxonomy($vehicle);
        $this->setAutoTraderPublishFlags($vehicle);

        return $vehicle;
    }

    protected function syncOptionalExtras(Vehicle $vehicle, array $extras): void
    {
        collect($extras)->each(function (array $extra) use ($vehicle) {
            $description = $extra['description'] ?? null;
            if (empty($description)) {
                return;
            }
            VehicleStandardEquipment::query()->updateOrCreate(
                [
                    'vehicle_id' => $vehicle->id,
                    'vehicle_type' => 'vehicle',
                    'description' => $description,
                ],
                [
                    'type' => VehicleSpecType::OPTIONAL_EQUIPMENT->value,
                    'code' => $extra['code'] ?? null,
                    'category' => $extra['category'] ?? null,
                    'price' => $extra['price'] ?? null,
                    'vat_amount' => $extra['vat'] ?? null,
                    'updated_at' => now(),
                ]
            );
        });
    }

    protected function syncStandardEquipment(Vehicle $vehicle, $equipment): void
    {
        collect($equipment)->each(function (VehicleStandardEquipmentItem $item) use ($vehicle) {
            VehicleStandardEquipment::query()->updateOrCreate(
                [
                    'vehicle_id' => $vehicle->id,
                    'vehicle_type' => 'vehicle',
                    'description' => $item->description,
                ],
                [
                    'type' => $item->type,
                    'code' => $item->code,
                    'category' => $item->category_description,
                    'updated_at' => now()
                ]
            );
        });
    }

    protected function syncTechnicalData(Vehicle $vehicle, $technicalData): void
    {
        collect($technicalData)->each(function (VehicleTechnicalDataItem $item) use ($vehicle) {
            VehicleTechnicalData::query()->updateOrCreate([
                'vehicle_id' => $vehicle->id,
                'vehicle_type' => 'vehicle',
                'description' => $item->description,
                'category' => $item->category
            ], [
                'code' => $item->code,
                'value' => $item->value,
            ]);
        });
    }

    private function excludeSoldVehicles(): bool
    {
        return (bool) Settings::get('filter-results-exclude-sold-vehicles', false);
    }

    /**
     * Base query for the "Vehicle overview" sidebar counts. Sold vehicles are excluded from the
     * counts when the exclude-sold setting is enabled, mirroring how they are hidden from the list.
     */
    private function vehicleWarningQuery(): Builder
    {
        return Vehicle::query()
            ->when($this->excludeSoldVehicles(), fn (Builder $query) => $query->where('is_sold', false));
    }

    private function getWarningValue(string $type)
    {
        return match ($type) {
            'total_vehicles' => [
                'severity' => 'info',
                'label' => __('labels.total_count'),
                'values' => collect([
                    [
                        'label' => __('labels.published'),
                        'value' => $this->vehicleWarningQuery()->active()->count(),
                        'slug' => 'active',
                        'selections' => [ 'status' => 'is_published']
                    ],
                    [
                        'label' => __('labels.total'),
                        'value' => $this->vehicleWarningQuery()->count(),
                    ],
                ])->filter(fn ($row) => !empty($row['value']))->toArray(),
            ],
            'no_price' => [
                'severity' => 'warning',
                'label' => __('labels.vehicle_warnings.missing_price'),
                'values' => collect([
                    [
                        'label' => __('labels.published'),
                        'value' => $this->vehicleWarningQuery()->active()->where('price', '<=', 1)->count(),
                        'slug' => 'no_price_active',
                        'selections' => [ 'price_max' => 0, 'status' => 'is_published']
                    ],
                    [
                        'label' => __('labels.total'),
                        'value' => $this->vehicleWarningQuery()->where('price', '<=', 1)->count(),
                        'slug' => 'no_price',
                        'selections' => [ 'price_max' => 0]
                    ],
                ])->filter(fn ($row) => !empty($row['value']))->toArray(),
            ],
            'no_make' => [
                'severity' => 'warning',
                'label' => __('labels.vehicle_warnings.missing_make'),
                'values' => collect([
                    [
                        'label' => __('labels.published'),
                        'value' => $this->vehicleWarningQuery()->active()->whereNull('make_id')->count(),
                        'slug' => 'no_make_active',
                        'selections' => [ 'make_id' => 'null', 'status' => 'is_published']
                    ],
                    [
                        'label' => __('labels.total'),
                        'value' => $this->vehicleWarningQuery()->whereNull('make_id')->count(),
                        'slug' => 'no_make',
                        'selections' => [ 'make_id' => 'null', 'status' => 'is_published']
                    ],
                ])->filter(fn ($row) => !empty($row['value']))->toArray(),
            ],
            'no_model' => [
                'severity' => 'warning',
                'label' => __('labels.vehicle_warnings.missing_model'),
                'values' => collect([
                    [
                        'label' => __('labels.published'),
                        'value' => $this->vehicleWarningQuery()->active()->whereNull('model_id')->count(),
                        'slug' => 'no_model_active',
                        'selections' => [ 'model_id' => 'null', 'status' => 'is_published']
                    ],
                    [
                        'label' => __('labels.total'),
                        'value' => $this->vehicleWarningQuery()->whereNull('model_id')->count(),
                        'slug' => 'no_model',
                        'selections' => [ 'model_id' => 'null']
                    ],
                ])->filter(fn ($row) => !empty($row['value']))->toArray(),
            ],
            'no_fuel_type' => [
                'severity' => 'warning',
                'label' => __('labels.vehicle_warnings.missing_fuel_type'),
                'values' => collect([
                    [
                        'label' => __('labels.published'),
                        'value' => $this->vehicleWarningQuery()->active()->whereNull('fuel_type_id')->count(),
                        'slug' => 'no_fuel_type_active',
                        'selections' => [ 'fuel_type_id' => 'null', 'status' => 'is_published']
                    ],
                    [
                        'label' => __('labels.total'),
                        'value' => $this->vehicleWarningQuery()->whereNull('fuel_type_id')->count(),
                        'slug' => 'no_fuel_type',
                        'selections' => [ 'fuel_type_id' => 'null']
                    ],
                ])->filter(fn ($row) => !empty($row['value']))->toArray(),
            ],
            'no_body_style' => [
                'severity' => 'warning',
                'label' => __('labels.vehicle_warnings.missing_body_style'),
                'values' => collect([
                    [
                        'label' => __('labels.published'),
                        'value' => $this->vehicleWarningQuery()->active()->whereNull('body_style_id')->count(),
                        'slug' => 'no_body_style_active',
                        'selections' => [ 'body_style_id' => 'null', 'status' => 'is_published']
                    ],
                    [
                        'label' => __('labels.total'),
                        'value' => $this->vehicleWarningQuery()->whereNull('body_style_id')->count(),
                        'slug' => 'no_body_style',
                        'selections' => [ 'body_style_id' => 'null']
                    ],
                ])->filter(fn ($row) => !empty($row['value']))->toArray(),
            ],
            'no_transmission' => [
                'severity' => 'warning',
                'label' => __('labels.vehicle_warnings.missing_transmission'),
                'values' => collect([
                    [
                        'label' => __('labels.published'),
                        'value' => $this->vehicleWarningQuery()->active()->whereNull('transmission_id')->count(),
                        'slug' => 'no_transmission_active',
                        'selections' => [ 'transmission_id' => 'null', 'status' => 'is_published']
                    ],
                    [
                        'label' => __('labels.total'),
                        'value' => $this->vehicleWarningQuery()->whereNull('transmission_id')->count(),
                        'slug' => 'no_transmission',
                        'selections' => [ 'transmission_id' => 'null']
                    ],
                ])->filter(fn ($row) => !empty($row['value']))->toArray(),
            ],
            'no_primary_image' => [
                'severity' => 'warning',
                'label' => __('labels.vehicle_warnings.missing_primary_image'),
                'values' => collect([
                    [
                        'label' => __('labels.published'),
                        'value' => $this->vehicleWarningQuery()->active()->whereDoesntHave('primaryMediaUse')->count(),
                        'slug' => 'no_primary_image_active',
                    ],
                    [
                        'label' => __('labels.total'),
                        'value' => $this->vehicleWarningQuery()->whereDoesntHave('primaryMediaUse')->count(),
                        'slug' => 'no_primary_image',
                    ],
                ])->filter(fn ($row) => !empty($row['value']))->toArray(),
            ],
            'no_images' => [
                'severity' => 'warning',
                'label' => __('labels.vehicle_warnings.missing_images'),
                'values' => collect([
                    [
                        'label' => __('labels.published'),
                        'value' => $this->vehicleWarningQuery()->active()->whereDoesntHave('mediaUses')->count(),
                        'slug' => 'no_images_active',
                        'selections' => [ 'image_count_max' => 0, 'status' => 'is_published']
                    ],
                    [
                        'label' => __('labels.total'),
                        'value' => $this->vehicleWarningQuery()->whereDoesntHave('mediaUses')->count(),
                        'slug' => 'no_images',
                        'selections' => [ 'image_count_max' => 0]
                    ],
                ])->filter(fn ($row) => !empty($row['value']))->toArray(),
            ],
            'no_finance' => [
                'severity' => 'warning',
                'label' => __('labels.vehicle_warnings.missing_finance'),
                'values' => collect([
                    [
                        'label' => __('labels.published'),
                        'value' => $this->vehicleWarningQuery()->active()->whereDoesntHave('financeExamples')->count(),
                        'slug' => 'no_finance_active',
                    ],
                    [
                        'label' => __('labels.total'),
                        'value' => $this->vehicleWarningQuery()->whereDoesntHave('financeExamples')->count(),
                        'slug' => 'no_finance',
                    ],
                ])->filter(fn ($row) => !empty($row['value']))->toArray(),
            ],
            'no_description' => [
                'severity' => 'warning',
                'label' => __('labels.vehicle_warnings.missing_description'),
                'values' => collect([
                    [
                        'label' => __('labels.published'),
                        'value' => $this->vehicleWarningQuery()->active()->whereNull('description')->count(),
                        'slug' => 'no_description_active',
                    ],
                    [
                        'label' => __('labels.total'),
                        'value' => $this->vehicleWarningQuery()->whereNull('description')->count(),
                        'slug' => 'no_description',
                    ],
                ])->filter(fn ($row) => !empty($row['value']))->toArray(),
            ],
            'at_export_error' => [
                'severity' => 'warning',
                'label' => __('labels.vehicle_warnings.at_export_error'),
                'values' => collect([
                    [
                        'label' => __('labels.published'),
                        'value' => $this->vehicleWarningQuery()->active()
                            ->whereHas(
                                'autoTraderData',
                                fn ($q) => $q->whereNotNull('at_export_error')->where('at_export_error', '!=', '')
                            )
                            ->count(),
                        'slug' => 'at_export_error_active',
                        'selections' => ['at_export_error' => 'has_error', 'status' => 'is_published'],
                    ],
                    [
                        'label' => __('labels.total'),
                        'value' => $this->vehicleWarningQuery()
                            ->whereHas(
                                'autoTraderData',
                                fn ($q) => $q->whereNotNull('at_export_error')->where('at_export_error', '!=', '')
                            )
                            ->count(),
                        'slug' => 'at_export_error',
                        'selections' => ['at_export_error' => 'has_error'],
                    ],
                ])->filter(fn ($row) => !empty($row['value']))->toArray(),
            ],
            default => [],
        };
    }

    private function setInteriorExterior(array $media_ids, array $media_data, Vehicle $vehicle): void
    {
        $interior = collect($media_data)
            ->filter(fn ($entry) => $entry['media']['interior'] ?? false)
            ->pluck('media.id')
            ->toArray();
        $vehicle->mediaUses()
            ->whereIn('media_id', $interior)
            ->update(['interior' => 1]);
        $vehicle->mediaUses()
            ->whereIn('media_id', array_diff($media_ids, $interior))
            ->update(['interior' => 0]);

        $exterior = collect($media_data)
            ->filter(fn ($entry) => $entry['media']['exterior'] ?? false)
            ->pluck('media.id')
            ->toArray();
        $vehicle->mediaUses()
            ->whereIn('media_id', $exterior)
            ->update(['exterior' => 1]);
        $vehicle->mediaUses()
            ->whereIn('media_id', array_diff($media_ids, $exterior))
            ->update(['exterior' => 0]);
    }

    private function getVehicleType(?string $type): VehicleType
    {
        $normalized = strtolower(trim($type ?? ''));

        // Map free-text aliases that don't equal an enum value directly.
        $normalized = match ($normalized) {
            'bike' => VehicleType::MOTORCYCLE->value,
            'light commercial vehicle', 'van', 'panel van' => VehicleType::LCV->value,
            default => $normalized,
        };

        // Enum is the source of truth: any canonical value (incl. campervan and
        // future types) resolves; anything unknown falls back to car as before.
        return VehicleType::tryFrom($normalized) ?? VehicleType::CAR;
    }

    public function previewImage($data): string
    {
        return 'https://cdn.imagin.studio/getImage?' . http_build_query([
                'customer' => Settings::get('imagin-placeholders-client-key') ?: config('services.imagin-studio.key'),
                'make' => $data['make_name'] ?? null,
                'modelFamily' => $data['model_name'] ?? null,
                'paintdescription' => $data['colour'] ?? null,
                'modelYear' => $data['manufacture_year'] ?? null,
                'aspectRatio' => '16:9',
                'zoomLevel' => 50,
            ]);
    }
}
