<?php

namespace App\VehicleSpec\Jobs;

use App\Facades\Settings;
use App\TaxonomyMap;
use App\Traits\MapsTaxonomies;
use App\VehicleSpec\Services\Cap;
use App\VehicleSpec\Services\LocalVehicleCapIdCacheService;
use App\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 VehicleCapIdLookup 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');
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle(): void
    {
        if (!$this->force && !empty($this->vehicle->cap_id)) {
            return;
        }

        if (!$this->force) {
            $cachedResult = App::make(LocalVehicleCapIdCacheService::class)->lookup($this->vehicle);
            if ($cachedResult) {
                $this->vehicle->update($cachedResult);
                $this->vehicle->equipment()->delete();
                $this->vehicle->specs()->delete();
                FetchVehicleSpecData::dispatch($this->vehicle);
                return;
            }
        }

        $result = $this->capService()->capIdLookup($this->vehicle);
        $mappedResult = $this->valuesToUpdate($result);
        $this->vehicle->update($mappedResult);
        if (!empty($result['cap_id'])) {
            App::make(LocalVehicleCapIdCacheService::class)->store($mappedResult);
            $this->vehicle->equipment()->delete();
            $this->vehicle->specs()->delete();
            FetchVehicleSpecData::dispatch($this->vehicle);
        } else {
            Notification::addNotification(
                'error',
                'Failed to get CAP ID for vehicle',
                [
                    $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 'cap';
    }

    protected function getDetailsForTaxonomyMap(array $record)
    {
        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 capService(): Cap
    {
        return App::make(Cap::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)
            || Settings::get('vehicle-spec-providers-cap-enrich-data');
    }

    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),
            'fuel_type_id' =>  $this->getMappedTaxonomy(TaxonomyMap::FUEL_TYPE, $value, $result),
            'body_style_id' =>  $this->getMappedTaxonomy(TaxonomyMap::BODY_STYLE, $value, $result),
            'transmission_id' =>  $this->getMappedTaxonomy(TaxonomyMap::TRANSMISSION, $value, $result),
            default => $value,
        };
    }
}
