<?php

namespace App\Models;

use Database\Factories\UserFactory;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\Hidden;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Laravel\Fortify\TwoFactorAuthenticatable;
use OwenIt\Auditing\Auditable as AuditableTrait;
use OwenIt\Auditing\Contracts\Auditable as AuditableContract;

#[Fillable([
    'document',
    'email',
    'name',
    'paternal_surname',
    'maternal_surname',
    'phone',
    'avatar_path',
    'password',
    'status',
])]
#[Hidden(['password', 'two_factor_secret', 'two_factor_recovery_codes', 'remember_token'])]
class User extends Authenticatable implements AuditableContract
{
    /** @use HasFactory<UserFactory> */
    use AuditableTrait;

    use HasFactory, Notifiable, TwoFactorAuthenticatable;

    /**
     * @var list<string>
     */
    protected $auditExclude = [
        'password',
        'remember_token',
        'two_factor_secret',
        'two_factor_recovery_codes',
        'two_factor_confirmed_at',
    ];

    /**
     * Get the attributes that should be cast.
     *
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'password' => 'hashed',
        ];
    }

    /**
     * Get the user's initials
     */
    public function initials(): string
    {
        $first = Str::substr((string) $this->name, 0, 1);
        $second = Str::substr((string) $this->paternal_surname, 0, 1);

        $combined = Str::upper($first.$second);

        return $combined !== '' ? $combined : Str::upper(Str::substr((string) $this->name, 0, 2));
    }

    public function fullName(): string
    {
        return trim("{$this->name} {$this->paternal_surname} {$this->maternal_surname}");
    }

    /**
     * URL pública de la foto de perfil (disco public + enlace storage), o null.
     */
    public function avatarPublicUrl(): ?string
    {
        $path = $this->avatar_path;
        if ($path === null || $path === '') {
            return null;
        }

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

    public function isAdministrator(): bool
    {
        return $this->hasRole(Role::ADMINISTRATOR_NAME);
    }

    public function isCoordinator(): bool
    {
        return $this->hasRole(Role::COORDINATOR_NAME);
    }

    /**
     * Administrador o Coordinador: módulo Operaciones (proyectos, sitios, tipos de trabajo, trabajos).
     */
    public function canAccessOperations(): bool
    {
        return $this->isAdministrator() || $this->isCoordinator();
    }

    public function isTechnician(): bool
    {
        return $this->hasRole(Role::TECHNICIAN_NAME);
    }

    public function isNoc(): bool
    {
        return $this->hasRole(Role::NOC_NAME);
    }

    /**
     * Gestión del catálogo de trabajos (listado, alta, edición completa).
     */
    public function canManageWorksCatalog(): bool
    {
        return $this->isAdministrator() || $this->isCoordinator();
    }

    public function hasRole(string $roleName): bool
    {
        return $this->roles()
            ->where('roles.name', $roleName)
            ->where('roles.status', true)
            ->exists();
    }

    /** @return HasMany<Work, User> */
    public function worksAsTechnician(): HasMany
    {
        return $this->hasMany(Work::class, 'technician_id');
    }

    /** @return HasMany<WorkAssignment, User> */
    public function technicianAssignments(): HasMany
    {
        return $this->hasMany(WorkAssignment::class, 'technician_id');
    }

    public function roles(): BelongsToMany
    {
        return $this->belongsToMany(Role::class, 'role_user');
    }

    /**
     * @param  Builder<User>  $query
     * @return Builder<User>
     */
    public function scopeWithRoleName(Builder $query, string $roleName): Builder
    {
        return $query->whereHas('roles', fn ($q) => $q->where('name', $roleName));
    }
}
