<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;

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

    protected $fillable = [
        'name', 'username', 'email', 'password', 'avatar',
        'social_provider', 'social_id',
        'bio', 'banner_image', 'website', 'twitter', 'instagram', 'discord',
        'profile_color', 'show_watchlist', 'show_activity',
        'role', 'membership', 'premium_expires_at',
        'is_banned', 'ban_reason', 'banned_at',
        'gif_avatar', 'comment_bg', 'comment_glow', 'username_color', 'username_effect',
        'profile_frame', 'profile_badge', 'admin_badge', 'profile_bg', 'profile_theme',
        'profile_music_url', 'comment_signature', 'entry_effect', 'animated_banner',
    ];

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

    protected function casts(): array
    {
        return [
            'email_verified_at'  => 'datetime',
            'premium_expires_at' => 'datetime',
            'banned_at'          => 'datetime',
            'is_banned'          => 'boolean',
            'show_watchlist'     => 'boolean',
            'show_activity'      => 'boolean',
            'animated_banner'    => 'boolean',
            'password'           => 'hashed',
        ];
    }

    /**
     * /u/{username} gibi URL'lerde username veya ID ile çözümleme.
     * custom_profile_url perki olan kullanıcılar /u/kullanici-adi şeklinde erişilebilir.
     */
    public function resolveRouteBinding($value, $field = null): ?self
    {
        if (is_numeric($value)) {
            return static::find($value);
        }
        return static::where('username', $value)
            ->whereNotNull('username')
            ->first();
    }

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

    public function isModerator(): bool
    {
        return in_array($this->role, ['admin', 'moderator']);
    }

    public function moderatorPermissions()
    {
        return $this->hasMany(ModeratorPermission::class);
    }

    public function activityLogs()
    {
        return $this->hasMany(UserActivityLog::class);
    }

    /** Returns cached permission set for this user. Admins have all permissions. */
    public function can_mod(string $permission): bool
    {
        if ($this->isAdmin()) return true;
        if ($this->role !== 'moderator') return false;

        $key = "mod_perms_{$this->id}";
        $perms = cache()->remember($key, 300, fn() =>
            ModeratorPermission::where('user_id', $this->id)->pluck('permission')->all()
        );
        return in_array($permission, $perms);
    }

    /** Flush cached permissions (call after saving changes). */
    public function flushPermCache(): void
    {
        cache()->forget("mod_perms_{$this->id}");
    }

    /** isPremium() sonucunu istek başına önbellekle — sayfa başına onlarca kez çağrılıyor */
    private ?bool $_isPremiumCache = null;

    public function isPremium(): bool
    {
        if ($this->_isPremiumCache !== null) {
            return $this->_isPremiumCache;
        }

        // 1. yol: membership alanı 'premium' ve süresi dolmamış
        $viaMembership = $this->membership === 'premium'
            && ($this->premium_expires_at === null || $this->premium_expires_at->isFuture());
        if ($viaMembership) {
            return $this->_isPremiumCache = true;
        }

        // 2. yol: aktif abonelik var ama membership alanı senkronize değil
        // (2 farklı premium yolu — biri güncellenmezse kullanıcı yine premium sayılır)
        try {
            $viaSubscription = $this->subscriptions()
                ->where('status', 'active')
                ->where(fn ($q) => $q->whereNull('expires_at')->orWhere('expires_at', '>', now()))
                ->exists();
        } catch (\Throwable) {
            $viaSubscription = false;
        }

        return $this->_isPremiumCache = $viaSubscription;
    }

    /**
     * Kullanıcının aktif planında belirli bir perk var mı?
     * Ücretsiz kullanıcılarda her zaman false döner.
     */
    public function hasPerk(string $key): bool
    {
        if (!$this->isPremium()) return false;

        // Ücretsiz mod: tüm perkler herkese açık
        if (self::freeModeActive()) return true;

        $sub = $this->subscriptions()
            ->where('status', 'active')
            ->where(fn($q) => $q->whereNull('expires_at')->orWhere('expires_at', '>', now()))
            ->latest()
            ->with('plan')
            ->first();

        if (!$sub?->plan) return false;

        $perks = $sub->plan->perks ?? [];
        return !empty($perks[$key]);
    }

    /** premium_free_mode ayarını 5dk cache'leyerek okur */
    public static function freeModeActive(): bool
    {
        return cache()->remember('premium_free_mode', 300, fn() =>
            \App\Models\Setting::get('premium_free_mode', '0')
        ) === '1';
    }

    /**
     * Kullanıcının aktif avatar URL'si: GIF avatar varsa ve hasPerk('gif_avatar') ise döner.
     */
    public function effectiveAvatar(): ?string
    {
        if ($this->gif_avatar && $this->hasPerk('gif_avatar')) {
            return $this->gif_avatar;
        }
        return $this->avatar;
    }

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

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

    // ── Social ────────────────────────────────────────────────────────────────

    public function followers()
    {
        return $this->belongsToMany(User::class, 'user_follows', 'following_id', 'follower_id')
            ->withPivot('created_at');
    }

    public function following()
    {
        return $this->belongsToMany(User::class, 'user_follows', 'follower_id', 'following_id')
            ->withPivot('created_at');
    }

    public function isFollowing(int $userId): bool
    {
        return \App\Models\UserFollow::where('follower_id', $this->id)
            ->where('following_id', $userId)
            ->exists();
    }

    public function conversations()
    {
        return $this->belongsToMany(Conversation::class, 'conversation_participants')
            ->withPivot('last_read_at');
    }

    public function totalUnreadMessages(): int
    {
        return $this->conversations()
            ->with(['messages' => fn($q) => $q->where('user_id', '!=', $this->id)])
            ->get()
            ->sum(fn($c) => $c->unreadCountFor($this->id));
    }

    // Anime zevk uyum skoru (0-100)
    public function compatibilityWith(User $other): int
    {
        $myIds    = \App\Models\Watchlist::where('user_id', $this->id)->pluck('anime_id');
        $theirIds = \App\Models\Watchlist::where('user_id', $other->id)->pluck('anime_id');

        if ($myIds->isEmpty() || $theirIds->isEmpty()) return 0;

        $mySet    = $myIds->unique()->values();
        $theirSet = $theirIds->unique()->values();
        $intersection = $mySet->intersect($theirSet)->count();
        $union        = $mySet->merge($theirSet)->unique()->count();

        $jaccard = $union > 0 ? $intersection / $union : 0;

        // Rating similarity bonus
        $myRatings    = \DB::table('anime_ratings')->where('user_id', $this->id)->pluck('rating', 'anime_id');
        $theirRatings = \DB::table('anime_ratings')->where('user_id', $other->id)->pluck('rating', 'anime_id');
        $commonAnimes = $myRatings->keys()->intersect($theirRatings->keys());

        $ratingScore = 0;
        if ($commonAnimes->count() > 0) {
            $diffs = $commonAnimes->map(fn($id) => abs($myRatings[$id] - $theirRatings[$id]) / 10);
            $ratingScore = 1 - $diffs->avg();
        }

        $score = $jaccard * 0.6 + $ratingScore * 0.4;
        return (int) round(min($score * 100, 100));
    }

    /**
     * İzleme saatine göre rank bilgisi döner.
     * watch_rank perki yoksa null döner.
     */
    public function watchRank(): ?array
    {
        if (!$this->hasPerk('watch_rank')) return null;

        $totalSeconds = \App\Models\ContinueWatching::where('user_id', $this->id)
            ->sum('seconds_watched');
        $hours = $totalSeconds / 3600;

        return match(true) {
            $hours >= 500 => ['label' => 'Efsane',   'color' => '#ff2d7d', 'icon' => 'bi-trophy-fill'],
            $hours >= 250 => ['label' => 'Usta',     'color' => '#ffd700', 'icon' => 'bi-star-fill'],
            $hours >= 100 => ['label' => 'Bağımlı',  'color' => '#b84dff', 'icon' => 'bi-heart-fill'],
            $hours >= 50  => ['label' => 'Hayran',   'color' => '#00f5ff', 'icon' => 'bi-eye-fill'],
            $hours >= 20  => ['label' => 'İzleyici', 'color' => '#00d4a4', 'icon' => 'bi-play-circle-fill'],
            default       => ['label' => 'Acemi',    'color' => '#9ca3af', 'icon' => 'bi-controller'],
        };
    }
}
