<?php

namespace App\VehicleSpec\Jobs;

use App\TaxonomyMap;
use App\Traits\MapsTaxonomies;
use App\VehicleSpec\Services\HPICapIdLookupService;
use App\VehicleSpec\Services\LocalVehicleCapIdCacheService;
use Mtc\MercuryDataModels\VehicleType;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\Notifications\Facades\Notification;

class VehicleCapIdLookupViaHPI implements ShouldQueue
{
    use Dispatchable;
    use InteractsWithQueue;
    use Queueable;
    use SerializesModels;
    use MapsTaxonomies;

    private array $capFields = [
        'cap_id',
        'cap_code'
    ];

    public function __construct(
        protected readonly Vehicle $vehicle,
        protected bool $force = false,
    ) {
        $this->onQueue('specs');
    }

    public function handle(): void
    {
        $capCache = App::make(LocalVehicleCapIdCacheService::class);

        if (!$this->force && !empty($this->vehicle->cap_id)) {
            return;
        }

        if (!$this->force) {
            $cachedResult = $capCache->lookup($this->vehicle);
            if ($cachedResult) {
                $this->vehicle->update($cachedResult);
                return;
            }
        }

        $result = $this->hpiCapIdLookupService()->lookup($this->vehicle);

        if (!empty($result['cap_id'])) {
            $originalMakeId = $this->vehicle->make_id;
            $originalModelId = $this->vehicle->model_id;

            $updateValues = $this->valuesToUpdate($result);
            $this->vehicle->update($updateValues);

            $matchedMakeId = !empty($result['make'])
                ? $this->getMappedTaxonomy(TaxonomyMap::MAKE, $result['make'], $result)
                : null;
            $matchedModelId = $matchedMakeId && !empty($result['model'])
                ? $this->getMappedTaxonomy(TaxonomyMap::MODEL, $result['model'], $result, $matchedMakeId)
                : null;
            if (!$matchedModelId && $matchedMakeId && !empty($result['smmt_model'])) {
                // DVLA model descriptions bundle trim/engine codes and often fail an exact
                // taxonomy match; retry with the cleaner SMMT model name.
                $matchedModelId = $this->getMappedTaxonomy(
                    TaxonomyMap::MODEL,
                    $result['smmt_model'],
                    $result,
                    $matchedMakeId,
                );
            }
            $matchedFuelTypeId = !empty($result['fuel_type'])
                ? $this->getMappedTaxonomy(TaxonomyMap::FUEL_TYPE, $result['fuel_type'], $result)
                : null;
            $matchedBodyStyleId = !empty($result['body_style'])
                ? $this->getMappedTaxonomy(TaxonomyMap::BODY_STYLE, $result['body_style'], $result)
                : null;
            $matchedTransmissionId = !empty($result['transmission'])
                ? $this->getMappedTaxonomy(TaxonomyMap::TRANSMISSION, $result['transmission'], $result)
                : null;

            $capCache->store([
                'make_id' => $originalMakeId,
                'model_id' => $originalModelId,
                'derivative' => $this->vehicle->derivative,
                'cap_id' => $result['cap_id'],
                'cap_code' => $result['cap_code'] ?? null,
                'cap_matched_make_id' => $matchedMakeId,
                'cap_matched_model_id' => $matchedModelId,
                'cap_matched_fuel_type_id' => $matchedFuelTypeId,
                'cap_matched_body_style_id' => $matchedBodyStyleId,
                'cap_matched_transmission_id' => $matchedTransmissionId,
            ]);
        } else {
            Notification::addNotification(
                'error',
                'Failed to get CAP ID for vehicle via HPI',
                [
                    $this->vehicle->registration_number,
                ],
                'edit-vehicles',
                "/manage-content/vehicles/edit/{$this->vehicle->id}",
            );
        }

        $this->storeUnmappedTaxonomy($this->vehicle);
    }

    public function failed(?\Throwable $exception): void
    {
        if (Str::contains($exception->getMessage(), 'Operation timed out after')) {
            return;
        }

        Log::error($exception->getMessage(), [
            'tenant' => tenant('id'),
            'vehicle' => $this->vehicle,
            'exception' => $exception,
        ]);
    }

    protected function getProviderName(): string
    {
        return 'hpi';
    }

    protected function getDetailsForTaxonomyMap(array $record): array
    {
        return [
            'tenant_id' => tenant('id'),
            'registration_number' => $this->vehicle?->registration_number ?? '',
            'make' => $record['make_id'] ?? '',
            'model' => $record['model_id'] ?? '',
            'fuel_type' => $record['fuel_type_id'] ?? '',
            'transmission' => $record['transmission_id'] ?? '',
        ];
    }

    private function hpiCapIdLookupService(): HPICapIdLookupService
    {
        return App::make(HPICapIdLookupService::class);
    }

    private function valuesToUpdate(array $result): array
    {
        return collect($result)
            ->filter(fn ($value, $field) => in_array($field, $this->capFields, true)
                || $this->columnCanBeUpdated($field))
            ->map(fn ($value, $field) => $this->columnAdjustedValue($value, $field, $result))
            ->filter()
            ->toArray();
    }

    private function columnCanBeUpdated($field): bool
    {
        return in_array($field, $this->capFields, true);
    }

    private function columnAdjustedValue($value, string $field, array $result)
    {
        $make_id = null;
        if ($field === 'model_id') {
            $make_id = $this->getMappedTaxonomy(TaxonomyMap::MAKE, $result['make_id'], $result);
        }
        return match ($field) {
            'type' => $value === 'Car' ? VehicleType::CAR->value : VehicleType::LCV->value,
            'make_id' =>  $this->getMappedTaxonomy(TaxonomyMap::MAKE, $value, $result),
            'model_id' =>  $this->getMappedTaxonomy(TaxonomyMap::MODEL, $value, $result, $make_id),
            default => $value,
        };
    }
}
