<?php

namespace App\Models\Resources;

use App\Models\Auth\User;
use App\Models\Products\Product;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Storage;

class Resource extends Model
{
    use HasFactory;

    protected $table = 'resources';

    protected $fillable = [
        'resource_version_id',
        'title',
        'description',
        'type',
        'url',
        'path',
        'mime',
        'original_filename',
        'size',
        'read_time',
        'is_public',
        'status',
        'sort_order',
        'created_by',
    ];

    protected $casts = [
        'is_public' => 'boolean',
        'size' => 'integer',
        'read_time' => 'integer',
        'sort_order' => 'integer',
    ];

    /* -----------------------------
       Relaciones
    ------------------------------*/

    /**
     * Versión a la que pertenece el recurso
     */
    public function resourceVersion()
    {
        return $this->belongsTo(ResourceVersion::class, 'resource_version_id');
    }

    /**
     * Producto al que pertenece el recurso (a través de resourceVersion)
     */
    public function product()
    {
        return $this->hasOneThrough(Product::class, ResourceVersion::class, 'id', 'id', 'resource_version_id', 'product_id');
    }

    /**
     * Usuario que creó el recurso
     */
    public function creator()
    {
        return $this->belongsTo(User::class, 'created_by');
    }

    /* -----------------------------
       Scopes
    ------------------------------*/

    /**
     * Scope para filtrar recursos publicados
     */
    public function scopePublished($query)
    {
        return $query->where('status', 'published');
    }

    /**
     * Scope para filtrar recursos en borrador
     */
    public function scopeDraft($query)
    {
        return $query->where('status', 'draft');
    }

    /**
     * Scope para filtrar recursos archivados
     */
    public function scopeArchived($query)
    {
        return $query->where('status', 'archived');
    }

    /**
     * Scope para filtrar recursos públicos
     */
    public function scopePublic($query)
    {
        return $query->where('is_public', true);
    }

    /**
     * Scope para filtrar por producto (a través de resourceVersion)
     */
    public function scopeForProduct($query, $product)
    {
        $productId = $product instanceof Product ? $product->id : $product;
        return $query->whereHas('resourceVersion', function ($q) use ($productId) {
            $q->where('product_id', $productId);
        });
    }

    /**
     * Scope para ordenar por sort_order
     */
    /**
     * El orden en que la API sirve los elementos al Moodle del cliente.
     *
     * **Los que no tienen orden van al final**, que es lo que dice el contrato
     * (`api/content-versioning.md`). Hacía falta decirlo explícitamente: un
     * `orderBy('sort_order', 'asc')` a secas pone los NULL **primero** en MySQL y en
     * sqlite, así que un elemento recién creado sin orden se colaba delante de los que
     * alguien había ordenado a mano.
     *
     * Y entre los que empatan, el más nuevo primero.
     */
    public function scopeOrdered($query)
    {
        return $query
            ->orderByRaw('case when sort_order is null then 1 else 0 end')
            ->orderBy('sort_order', 'asc')
            ->orderBy('created_at', 'desc')
            // Desempate: `created_at` tiene precisión de segundo, así que los elementos
            // dados de alta en la misma petición empatan y el orden lo decide la base.
            // Entre empatados se respeta el orden en que se crearon, que es como se
            // escribieron y como se venían viendo.
            ->orderBy('id', 'asc');
    }

    /* -----------------------------
       Accessors
    ------------------------------*/

    /**
     * Obtiene la URL pública del archivo (si type=file y is_public=true)
     */
    public function getFileUrlAttribute(): ?string
    {
        if ($this->type !== 'file' || !$this->is_public || !$this->path) {
            return null;
        }

        return Storage::disk('public')->url($this->path);
    }

    /**
     * Obtiene el tamaño del archivo formateado
     */
    public function getFileSizeHumanAttribute(): ?string
    {
        if (!$this->size) {
            return null;
        }

        $units = ['B', 'KB', 'MB', 'GB'];
        $size = $this->size;
        $unit = 0;

        while ($size >= 1024 && $unit < count($units) - 1) {
            $size /= 1024;
            $unit++;
        }

        return round($size, 2) . ' ' . $units[$unit];
    }
}

