<?php

namespace App\Traits;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use Mtc\MercuryDataModels\Dealership;
use Mtc\MercuryDataModels\NewCar;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\VehicleAttribute;
use Mtc\MercuryDataModels\VehicleAttributeValue;
use Mtc\MercuryDataModels\VehicleOffer;
use Mtc\MercuryDataModels\VehicleTrim;

trait EnsuresVehicleAttribute
{
    /**
     * ensure that a VehicleAttribute exists and return it.
     *
     * @param string $name
     * @param string $type
     * @param string|null $slug
     * @return Model
     */
    public function getVehicleAttribute(string $name, string $type, ?string $slug = null): Model
    {
        if (!$this->hasValidAttributeType($type)) {
            throw new \Exception($type . ' is not a supported attribute type');
        }
        return VehicleAttribute::query()
            ->firstOrCreate(
                [
                    'slug' => $slug ?? Str::slug($name, '_'),
                    'model' => 'vehicle',
                ],
                [
                    'name' => $name,
                    'type' => $type,
                    'count' => 1,
                    'validation' => [],
                    'data' => []
                ]
            );
    }

    public function attributeValueColumn(array $attribute): string
    {
        return match ($attribute['type']) {
            'text', 'textarea', 'editor', 'select' => 'value_text',
            'number' => 'value_float',
            'integer', 'boolean' => 'value_integer',
            'datetime' => 'value_datetime',
            default => 'value',
        };
    }

    private function setVehicleAttributes(array $attributes, Vehicle $vehicle): void
    {
        $data = collect($attributes)
            ->reject(fn ($value, $attribute) => $this->vehicleAttributes[$attribute]['count'] > 1)
            ->map(function ($value, $attribute) use ($vehicle) {
                $column = $this->attributeValueColumn($this->vehicleAttributes[$attribute]);
                return [
                    'attribute_id' => $this->vehicleAttributes[$attribute]['id'],
                    'owner_id' => $vehicle->id,
                    'owner_type' => 'vehicle',
                    'index' => 0,
                    'type' => $this->vehicleAttributes[$attribute]['type'],
                    'slug' => $this->vehicleAttributes[$attribute]['slug'],
                    'value_text' => $column === 'value_text' ? $value : null,
                    'value_float' => $column === 'value_float' ? $value : null,
                    'value_integer' => $column === 'value_integer' ? $value : null,
                    'value_datetime' => $column === 'value_datetime' ? $value : null,
                    'value' => $column === 'value_text' && mb_strlen((string) $value) <= 250
                        ? (string) $value
                        : null,
                ];
            })->toArray();

        VehicleAttributeValue::query()->upsert($data, ['attribute_id', 'owner_id', 'owner_type', 'index']);

        collect($attributes)
            ->filter(fn ($value, $attribute) => $this->vehicleAttributes[$attribute]['count'] > 1)
            ->each(fn ($value, $attribute) => $this->syncVehicleAttribute($vehicle, $attribute, $value));
    }

    private function syncVehicleAttribute(Vehicle $vehicle, string $name, $value): void
    {
        VehicleAttributeValue::query()->updateOrCreate(
            [
                'attribute_id' => $this->vehicleAttributes[$name]['id'],
                'owner_id' => $vehicle->id,
                'owner_type' => 'vehicle',
            ],
            [
                'type' => $this->vehicleAttributes[$name]['type'],
                'slug' => $this->vehicleAttributes[$name]['slug'],
                $this->attributeValueColumn($this->vehicleAttributes[$name]) => $value
            ]
        );
    }

    private function hasValidAttributeType(string $type): bool
    {
        return in_array($type, array_keys(config("pages.field_types")));
    }

    private function saveAttributeValue(
        Vehicle|VehicleOffer|NewCar|Dealership|VehicleTrim $vehicle,
        array $attribute
    ): void {
        $values = collect($attribute['value'] ?? []);
        $allIds = $values->pluck('id')->filter(fn ($id) => is_numeric($id))->values();
        $column = $this->attributeValueColumn($attribute);

        // Delete attribute values removed from the list entirely
        $deleteQuery = $vehicle->attributeValues()->where('attribute_id', $attribute['id']);
        if ($allIds->isNotEmpty()) {
            $deleteQuery->whereNotIn('id', $allIds);
        }
        $deleteQuery->delete();

        $values
            ->values()
            ->each(function ($value, $index) use ($vehicle, $attribute, $column) {
                if (empty($value['value'])) {
                    // Value cleared (e.g. image removed) — delete the existing record
                    if (is_numeric($value['id'] ?? null)) {
                        $vehicle->attributeValues()->where('id', $value['id'])->delete();
                    }
                    return;
                }

                $storeValue = $value['value'];
                if (is_array($storeValue)) {
                    $storeValue = $storeValue['name'] ?? $storeValue['id'] ?? json_encode($storeValue);
                }

                $vehicle->attributeValues()->updateOrCreate(['id' => $value['id']], [
                    'attribute_id' => $attribute['id'],
                    'slug' => $attribute['slug'],
                    'type' => $attribute['type'],
                    $column => $storeValue,
                    'order' => $index,
                    'index' => $index,
                ]);
            });
    }
}
