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

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' => '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' ? $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 $vehicle, array $attribute): void
    {
        $vehicle->attributeValues()
            ->where('attribute_id', $attribute['id'])
            ->whereNotIn('id', collect($attribute['value'])->filter(fn($value) => !empty($value['value']))->pluck('id'))
            ->delete();
        collect($attribute['value'] ?? [])
            ->filter(fn($value) => !empty($value['value']))
            ->values()
            ->each(fn($value, $index) => $vehicle->attributeValues()->updateOrCreate(['id' => $value['id']], [
                'attribute_id' => $attribute['id'],
                'slug' => $attribute['slug'],
                'type' => $attribute['type'],
                $this->attributeValueColumn($attribute) => $value['value'],
                'order' => $index,
                'index' => $index,
            ]));
    }
}
