<?php

namespace App\Models;

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    /** @use HasFactory<\Database\Factories\UserFactory> */
    use HasApiTokens, HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var list<string>
     */
    protected $fillable = [
        'name',
        'email',
        'phone',
        'job_title',
        'manager_id',
        'organization_company_id',
        'access_group_id',
        'birth_date',
        'permissions',
        'role',
        'locale',
        'profile_photo_path',
        'profile_photo_focus_x',
        'profile_photo_focus_y',
        'profile_photo_zoom',
        'sidebar_collapsed',
        'right_rail_collapsed',
        'appearance_settings',
        'start_page',
        'background_image_path',
        'preferred_task_view',
        'preferred_deal_view',
        'preferred_project_view',
        'password',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var list<string>
     */
    protected $hidden = [
        'password',
        'remember_token',
        'two_factor_secret',
        'two_factor_recovery_codes',
    ];

    /**
     * Get the attributes that should be cast.
     *
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'email_verified_at' => 'datetime',
            'last_seen_at' => 'datetime',
            'manager_id' => 'integer',
            'organization_company_id' => 'integer',
            'access_group_id' => 'integer',
            'birth_date' => 'date',
            'permissions' => 'array',
            'two_factor_secret' => 'encrypted',
            'two_factor_recovery_codes' => 'encrypted:array',
            'two_factor_confirmed_at' => 'datetime',
            'profile_photo_focus_x' => 'integer',
            'profile_photo_focus_y' => 'integer',
            'profile_photo_zoom' => 'decimal:2',
            'task_kanban_preset' => 'array',
            'right_rail_viewed_notifications' => 'array',
            'right_rail_collapsed' => 'boolean',
            'appearance_settings' => 'array',
            'preferred_task_view' => 'string',
            'preferred_deal_view' => 'string',
            'preferred_project_view' => 'string',
            'password' => 'hashed',
        ];
    }

    public function companies(): HasMany
    {
        return $this->hasMany(Company::class, 'owner_id');
    }

    public function contacts(): HasMany
    {
        return $this->hasMany(Contact::class, 'owner_id');
    }

    public function deals(): HasMany
    {
        return $this->hasMany(Deal::class, 'owner_id');
    }

    public function products(): HasMany
    {
        return $this->hasMany(Product::class, 'owner_id');
    }

    public function warehouses(): HasMany
    {
        return $this->hasMany(Warehouse::class, 'manager_id');
    }

    public function warehouseAddresses(): HasMany
    {
        return $this->hasMany(WarehouseAddress::class, 'created_by');
    }

    public function ownedProjects(): HasMany
    {
        return $this->hasMany(Project::class, 'owner_id');
    }

    public function managedProjects(): HasMany
    {
        return $this->hasMany(Project::class, 'manager_id');
    }

    public function projectMemberships(): BelongsToMany
    {
        return $this->belongsToMany(Project::class)
            ->withPivot(['role', 'joined_at'])
            ->withTimestamps();
    }

    public function createdTasks(): HasMany
    {
        return $this->hasMany(Task::class, 'creator_id');
    }

    public function assignedTasks(): HasMany
    {
        return $this->hasMany(Task::class, 'assignee_id');
    }

    public function activities(): HasMany
    {
        return $this->hasMany(Activity::class);
    }

    public function disks(): HasMany
    {
        return $this->hasMany(Disk::class, 'owner_id');
    }

    public function mailboxes(): HasMany
    {
        return $this->hasMany(Mailbox::class, 'user_id');
    }

    public function employeeHrRequests(): HasMany
    {
        return $this->hasMany(HrRequest::class, 'employee_user_id');
    }

    public function assignedHrRequests(): HasMany
    {
        return $this->hasMany(HrRequest::class, 'assignee_user_id');
    }

    public function createdHrRequests(): HasMany
    {
        return $this->hasMany(HrRequest::class, 'creator_user_id');
    }

    public function sentChatMessages(): HasMany
    {
        return $this->hasMany(ChatMessage::class, 'sender_id');
    }

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

    public function organizationCompany(): BelongsTo
    {
        return $this->belongsTo(OrganizationCompany::class, 'organization_company_id');
    }

    public function accessGroup(): BelongsTo
    {
        return $this->belongsTo(AccessGroup::class, 'access_group_id');
    }

    public function subordinates(): HasMany
    {
        return $this->hasMany(self::class, 'manager_id');
    }

    public function receivedChatMessages(): HasMany
    {
        return $this->hasMany(ChatMessage::class, 'recipient_id');
    }

    public function menuItems(): HasMany
    {
        return $this->hasMany(UserMenuItem::class)->orderBy('sort_order')->orderBy('id');
    }

    public function isAdmin(): bool
    {
        return $this->role === 'admin';
    }

    public function hasTwoFactorEnabled(): bool
    {
        return ! empty($this->two_factor_secret) && $this->two_factor_confirmed_at !== null;
    }
}
