<?php

namespace App\Models;

use App\Notifications\VerifyEmail;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Str;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable implements MustVerifyEmail
{
    use HasApiTokens, HasFactory, Notifiable;

    protected $fillable = [
        'name',
        'username',
        'email',
        'password',
        'avatar',
        'role',
        'bio',
        'website',
        'twitter',
        'instagram',
        'facebook',
        'youtube',
        'linkedin',
        'tiktok',
        'birthday',
        'location',
        'gender',
        'nationality',
        'phone_code',
        'phone_number',
        'timezone',
        'whatsapp',
        'google_location',
        'social_phone',
        'social_email',
        'two_factor_secret',
        'two_factor_enabled',
        'banner',
        'notification_preferences',
    ];

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

    protected $casts = [
        'email_verified_at'          => 'datetime',
        'password'                   => 'hashed',
        'two_factor_enabled'         => 'boolean',
        'notification_preferences'   => 'array',
    ];

    // Defaults for each preference key (true = on, false = off)
    private const NOTIF_DEFAULTS = [
        'notif_new_comment'        => true,
        'notif_new_reply'          => true,
        'notif_comment_like'       => true,
        'notif_video_like'         => true,
        'notif_new_subscriber'     => true,
        'notif_new_video_from_sub' => true,
        'notif_new_post_from_sub'  => true,
        'notif_new_user_reg'       => true,
        'email_new_comment'        => true,
        'email_new_reply'          => true,
        'email_comment_like'       => false,
        'email_video_like'         => false,
        'email_new_subscriber'     => true,
        'email_new_video_from_sub' => true,
        'email_new_post_from_sub'  => false,
        'email_video_processed'    => true,
        'email_new_user_reg'       => true,
        'email_weekly_digest'      => true,
    ];

    public function notificationPref(string $key): bool
    {
        $prefs   = $this->notification_preferences ?? [];
        $default = self::NOTIF_DEFAULTS[$key] ?? true;
        return isset($prefs[$key]) ? (bool) $prefs[$key] : $default;
    }

    public static function notifDefaults(): array
    {
        return self::NOTIF_DEFAULTS;
    }

    protected $appends = ['avatar_url', 'banner_url'];

    // Auto-generate a unique slug-based username when creating a user without one
    protected static function boot(): void
    {
        parent::boot();
        static::creating(function (User $user) {
            if (empty($user->username)) {
                $user->username = static::generateUniqueUsername($user->name);
            }
        });
    }

    public static function generateUniqueUsername(string $name): string
    {
        $base = substr(Str::slug(trim($name)), 0, 18);
        if ($base === '') {
            $base = 'user';
        }
        do {
            $slug = $base . '-' . Str::lower(Str::random(6));
        } while (static::where('username', $slug)->exists());

        return $slug;
    }

    // Returns the channel URL slug — the username, auto-generated and saved if missing
    public function getChannelAttribute(): string
    {
        if (empty($this->username)) {
            $this->username = static::generateUniqueUsername($this->name);
            $this->saveQuietly();
        }
        return $this->username;
    }

    // Relationships
    public function videos()
    {
        return $this->hasMany(Video::class);
    }

    public function likes()
    {
        return $this->belongsToMany(Video::class, 'video_likes')->withTimestamps();
    }

    public function views()
    {
        return $this->belongsToMany(Video::class, 'video_views')->withTimestamps();
    }

    public function comments()
    {
        return $this->hasMany(Comment::class);
    }

    public function playlists()
    {
        return $this->hasMany(Playlist::class);
    }

    public function posts()
    {
        return $this->hasMany(\App\Models\Post::class);
    }

    public function getAvatarUrlAttribute(): string
    {
        if ($this->avatar) {
            return route('media.avatar', $this->avatar);
        }

        return 'https://i.pravatar.cc/150?u='.$this->id;
    }

    public function getBannerUrlAttribute(): ?string
    {
        if ($this->banner) {
            return route('media.banner', $this->banner);
        }
        return null;
    }

    public function sendEmailVerificationNotification(): void
    {
        $this->notify(new VerifyEmail);
    }

    // Role helper methods
    public function isSuperAdmin()
    {
        return $this->role === 'super_admin';
    }

    public function isAdmin()
    {
        return in_array($this->role, ['admin', 'super_admin']);
    }

    public function isUser()
    {
        return $this->role === 'user' || $this->role === null;
    }

    // Users who subscribe TO this channel
    public function subscribers()
    {
        return $this->belongsToMany(
            User::class,
            'user_subscriptions',
            'channel_id',
            'subscriber_id'
        )->withPivot(['created_at', 'source_video_id']);
    }

    // Channels this user subscribes to
    public function subscriptions()
    {
        return $this->belongsToMany(
            User::class,
            'user_subscriptions',
            'subscriber_id',
            'channel_id'
        )->withPivot(['created_at', 'source_video_id']);
    }

    public function isSubscribedTo(User $channel): bool
    {
        return $this->subscriptions()->where('channel_id', $channel->id)->exists();
    }

    public function getSubscriberCountAttribute(): int
    {
        return $this->subscribers()->count();
    }

    // Check if user has any social links
    public function socialLinks()
    {
        return $this->hasMany(UserSocialLink::class)->orderBy('sort_order');
    }

    public function hasSocialLinks()
    {
        return $this->socialLinks()->exists();
    }

    // Get formatted website URL
    public function getWebsiteUrlAttribute()
    {
        if (! $this->website) {
            return null;
        }

        // Add https:// if no protocol is specified
        if (! preg_match('/^https?:\/\//', $this->website)) {
            return 'https://'.$this->website;
        }

        return $this->website;
    }
}
