<?php

namespace App\VehicleSpec\Jobs;

use App\VehicleRepository;
use App\VehicleSpec\Contracts\VehicleSpecData;
use App\VehicleSpec\Contracts\VehicleStandardEquipmentItem;
use App\VehicleSpec\Contracts\VehicleTechnicalDataItem;
use App\VehicleSpec\VehicleSpecServiceHelper;
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 Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\VehicleSpecType;
use Mtc\MercuryDataModels\VehicleStandardEquipment;
use Mtc\MercuryDataModels\VehicleTechnicalData;
use Mtc\VehicleLookup\VehicleLookupService;

class FetchVehicleSpecData implements ShouldQueue
{
    use Dispatchable;
    use InteractsWithQueue;
    use Queueable;
    use SerializesModels;

    private static array $map_values = [
        'mpg' => [
            'WLTP - MPG - Comb',
            'EC Combined (mpg)',
            'WLTP - MPG - Comb - TEL',
        ],
        'bhp' => [
            'BHP',
            'Engine Power - BHP',
        ],
        'battery_range' => [
            'WLTP - Pure Electric Range (miles) - Comb'
        ],
        'battery_capacity_kwh' => [
            'Battery Capacity in kWh'
        ],
    ];

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

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

        $specService = (VehicleSpecServiceHelper::initializeForSite())->getSpec($this->vehicle);

        // persist standard spec
        $specService->standard_equipment?->each(function (VehicleStandardEquipmentItem $item) {
            VehicleStandardEquipment::query()->updateOrCreate(
                [
                    'vehicle_id' => $this->vehicle->id,
                    'vehicle_type' => 'vehicle',
                    'description' => $item->description,
                ],
                [
                    'type' => VehicleSpecType::STANDARD_EQUIPMENT,
                    'code' => $item->code,
                    'category' => $item->category_description,
                    'updated_at' => now()
                ]
            );
        });

        // persist technical spec
        $specService->technical_data?->each(function (VehicleTechnicalDataItem $item) {
            VehicleTechnicalData::query()->updateOrCreate([
                'vehicle_id' => $this->vehicle->id,
                'vehicle_type' => 'vehicle',
                'code' => $item->code,
                'description' => $item->description,
                'value' => $item->value,
                'category' => $item->category
            ]);
        });

        $this->checkAdditionalValues($specService);
    }

    private function updateBasicVehicleData()
    {

        try {
            $lookup_vehicle_data = App::make(VehicleLookupService::class)->findByVRM($this->vehicle->vrm_condensed, 0);
            $this->vehicle->update(App::make(VehicleRepository::class)->mapTechnicalData($lookup_vehicle_data));
        } catch (\Throwable $throwable) {
            Log::debug('failed to update vehicle basic details:' . $throwable->getMessage(), $throwable->getTrace());
            // Unable to find vehicle
        }
    }

    private function checkAdditionalValues(VehicleSpecData $specService): void
    {
        $update_values = [];
        foreach (self::$map_values as $attribute => $values) {
            if (empty($this->vehicle->getAttribute($attribute))) {
                $matched_value = $specService->technical_data
                    ?->filter(fn($item) => in_array($item->description, $values))
                    ?->map(fn($item) => $item->value)
                    ->first();

                if (!empty($matched_value) && is_numeric($matched_value)) {
                    $update_values[$attribute] = $matched_value;
                }
            }
        }

        if (!empty($update_values)) {
            $this->vehicle->update($update_values);
        }
    }
}
