<?php

namespace App\VehicleSpec\Jobs;

use App\TaxonomyMap;
use App\Traits\MapsTaxonomies;
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;
    use MapsTaxonomies;

    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'
        ],
        'battery_usable_capacity_kwh' => [
            'Usable Battery Capacity',
        ],
        'battery_charge_time' => [
            'Battery Charging Scenario 1 - Charge Time (Mins)'
        ],
        'battery_quick_charge_time' => [
            'Battery Charging Scenario 4 - Charge Time (Mins)',
            'Battery Charging Scenario 3 - Charge Time (Mins)',
        ],
        'battery_quick_charge_level' => [
            'Battery Charging Scenario 4 - Percentage Change',
            'Battery Charging Scenario 3 - Percentage Change',
        ],
        'plug_type' => [
            'Coupler/Connector Type',
        ],
        'rapid_charge_plug_type' => [
            'Coupler/Connector Type',
        ],
    ];

    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;
        }

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

        if ($this->update_basics) {
            $this->updateBasicVehicleData();
        }

        // persist standard spec
        if (isset($specService->standard_equipment)) {
            $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' => strlen($item->category_description) < 190
                            ? $item->category_description
                            : null,
                        'updated_at' => now()
                    ]
                );
            });
        }

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

        $this->checkAdditionalValues($specService);
    }

    private function updateBasicVehicleData(): void
    {
        try {
            if (empty($this->vehicle->vrm_condensed)) {
                return;
            }
            $lookup_vehicle_data = App::make(VehicleLookupService::class)->findByVRM($this->vehicle->vrm_condensed, 0);
            if ($lookup_vehicle_data->make || $lookup_vehicle_data->model) {
                $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
    {
        if (!empty($specService->basics['model']) && empty($this->vehicle->model_id)) {
            $model_id = $this->getMappedTaxonomy(
                TaxonomyMap::MODEL,
                $specService->basics['model'],
                [],
                $this->vehicle->make_id
            );
            if ($model_id) {
                $this->vehicle->update(['model_id' => $model_id]);
            }
        }
        $update_values = [];
        foreach (self::$map_values as $attribute => $values) {
            if (empty($this->vehicle->getAttribute($attribute))) {
                if (isset($specService->technical_data)) {
                    $matched_value = $specService->technical_data
                        ?->filter(fn ($item) => in_array($item->description, $values))
                        ?->sortBy(fn ($item) => array_search($item->description, self::$map_values[$attribute]))
                        ?->reject(fn ($item) => $item->value === 'Not Available')
                        ?->map(fn ($item) => $item->value)
                        ->first();
                }

                if (!empty($matched_value)) {
                    $update_values[$attribute] = $this->sanitiseAdditionalValue($attribute, $matched_value);
                }
            }
        }

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

    private function sanitiseAdditionalValue(string $attribute, ?string $matched_value): ?string
    {
        if (
            $attribute === 'battery_quick_charge_level'
            && preg_match("/[0-9]{1,2}-([0-9]{1,3})/", (string) $matched_value, $matches)
        ) {
            return $matches[1];
        }

        if (in_array($attribute, ['plug_type', 'rapid_charge_plug_type'])) {
            return $matched_value;
        }

        return is_numeric($matched_value) ? $matched_value : null;
    }

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