<?php

namespace App\Models\Auth;

use App\Models\Clients\Client;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable
{
    use HasFactory, Notifiable, HasRoles, SoftDeletes;

    /**
     * **`last_login_at` y `last_login_ip_address` estaban aquí y no existen.**
     *
     * La tabla `users` tiene `id, name, email, email_verified_at, password,
     * remember_token` y los timestamps. Nada más. Las dos claves eran una mina:
     * cualquier `create()` o `update()` que llegara a incluirlas —un formulario
     * nuevo, un import, un seeder— habría petado con *unknown column*, y no en el
     * momento de escribirlo sino el día que alguien las pasara.
     *
     * `last_login_at` **sí existe ahora** —migración `2026_09_07_090000`— y sigue fuera de
     * esta lista a propósito: no se edita en ningún formulario, la escribe solo el listener
     * del evento `Login` en `AppServiceProvider`. Ver `getLastAccessAtAttribute()`.
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    protected $hidden = [
        'password',
        'remember_token',
    ];

    protected function casts(): array
    {
        return [
            'email_verified_at' => 'datetime',
            'last_login_at' => 'datetime',
            'password' => 'hashed',
        ];
    }

    // Relación con clientes
    public function clients()
    {
        return $this->belongsToMany(
            Client::class,
            'client_user',
            'user_id',
            'client_id'
        );
    }

    // AdminLTE description
    public function adminlte_desc(): string
    {
        return $this->roles->pluck('name')->implode(' - ');
    }

    /**
     * ¿Puede borrarse este usuario?
     */
    public function is_deletable(): bool
    {
        // Si el usuario tiene rol Admin → NO se puede borrar
        return !$this->hasRole('Admin');
    }

    /**
     * ¿Puede editarse este usuario?
     * No puedes editar otro Admin si tú no eres Admin.
     */
    public function is_editable(): bool
    {
        $current = auth()->user();

        if (!$current) {
            return false;
        }

        // Si yo soy Admin → puedo editar a cualquiera
        if ($current->hasRole('Admin')) {
            return true;
        }

        // Si el usuario que intento editar es Admin → NO
        return !$this->hasRole('Admin');
    }

    /**
     * Desde cuándo se guarda el último acceso.
     *
     * La fecha en que se creó `users.last_login_at`. **Hace falta para no mentir**: un
     * usuario sin fecha creado *antes* de esto no es que no haya entrado nunca, es que
     * nadie lo apuntaba. Uno creado *después* sí es un alta sin estrenar, y son dos cosas
     * que se atienden distinto —a una se le manda otra vez la bienvenida, a la otra se le
     * pregunta si sigue en el equipo—.
     *
     * Se cura sola: en cuanto cada uno entre una vez, deja de haber NULLs antiguos y esta
     * constante no vuelve a decidir nada.
     */
    public const REGISTRO_DE_ACCESOS_DESDE = '2026-09-07';

    /**
     * Último acceso: **lo más reciente de la columna y de la sesión viva**.
     *
     * Son dos fuentes y ninguna sobra:
     *
     * - `last_login_at` es **permanente** y contesta «¿cuándo entró por última vez?».
     *   La escribe el listener del evento `Login`.
     * - `last_activity_at` **no es una columna**: es un alias que tiene que traer la
     *   consulta, con un `MAX(last_activity)` sobre `sessions` —lo hace `Users\Index`—.
     *   Contesta «¿está dentro **ahora**?» y es más fino, porque se mueve con cada
     *   petición; pero desaparece a los `SESSION_LIFETIME` minutos, y con las sesiones
     *   en Redis o en cookie no existe siquiera.
     *
     * Así que se devuelve el máximo: alguien que lleva ocho horas trabajando sin volver
     * a hacer login tiene el acceso «hace un minuto», que es la verdad, y no «esta
     * mañana». Y si el `addSelect` no está, la respuesta sigue siendo correcta con solo
     * la columna.
     */
    public function getLastAccessAtAttribute(): ?Carbon
    {
        $sesion = $this->last_activity_at
            ? Carbon::createFromTimestamp($this->last_activity_at)
            : null;

        $login = $this->last_login_at;

        if ($sesion === null) {
            return $login;
        }

        return $login === null || $sesion->greaterThan($login) ? $sesion : $login;
    }

    /**
     * ¿Se sabe algo del acceso de este usuario?
     *
     * `false` significa **«no lo sabemos»**, no «no ha entrado»: la cuenta es anterior a
     * que se empezara a guardar el dato. Ver `REGISTRO_DE_ACCESOS_DESDE`.
     */
    public function tieneRegistroDeAcceso(): bool
    {
        if ($this->last_access_at !== null) {
            return true;
        }

        return $this->created_at !== null
            && $this->created_at->greaterThanOrEqualTo(
                Carbon::parse(self::REGISTRO_DE_ACCESOS_DESDE)->startOfDay()
            );
    }
}

