<?php

namespace App\Domain\Website\Models;

use App\Domain\Shared\Traits\BelongsToAcademy;
use App\Domain\Shared\Traits\HasUuid;
use App\Domain\Website\Blocks\BlockRegistry;
use App\Domain\Website\Blocks\BlockType;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;

class WebsiteBlock extends Model
{
    use BelongsToAcademy, HasUuid;

    protected $fillable = [
        'academy_id',
        'website_page_id',
        'parent_id',
        'slot',
        'type',
        'variant',
        'sort_order',
        'is_enabled',
        'data',
        'style',
    ];

    protected $casts = [
        'data' => 'array',
        'style' => 'array',
        'sort_order' => 'integer',
        'is_enabled' => 'boolean',
    ];

    public function page(): BelongsTo
    {
        return $this->belongsTo(WebsitePage::class, 'website_page_id');
    }

    public function parent(): BelongsTo
    {
        return $this->belongsTo(self::class, 'parent_id');
    }

    public function children(): HasMany
    {
        return $this->hasMany(self::class, 'parent_id')->orderBy('sort_order');
    }

    /** Eager-loadable recursive tree. */
    public function childrenRecursive(): HasMany
    {
        return $this->children()->with('childrenRecursive');
    }

    public function scopeEnabled($query)
    {
        return $query->where('is_enabled', true);
    }

    public function scopeOrdered($query)
    {
        return $query->orderBy('sort_order');
    }

    /**
     * The block's definition. Returns null for a type that is no longer
     * registered, so an orphaned row degrades to "skipped" rather than fatal.
     */
    public function definition(): ?BlockType
    {
        return app(BlockRegistry::class)->get($this->type);
    }

    /** Children grouped by slot name, for multi-slot container blocks. */
    public function childrenInSlot(string $slot = 'default')
    {
        return $this->children->where('slot', $slot);
    }

    /**
     * Read a content field, resolving bilingual values for the active locale.
     * Falls back to the other locale rather than rendering an empty element.
     */
    public function get(string $key, mixed $default = null, ?string $locale = null): mixed
    {
        $value = data_get($this->data, $key, $default);

        if (! is_array($value) || ! array_key_exists('ar', $value)) {
            return $value;
        }

        $locale ??= app()->getLocale();
        $primary = $locale === 'ar' ? 'ar' : 'en';
        $fallback = $primary === 'ar' ? 'en' : 'ar';

        return filled($value[$primary] ?? null)
            ? $value[$primary]
            : ($value[$fallback] ?? $default);
    }

    /** Read a presentation setting from the style payload. */
    public function style(string $key, mixed $default = null): mixed
    {
        return data_get($this->style, $key, $default);
    }

    public function isRenderable(): bool
    {
        return $this->is_enabled && $this->definition() !== null;
    }
}
