<?php

namespace App\Services;

use App\Events\LoadDealershipDataFields;
use Illuminate\Support\Collection;
use Mtc\MercuryDataModels\Dealership;
use Mtc\MercuryDataModels\VehicleAttribute;
use Mtc\MercuryDataModels\VehicleAttributeValue;

class DealershipAdditionalFieldsRegistry
{
    private const DEALERSHIP_MORPH = 'dealership';

    private ?Collection $fields = null;

    public function all(): Collection
    {
        if ($this->fields === null) {
            $this->fields = collect(event(new LoadDealershipDataFields()))
                ->filter()
                ->mapWithKeys(fn ($field) => $field)
                ->map(function ($field, $key) {
                    $field['slug'] = $key;
                    return $field;
                });
        }

        return $this->fields;
    }

    public function slugs(): Collection
    {
        return $this->all()->keys();
    }

    public function getField(string $slug): ?array
    {
        return $this->all()->get($slug);
    }

    public function ensureAttribute(string $slug, array $field): VehicleAttribute
    {
        return VehicleAttribute::query()->firstOrCreate(
            [
                'slug' => $slug,
                'model' => self::DEALERSHIP_MORPH,
            ],
            [
                'name' => $field['label'] ?? $slug,
                'type' => $field['type'] ?? 'text',
                'count' => 1,
                'validation' => [],
                'data' => [],
            ]
        );
    }

    public function saveValue(Dealership $dealership, string $slug, $value): ?VehicleAttributeValue
    {
        $field = $this->getField($slug);
        if ($field === null) {
            return null;
        }

        $type = $field['type'] ?? 'text';
        $attribute = $this->ensureAttribute($slug, $field);
        $column = $this->valueColumn($type);
        $storeValue = $this->normaliseValue($type, $value);

        $payload = [
            'value' => null,
            'value_text' => null,
            'value_float' => null,
            'value_integer' => null,
            'value_datetime' => null,
        ];
        $payload[$column] = $storeValue;
        $payload['type'] = $this->storedType($type);
        $payload['slug'] = $slug;
        $payload['index'] = 0;

        return $dealership->attributeValues()->updateOrCreate(
            [
                'attribute_id' => $attribute->id,
                'index' => 0,
            ],
            $payload
        );
    }

    private function storedType(string $type): string
    {
        return match ($type) {
            'checkbox' => 'boolean',
            'date' => 'datetime',
            'decimal' => 'number',
            default => $type,
        };
    }

    public function valueColumn(string $type): string
    {
        return match ($type) {
            'number', 'decimal' => 'value_float',
            'integer', 'boolean', 'checkbox' => 'value_integer',
            'datetime', 'date' => 'value_datetime',
            'text', 'textarea', 'editor', 'select', 'password' => 'value_text',
            default => 'value',
        };
    }

    private function normaliseValue(string $type, $value)
    {
        if ($value === null || $value === '') {
            return null;
        }

        return match ($type) {
            'checkbox', 'boolean' => (int) filter_var($value, FILTER_VALIDATE_BOOLEAN),
            'integer' => (int) $value,
            'number', 'decimal' => (float) $value,
            default => is_scalar($value) ? (string) $value : json_encode($value),
        };
    }
}
