<?php

declare(strict_types=1);

namespace App\Models;

use App\Enums\UserActions;
use App\Enums\UserTypes;
use App\Models\PersonalAccessToken;
use App\Support\HasApiTokens;
use Hypervel\Foundation\Auth\User as Authenticatable;

use Hypervel\Support\Collection;

class User extends Authenticatable
{
    use HasApiTokens;

    public ?PersonalAccessToken $accessToken = null;

    protected ?string $table = 'users';

    public bool $incrementing = true;
    protected array $attributes = [
        'active' => true,
    ];


    protected array $hidden = [
        'password',
        'remember_token',
        // add anything else you don’t want exposed
    ];

    /**
     * The attributes that are mass assignable.
     */
    protected array $fillable = [
        'name',
        'fullname',
        'hashkey',
        'mobile_number',
        'landline',
        'nickname',
        'username',
        'email',
        'email_verified_at',
        'mobile_verified_at',
        'password',
        'acct_type',
        'total_balance',
        'total_credit',
        'created_by',
        'updated_by',
        'active',
        'parentuid',
        'targetuids',
        'notes',
        'exec_command',
        'settings',
        'multiple_logins',
        'referralcode',
        'photourl',
        'logs',
        'cart',
        'details',
        'additional_roles',
        'denied_roles',
    ];

    protected array $casts = [
        'email_verified_at' => 'datetime',
        'mobile_verified_at' => 'datetime',
        'targetuids' => 'array',
        'settings' => 'array',
        'photourl' => 'array',
        'logs' => 'array',
        'cart' => 'array',
        'multiple_logins' => 'boolean',
        'active' => 'boolean',
        'details' => 'array',
        'acct_type' => UserTypes::class ,
        'additional_roles' => \App\Casts\UserActionsArrayCast::class ,
        'denied_roles' => \App\Casts\UserActionsArrayCast::class ,
    ];

    public function userInfo()
    {
        return $this->hasOne(\App\Models\Market\UserInfo::class, 'user_id');
    }

    public function cooperativeMemberships()
    {
        return $this->hasMany(\App\Models\Market\CooperativeMember::class, 'user_id');
    }

    public function creator()
    {
        return $this->belongsTo(User::class , 'created_by');
    }


    public function updater()
    {
        return $this->belongsTo(User::class , 'updated_by');
    }

    public function parent()
    {
        return $this->belongsTo(User::class , 'parentuid');
    }

    public function getAllDescendants(): Collection
    {
        $descendants = collect();

        $children = self::where('parentuid', $this->id)->get();

        foreach ($children as $child) {
            $descendants->push($child);

            // Recursively get each child's descendants
            $descendants = $descendants->merge($child->getAllDescendants());
        }
        return $descendants;
    }

    public function children()
    {
        return $this->hasMany(User::class , 'parentuid');
    }

    /**
     * Check if the user has a specific role.
     */
    public function hasRole(UserTypes|string|array $role): bool
    {
        if (is_array($role)) {
            foreach ($role as $r) {
                if ($this->hasRole($r)) {
                    return true;
                }
            }
            return false;
        }

        $roleValue = $role instanceof UserTypes ? $role->value : $role;
        return $this->acct_type->value === $roleValue;
    }

    /**
     * Convenience methods for common roles.
     */
    public function isUltimate(): bool
    {
        return $this->acct_type === UserTypes::ULTIMATE;
    }

    public function isSuperOperator(): bool
    {
        return $this->acct_type === UserTypes::SUPER_OPERATOR;
    }

    public function isOperator(): bool
    {
        return $this->acct_type === UserTypes::OPERATOR;
    }

    /**
     * Get cooperatives from settings.
     */
    public function getCooperativesAttribute(): array
    {
        return $this->settings['cooperatives'] ?? [];
    }

    /**
     * Check if the user has joined a specific cooperative via settings.
     */
    public function hasJoinedCooperative(string $cooperativeHash): bool
    {
        return in_array($cooperativeHash, $this->cooperatives);
    }

    /**
     * Check if the user has a specific permission (action).
     */
    public function canDo(\App\Enums\UserActions $action, string|int|UserTypes $target = null): bool
    {
        return \App\Http\Controllers\Helpers\Permissions\UserPermissions::isActionPermitted($target ?? $this->acct_type, $action);
    }
}