<?php

namespace App\Models;

use Database\Factories\UserFactory;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
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;

class User extends Authenticatable implements MustVerifyEmail
{
    /** @use HasFactory<UserFactory> */
    use HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var list<string>
     */
    protected $fillable = [
        'name',
        'email',
        'google_id',
        'avatar',
        'profile_photo',
        'selected_avatar',
        'avatar_type',
        'email_verified_at',
        'password',
        'role',
        'status',
        'referral_code',
        'public_username',
        'public_profile_enabled',
        'show_public_profit',
        'referred_by',
        'referral_bonus',
    ];

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

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

    protected static function booted(): void
    {
        static::creating(function (User $user): void {
            if (blank($user->referral_code)) {
                do {
                    $code = 'VZT'.Str::upper(Str::random(8));
                } while (self::where('referral_code', $code)->exists());

                $user->referral_code = $code;
            }
        });
    }

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

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

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

    public function activeSubscription()
    {
        return $this->hasOne(UserSubscription::class)->active()->latestOfMany();
    }

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

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

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

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

    public function mentorStudents(): HasMany
    {
        return $this->hasMany(MentorStudent::class, 'mentor_id');
    }

    public function studentMentors(): HasMany
    {
        return $this->hasMany(MentorStudent::class, 'student_id');
    }

    public function mentorTradeComments(): HasMany
    {
        return $this->hasMany(TradeComment::class, 'mentor_id');
    }

    public function studentTradeComments(): HasMany
    {
        return $this->hasMany(TradeComment::class, 'student_id');
    }

    public function referredBy(): BelongsTo
    {
        return $this->belongsTo(User::class, 'referred_by');
    }

    public function referrals(): HasMany
    {
        return $this->hasMany(User::class, 'referred_by');
    }

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

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

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

    public function communityBan()
    {
        return $this->hasOne(CommunityBan::class);
    }

    public function communityFollowers(): HasMany
    {
        return $this->hasMany(CommunityFollow::class, 'following_id');
    }

    public function communityFollowing(): HasMany
    {
        return $this->hasMany(CommunityFollow::class, 'follower_id');
    }

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

    public function isBannedFromCommunity(): bool
    {
        $ban = $this->communityBan;

        return $ban !== null && $ban->isActive();
    }

    public function hasActiveSubscription(): bool
    {
        return $this->subscriptions()->active()->exists();
    }

    public function latestSubscription()
    {
        return $this->hasOne(UserSubscription::class)->latestOfMany();
    }

    public function isWithinFreeTrial(int $trialDays): bool
    {
        if ($trialDays <= 0) {
            return false;
        }

        return $this->created_at?->greaterThanOrEqualTo(now()->subDays($trialDays)) ?? false;
    }

    public function hasSubscriptionGracePeriod(int $graceDays): bool
    {
        if ($graceDays <= 0) {
            return false;
        }

        return $this->subscriptions()
            ->whereNotNull('ends_at')
            ->where('ends_at', '<=', now())
            ->where('ends_at', '>=', now()->subDays($graceDays))
            ->exists();
    }

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

    public function isSupportTeam(): bool
    {
        return $this->role === 'support_team' && $this->status === 'active';
    }

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

    public function isMentor(): bool
    {
        return $this->role === 'mentor' && $this->status === 'active';
    }

    public function isStudent(): bool
    {
        return $this->role === 'student' && $this->status === 'active';
    }

    public function isTrader(): bool
    {
        return in_array(($this->role ?? 'user'), ['user', 'student'], true) && ($this->status ?? 'active') === 'active';
    }

    public function isBlocked(): bool
    {
        return $this->status === 'blocked';
    }

    public function profileImageUrl(): string
    {
        if ($this->avatar_type === 'custom' && filled($this->profile_photo)) {
            return asset('storage/'.$this->profile_photo);
        }

        if ($this->avatar_type === 'avatar' && filled($this->selected_avatar)) {
            return str_starts_with($this->selected_avatar, 'avatars/')
                ? asset('storage/'.$this->selected_avatar)
                : asset($this->selected_avatar);
        }

        if (filled($this->avatar)) {
            return $this->avatar;
        }

        $defaultAvatar = Avatar::defaultImagePath();

        return str_starts_with($defaultAvatar, 'avatars/')
            ? asset('storage/'.$defaultAvatar)
            : asset($defaultAvatar);
    }

    public function usesAvatarPath(string $imagePath): bool
    {
        return $this->avatar_type === 'avatar' && $this->selected_avatar === $imagePath;
    }

    public static function roles(): array
    {
        return [
            'admin' => 'Admin',
            'support_team' => 'Support Team',
            'mentor' => 'Mentor',
            'student' => 'Student',
            'user' => 'User',
        ];
    }
}
