<?php

declare(strict_types=1);

namespace App\Models;

use App\Support\DberpDictionaryItemMaintenance;
use App\Support\DictionaryItemUsageChecker;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Validation\ValidationException;

class DberpDictionaryItem extends Model
{
    protected $table = 'dberp_dictionary_items';

    /**
     * @var list<string>
     */
    protected $fillable = [
        'type_id',
        'code',
        'label',
        'value',
        'is_enabled',
        'description',
        'is_system_preset',
        'is_delete_locked',
        'sort_order',
    ];

    protected function casts(): array
    {
        return [
            'sort_order' => 'integer',
            'is_enabled' => 'boolean',
            'is_system_preset' => 'boolean',
            'is_delete_locked' => 'boolean',
        ];
    }

    public function type(): BelongsTo
    {
        return $this->belongsTo(DberpDictionaryType::class, 'type_id');
    }

    protected static function booted(): void
    {
        static::creating(function (DberpDictionaryItem $item): void {
            $typeCode = $item->resolveParentTypeCode();

            if (DberpDictionaryItemMaintenance::isSystemFixedForTypeCode($typeCode)) {
                throw ValidationException::withMessages([
                    'code' => [__('dberp.dictionary_item_control.system_fixed_create_forbidden')],
                ]);
            }
        });

        static::updating(function (DberpDictionaryItem $item): void {
            if (! $item->isDirty('code')) {
                return;
            }

            $typeCode = $item->resolveParentTypeCode();

            if (DberpDictionaryItemMaintenance::isSystemFixedForTypeCode($typeCode)) {
                throw ValidationException::withMessages([
                    'code' => [__('dberp.dictionary_item_control.system_fixed_code_immutable')],
                ]);
            }

            throw ValidationException::withMessages([
                'code' => [__('dberp.dictionary_item_control.item_code_immutable_after_create')],
            ]);
        });

        static::deleting(function (DberpDictionaryItem $item): void {
            $reasons = app(DictionaryItemUsageChecker::class)->usageReasons($item);

            if ($reasons === []) {
                return;
            }

            throw ValidationException::withMessages([
                'id' => [implode(' ', $reasons)],
            ]);
        });
    }

    public function resolveTypeCode(): ?string
    {
        return $this->resolveParentTypeCode();
    }

    private function resolveParentTypeCode(): ?string
    {
        if ($this->relationLoaded('type') && $this->type instanceof DberpDictionaryType) {
            return $this->type->code;
        }

        if ($this->type_id === null) {
            return null;
        }

        return DberpDictionaryType::query()->whereKey($this->type_id)->value('code');
    }
}
