<?php

namespace App\VehicleSpec\Services;

use Mtc\MercuryDataModels\CapIdCache;
use Mtc\MercuryDataModels\Vehicle;

class CapIdCacheBackfillService
{
    /**
     * Backfill every vehicle that has the given cap_id but no model_id, using the
     * cap_id_cache. Returns the number of vehicles backfilled.
     */
    public function backfillForCapId(string $capId): int
    {
        if ($capId === '') {
            return 0;
        }

        $backfilled = 0;

        Vehicle::query()
            ->where('cap_id', $capId)
            ->whereNull('model_id')
            ->chunkById(200, function ($vehicles) use (&$backfilled) {
                foreach ($vehicles as $vehicle) {
                    if ($this->backfillVehicle($vehicle)) {
                        $backfilled++;
                    }
                }
            });

        return $backfilled;
    }

    /**
     * Backfill a single vehicle's model_id (and missing matched taxonomy) from the
     * best cap_id_cache match. Returns true when a match was found and applied.
     */
    public function backfillVehicle(Vehicle $vehicle, bool $dryRun = false): bool
    {
        $match = $this->findCacheMatch($vehicle);

        if (!$match) {
            return false;
        }

        if (!$dryRun) {
            $vehicle->update($this->buildUpdates($vehicle, $match));
        }

        return true;
    }

    /**
     * Find the cap_id_cache row that resolves this vehicle's cap_id to a model_id.
     * Prefers a row matching the vehicle's derivative, since a single cap_id can
     * span multiple cache rows (unique key is make_id + model_id + derivative).
     */
    public function findCacheMatch(Vehicle $vehicle): ?CapIdCache
    {
        if (empty($vehicle->cap_id)) {
            return null;
        }

        $query = CapIdCache::query()
            ->where('cap_id', $vehicle->cap_id)
            ->whereNotNull('cap_matched_model_id');

        if (!empty($vehicle->derivative)) {
            $match = (clone $query)->where('derivative', $vehicle->derivative)->first();

            if ($match) {
                return $match;
            }
        }

        return $query->first();
    }

    /**
     * model_id is the target of the backfill; the remaining matched taxonomy is
     * only filled where the vehicle is currently missing it, to avoid clobbering
     * values already set on the vehicle.
     */
    private function buildUpdates(Vehicle $vehicle, CapIdCache $match): array
    {
        $updates = ['model_id' => $match->cap_matched_model_id];

        $optional = [
            'make_id' => $match->cap_matched_make_id,
            'fuel_type_id' => $match->cap_matched_fuel_type_id,
            'body_style_id' => $match->cap_matched_body_style_id,
            'transmission_id' => $match->cap_matched_transmission_id,
        ];

        foreach ($optional as $column => $value) {
            if (empty($vehicle->{$column}) && !empty($value)) {
                $updates[$column] = $value;
            }
        }

        return $updates;
    }
}
