<?php

namespace Functional\Exercises\Models;

use Functional\Exercises\Database\Factories\ExerciseFactory;
use Illuminate\Database\Eloquent\Attributes\UseFactory;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

/**
 * Catalogue d'exercices (lecture seule, alimenté par l'import du dataset).
 *
 * @property string $external_id
 * @property string $name
 * @property array|null $secondary_muscles
 * @property array|null $instructions
 */
#[UseFactory(ExerciseFactory::class)]
class Exercise extends Model
{
    use HasFactory;

    protected $fillable = [
        'external_id', 'name', 'name_i18n', 'slug', 'category', 'body_part', 'equipment',
        'target', 'muscle_group', 'secondary_muscles', 'instructions',
        'image_path', 'gif_path', 'attribution',
    ];

    protected $casts = [
        'secondary_muscles' => 'array',
        'instructions' => 'array',
        'name_i18n' => 'array',
    ];

    protected $appends = ['image_url', 'gif_url'];

    /** URL publique du thumbnail (média servi depuis RustFS/S3). */
    public function imageUrl(): ?string
    {
        return $this->mediaUrl($this->image_path);
    }

    public function gifUrl(): ?string
    {
        return $this->mediaUrl($this->gif_path);
    }

    public function getImageUrlAttribute(): ?string
    {
        return $this->imageUrl();
    }

    public function getGifUrlAttribute(): ?string
    {
        return $this->gifUrl();
    }

    private function mediaUrl(?string $path): ?string
    {
        if (! $path) {
            return null;
        }

        return rtrim((string) config('exercises.media_base_url'), '/') . '/' . ltrim($path, '/');
    }

    /**
     * Instructions dans la locale demandée, avec repli.
     * pt-BR n'existe pas dans le dataset → repli en/fr.
     */
    public function instructionsFor(string $locale): array
    {
        $data = $this->instructions ?? [];
        $chain = [$locale, substr($locale, 0, 2), 'en', 'fr'];

        foreach ($chain as $lang) {
            if (! empty($data[$lang])) {
                return (array) $data[$lang];
            }
        }

        return [];
    }

    /** Nom localisé (name_i18n) avec repli sur le nom anglais canonique. */
    public function localizedName(string $locale): string
    {
        $map = $this->name_i18n ?? [];

        return $map[$locale] ?? $map[substr($locale, 0, 2)] ?? $this->name;
    }

    /** Traduit un terme du vocabulaire contrôlé (zone/équipement/muscle) selon la locale. Repli = anglais. */
    public static function localizeTerm(?string $value, string $locale): ?string
    {
        if ($value === null || $value === '') {
            return $value;
        }

        $map = config('exercise_i18n.' . $locale, []);

        return $map[mb_strtolower($value)] ?? $value;
    }

    /** @param array<int,string>|null $values @return array<int,string> */
    public static function localizeTerms(?array $values, string $locale): array
    {
        return array_values(array_map(fn ($v) => self::localizeTerm($v, $locale), $values ?? []));
    }

    /** Recherche plein-texte simple (nom / muscle cible / équipement). */
    public function scopeSearch(Builder $query, ?string $term): Builder
    {
        if (! $term) {
            return $query;
        }

        $like = '%' . str_replace('%', '\%', $term) . '%';

        return $query->where(function (Builder $q) use ($like) {
            $q->where('name', 'like', $like)
                ->orWhere('name_i18n', 'like', $like) // noms traduits (JSON stocké en texte)
                ->orWhere('target', 'like', $like)
                ->orWhere('equipment', 'like', $like)
                ->orWhere('body_part', 'like', $like);
        });
    }
}
