<?php

namespace App\Traits;

use App\Master\Models\BodyStyleType;
use App\Master\Models\DrivetrainType;
use App\Master\Models\FuelType;
use App\Master\Models\TransmissionType;
use App\Master\Models\VehicleMake;
use App\Master\Models\VehicleModel;
use App\VehicleSpec\Services\CapIdCacheBackfillService;
use Illuminate\Database\Eloquent\Relations\Relation;
use Mtc\MercuryDataModels\CapIdCache;
use Mtc\MercuryDataModels\Vehicle;

trait ResolvesTaxonomyMapping
{
    public function resolveTaxonomyMapping($mapables, $tenant, $map): void
    {
        tenancy()->initialize($tenant);

        foreach ($mapables as $mappable) {
            $modelClass = Relation::getMorphedModel($mappable->mappable_type);
            $model = $modelClass::find($mappable->mappable_id);

            if ($model) {
                $originalMakeId = $model->make_id;
                $originalModelId = $model->model_id;

                switch ($map->taxonomy_type) {
                    case 'make':
                    case 'master-make':
                        $model->make_id = $map->taxonomy_id;
                        break;
                    case 'model':
                    case 'master-model':
                        $model->model_id = $map->taxonomy_id;
                        break;
                    case 'body_type':
                    case 'master-body_type':
                    case 'body_style':
                    case 'master-body_style':
                        $model->fill(['body_style_id' => $map->taxonomy_id]);
                        break;
                    case 'drivetrain':
                    case 'master-drivetrain':
                        $model->fill(['drivetrain_id' => $map->taxonomy_id]);
                        break;
                    case 'fuel_type':
                    case 'master-fuel_type':
                        $model->fill(['fuel_type_id' => $map->taxonomy_id]);
                        if (method_exists($model, 'fuelTypes')) {
                            $model->fuelTypes()->syncWithoutDetaching([$map->taxonomy_id]);
                        }
                        break;
                    case 'transmission':
                    case 'master-transmission':
                        $model->fill(['transmission_id' => $map->taxonomy_id]);
                        break;
                    default:
                        throw new \Exception("Unknown taxonomy type: {$map->taxonomy_type}");
                }

                $model->save();

                if ($model instanceof Vehicle && $model->derivative) {
                    $this->updateCapIdCache($map, $model, $originalMakeId, $originalModelId);
                }

                $mappable->delete();
            }
        }
    }

    private function updateCapIdCache($map, Vehicle $vehicle, $originalMakeId, $originalModelId): void
    {
        $cacheColumn = match ($map->taxonomy_type) {
            'make', 'master-make' => 'cap_matched_make_id',
            'model', 'master-model' => 'cap_matched_model_id',
            'fuel_type', 'master-fuel_type' => 'cap_matched_fuel_type_id',
            'body_style', 'master-body_style', 'body_type', 'master-body_type' => 'cap_matched_body_style_id',
            'transmission', 'master-transmission' => 'cap_matched_transmission_id',
            default => null,
        };

        if (!$cacheColumn) {
            return;
        }

        $query = CapIdCache::query()
            ->where('derivative', $vehicle->derivative)
            ->where(fn ($q) => $originalMakeId ? $q->where('make_id', $originalMakeId) : $q->whereNull('make_id'))
            ->where(fn ($q) => $originalModelId ? $q->where('model_id', $originalModelId) : $q->whereNull('model_id'))
            ->whereNull($cacheColumn);

        // The bulk update below bypasses Eloquent events, so the CapIdCacheObserver
        // won't fire. When we are setting the matched model, capture the affected
        // cap_ids up front and backfill sibling vehicles that still have no model_id.
        $capIdsToBackfill = $cacheColumn === 'cap_matched_model_id'
            ? (clone $query)->pluck('cap_id')->filter()->unique()
            : collect();

        $query->update([$cacheColumn => $map->taxonomy_id]);

        if ($capIdsToBackfill->isNotEmpty()) {
            $backfill = app(CapIdCacheBackfillService::class);

            foreach ($capIdsToBackfill as $capId) {
                $backfill->backfillForCapId((string) $capId);
            }
        }
    }

    /**
     * @param mixed $activeFilter
     * @param $taxonomies
     * @return mixed
     */
    public function getFilters(mixed $activeFilter, $taxonomies)
    {
        if (empty($activeFilter) || stripos((string) $activeFilter, 'make') !== false) {
            $taxonomies['master-make'] = VehicleMake::query()->select(['id', 'name'])->get();
        }
        if (empty($activeFilter) || stripos((string) $activeFilter, 'body_style') !== false) {
            $taxonomies['master-body_style'] = BodyStyleType::query()->select(['id', 'name'])->get();
        }
        if (empty($activeFilter) || stripos((string) $activeFilter, 'fuel_type') !== false) {
            $taxonomies['master-fuel_type'] = FuelType::query()->select(['id', 'name'])->get();
        }
        if (empty($activeFilter) || stripos((string) $activeFilter, 'transmission') !== false) {
            $taxonomies['master-transmission'] = TransmissionType::query()->select(['id', 'name'])->get();
        }
        if (empty($activeFilter) || stripos((string) $activeFilter, 'drivetrain') !== false) {
            $taxonomies['master-drivetrain'] = DrivetrainType::query()->select(['id', 'name'])->get();
        }
        if (empty($activeFilter) || stripos((string) $activeFilter, 'model') !== false) {
            $taxonomies['master-model'] = VehicleModel::query()
                ->with('make')
                ->get()
                ->map(fn ($model) => [
                    'id' => $model->id,
                    'name' => $model->name . ' (' . ($model->make?->name ?? 'Unknown Make') . ')',
                ]);
        }
        return $taxonomies;
    }
}
