<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use Spatie\Permission\Traits\HasRoles;

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

    protected $fillable = [
        'first_name',
        'last_name',
        'email',
        'phone',
        'password',
        'gender',
        'date_of_birth',
        'profile_image',
        'account_type',
        'status',
        'language',
        'dark_mode',
        'interests',
        'preferences',
        'referral_code',
        'referred_by',
        'biometric_enabled',
        'device_token',
        'fcm_token',
        'last_active_at',
    ];

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

    protected $casts = [
        'email_verified_at' => 'datetime',
        'phone_verified_at' => 'datetime',
        'password' => 'hashed',
        'date_of_birth' => 'date',
        'dark_mode' => 'boolean',
        'biometric_enabled' => 'boolean',
        'interests' => 'array',
        'preferences' => 'array',
        'last_active_at' => 'datetime',
    ];

    /**
     * Eager load relationships
     */
    // Disabled to prevent collection issues with HasRoles trait
    // protected $with = ['roles.permissions'];


    // Relationships
    public function notifications()
    {
        return $this->morphMany(Notification::class, 'notifiable')->orderBy('created_at', 'desc');
    }

    public function unreadNotifications()
    {
        return $this->morphMany(Notification::class, 'notifiable')->whereNull('read_at')->orderBy('created_at', 'desc');
    }

    public function socialAccounts()
    {
        return $this->hasMany(SocialAccount::class);
    }

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

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

    public function businesses()
    {
        return $this->hasMany(Business::class, 'owner_id');
    }

    public function business()
    {
        return $this->hasOne(Business::class, 'owner_id')->latestOfMany();
    }

    public function getOwnerBusinessForStaff()
    {
        // Get the business that this user is a staff member of
        // User -> BusinessStaff -> Business
        return $this->belongsToMany(Business::class, 'business_staff', 'user_id', 'business_id')
            ->wherePivot('status', 'active')
            ->first();
    }

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

    public function activeSubscription()
    {
        return $this->hasOne(Subscription::class)->where('status', 'active')->latest();
    }

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

    public function redemptions()
    {
        return $this->hasMany(Redemption::class);
    }

    public function spotlights()
    {
        return $this->hasMany(Spotlight::class);
    }

    public function reviews()
    {
        return $this->hasMany(Review::class);
    }

    public function favorites()
    {
        return $this->hasMany(Favorite::class);
    }

    public function follows()
    {
        return $this->hasMany(Follow::class);
    }

    public function spotlightLikes()
    {
        return $this->hasMany(SpotlightLike::class);
    }

    public function spotlightComments()
    {
        return $this->hasMany(SpotlightComment::class);
    }

    public function businessStaff()
    {
        return $this->hasMany(BusinessStaff::class);
    }

    public function activeBusinessMemberships()
    {
        return $this->hasMany(BusinessStaff::class)->where('business_staff.status', 'active');
    }

    public function pendingBusinessInvitations()
    {
        return $this->hasMany(BusinessStaff::class)->where('business_staff.status', 'pending_invitation');
    }

    /**
     * Roles relationship
     */
    public function roles(): BelongsToMany
    {
        return $this->belongsToMany(Role::class, 'user_role')
            ->withPivot('business_id')
            ->withTimestamps();
    }

    /**
     * Check if user has role
     */
    public function hasRole($role, $businessId = null): bool
    {
        if (is_string($role)) {
            $query = $this->roles()->where('roles.name', $role);
        } elseif (is_int($role)) {
            // Handle integer IDs
            $query = $this->roles()->where('roles.id', $role);
        } elseif (is_object($role)) {
            // Handle Role objects or other models
            if (method_exists($role, 'getKey')) {
                $roleId = $role->getKey();
            } elseif (isset($role->id)) {
                $roleId = $role->id;
            } else {
                // Not a valid role object
                return false;
            }
            $query = $this->roles()->where('roles.id', $roleId);
        } else {
            // Invalid role parameter
            return false;
        }

        if ($businessId) {
            $query->wherePivot('business_id', $businessId);
        }

        return $query->exists();
    }

    /**
     * Check if user has any role
     */
    public function hasAnyRole(array $roles, $businessId = null): bool
    {
        foreach ($roles as $role) {
            if ($this->hasRole($role, $businessId)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Check if user has permission
     */
    public function hasPermission(string $permission, $businessId = null): bool
    {
        // Get roles with permissions eager loaded
        if ($businessId) {
            $roles = $this->roles()->wherePivot('business_id', $businessId)->with('permissions')->get();
        } else {
            // Use eager loaded roles or load them if not already loaded
            $roles = $this->relationLoaded('roles') ? $this->roles : $this->roles()->with('permissions')->get();
        }

        // Ensure roles is a collection
        if (!is_iterable($roles)) {
            return false;
        }

        foreach ($roles as $role) {
            if (!$role) {
                continue;
            }

            // Check if role has the permission
            if ($role->relationLoaded('permissions')) {
                // Use eager loaded permissions
                if ($role->permissions && $role->permissions->where('name', $permission)->isNotEmpty()) {
                    return true;
                }
            } else {
                // Fallback to query
                if (method_exists($role, 'hasPermission') && $role->hasPermission($permission)) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * Check if user has any permission
     */
    public function hasAnyPermission(array $permissions, $businessId = null): bool
    {
        foreach ($permissions as $permission) {
            if ($this->hasPermission($permission, $businessId)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Assign role to user
     */
    public function assignRole($role, $businessId = null)
    {
        if (is_string($role)) {
            $role = Role::where('name', $role)->firstOrFail();
        }

        if (!$this->hasRole($role->id, $businessId)) {
            $this->roles()->attach($role->id, ['business_id' => $businessId]);
        }

        return $this;
    }

    /**
     * Remove role from user
     */
    public function removeRole($role, $businessId = null)
    {
        if (is_string($role)) {
            $role = Role::where('name', $role)->firstOrFail();
        }

        if ($businessId) {
            $this->roles()
                ->wherePivot('business_id', $businessId)
                ->detach($role->id);
        } else {
            $this->roles()->detach($role->id);
        }

        return $this;
    }

    /**
     * Sync roles for user
     */
    public function syncRoles(array $roleIds, $businessId = null)
    {
        if ($businessId) {
            // Remove old roles for this business
            $this->roles()->wherePivot('business_id', $businessId)->detach();

            // Attach new roles
            foreach ($roleIds as $roleId) {
                $this->roles()->attach($roleId, ['business_id' => $businessId]);
            }
        } else {
            $this->roles()->sync($roleIds);
        }

        return $this;
    }

    /**
     * Check if super admin
     */
    public function isSuperAdmin(): bool
    {
        return $this->hasRole('super_admin');
    }

    /**
     * Check if has admin role
     */
    public function isAdminUser(): bool
    {
        return $this->hasAnyRole(['super_admin', 'admin']);
    }


    // =============== Team & Chat Relationships ===============

    /**
     * User belongs to many teams
     */
    public function teams(): BelongsToMany
    {
        return $this->belongsToMany(Team::class, 'team_user')
            ->withPivot('role_id', 'custom_permissions', 'status', 'invited_at', 'joined_at')
            ->withTimestamps();
    }

    /**
     * User belongs to many chats
     */
    public function chats(): BelongsToMany
    {
        return $this->belongsToMany(Chat::class, 'chat_participants')
            ->withPivot('role', 'joined_at', 'last_read_at', 'is_active')
            ->withTimestamps();
    }

    /**
     * User has many messages
     */
    public function messages(): \Illuminate\Database\Eloquent\Relations\HasMany
    {
        return $this->hasMany(Message::class, 'sender_id');
    }

    /**
     * Get all teams where user is member
     */
    public function getTeams()
    {
        return $this->teams()
            ->wherePivot('status', 'active')
            ->with('business')
            ->get();
    }

    /**
     * Check if user is member of team
     */
    public function isMemberOfTeam(Team $team): bool
    {
        return $this->teams()
            ->where('team_id', $team->id)
            ->wherePivot('status', 'active')
            ->exists();
    }

    /**
     * Get user's role in team
     */
    public function getTeamRole(Team $team): ?Role
    {
        $member = $this->teams()
            ->where('team_id', $team->id)
            ->first();

        if (!$member || !$member->pivot->role_id) {
            return null;
        }

        return Role::find($member->pivot->role_id);
    }

    // Helpers
    public function getFullNameAttribute()
    {
        return "{$this->first_name} {$this->last_name}";
    }

    public function hasActiveSubscription()
    {
        return $this->activeSubscription()->exists();
    }

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

    public function isBusiness()
    {
        return $this->account_type === 'business';
    }

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

    /**
     * Check if user is business owner
     */
    public function isBusinessOwner(): bool
    {
        // Check if user owns a business by checking businesses relationship
        $hasBusiness = $this->businesses()
            ->where('status', 'active')
            ->exists();

        // Also check if user is a business account type with active business
        if ($hasBusiness) {
            return true;
        }

        // Fallback: Check if user is business type and has any business
        if ($this->account_type === 'business') {
            return $this->businesses()->exists();
        }

        return false;
    }

    /**
     * Check if user has a specific permission in any team or as staff
     */
    public function hasTeamPermission(string $permission): bool
    {
        // Business owner has all permissions
        if ($this->isBusinessOwner()) {
            return true;
        }

        // Check staff permissions first
        if ($this->hasStaffPermission($permission)) {
            return true;
        }

        // Check if user is part of any team
        if (!$this->teams()->count()) {
            return false;
        }

        // Check team roles for permission
        $teamRoles = $this->teams()
            ->wherePivot('status', 'active')
            ->with(['pivot.role' => function($query) {
                $query->with('permissions');
            }])
            ->get()
            ->pluck('pivot.role')
            ->filter();

        // If no roles found, return false
        if ($teamRoles->isEmpty()) {
            return false;
        }

        // Check each role for the permission
        foreach ($teamRoles as $role) {
            if (!$role || !$role->permissions) {
                continue;
            }

            if ($role->permissions->where('name', $permission)->isNotEmpty()) {
                return true;
            }
        }

        return false;
    }

    /**
     * Get user's role in a specific team
     */
    public function getTeamRoleName($team = null): ?string
    {
        if (!$team && $this->teams->count() > 0) {
            $team = $this->teams->first();
        }

        if (!$team) {
            return null;
        }

        $member = $this->teams()
            ->where('team_id', $team->id)
            ->first();

        if (!$member || !$member->pivot->role_id) {
            return null;
        }

        $role = Role::find($member->pivot->role_id);
        return $role ? $role->display_name : null;
    }

    /**
     * Check if user has permission (considering business owner privilege)
     * This method accounts for business owner automatic permissions
     */
    public function canAccessFeature(string $permission, $businessId = null): bool
    {
        // Business owner has access to all features
        if ($this->isBusinessOwner()) {
            return true;
        }

        // Check explicit permission
        return $this->hasPermission($permission, $businessId) || $this->hasTeamPermission($permission);
    }

    protected static function boot()
    {
        parent::boot();

        static::creating(function ($user) {
            if (empty($user->referral_code)) {
                $user->referral_code = strtoupper(substr(md5(uniqid()), 0, 8));
            }
        });
    }

    /**
     * Check if user has a specific permission as staff member in a business
     */
    public function hasStaffPermission(string $permissionName, $businessId = null): bool
    {
        // Get staff record(s)
        $query = BusinessStaff::where('user_id', $this->id)
            ->where('status', 'active');

        if ($businessId) {
            $query->where('business_id', $businessId);
        }

        $staffRecords = $query->get();

        if ($staffRecords->isEmpty()) {
            return false;
        }

        // Check each staff record for the permission
        foreach ($staffRecords as $staff) {
            if (!$staff->permissions) {
                continue;
            }

            $permissionIds = is_array($staff->permissions) ? $staff->permissions : json_decode($staff->permissions, true);

            if (!is_array($permissionIds)) {
                continue;
            }

            // Get permissions by ID
            $permissions = Permission::whereIn('id', $permissionIds)->get();

            if ($permissions->where('name', $permissionName)->isNotEmpty()) {
                return true;
            }
        }

        return false;
    }

    /**
     * Get user's business through staff membership
     */
    public function getStaffBusiness($onlyActive = true): ?Business
    {
        $query = BusinessStaff::where('user_id', $this->id);

        if ($onlyActive) {
            $query->where('status', 'active');
        }

        $staff = $query->first();

        return $staff ? $staff->business : null;
    }

    /**
     * Get current user subscription
     */
    public function currentUserSubscription()
    {
        return $this->hasOne(UserSubscription::class)
            ->where('status', 'active')
            ->where('end_date', '>', now())
            ->latest();
    }

    /**
     * Get user subscription history
     */
    public function userSubscriptionHistory()
    {
        return $this->hasMany(UserSubscription::class);
    }

    /**
     * Check if user is premium
     */
    public function isPremium(): bool
    {
        $subscription = $this->currentUserSubscription;
        return $subscription && $subscription->plan->tier === 'premium';
    }

    /**
     * Check if user is VIP
     */
    public function isVIP(): bool
    {
        $subscription = $this->currentUserSubscription;
        return $subscription && $subscription->plan->tier === 'vip';
    }

    /**
     * Check if user can add favorite
     */
    public function canAddFavorite(): bool
    {
        $subscription = $this->currentUserSubscription;

        // If no subscription, check free plan limit (5 favorites max)
        if (!$subscription) {
            return $this->favorites()->count() < 5;
        }

        $plan = $subscription->plan;
        if ($plan->max_favorites == -1) return true; // Unlimited

        return $this->favorites()->count() < $plan->max_favorites;
    }

    /**
     * Get user's cashback rate
     */
    public function getCashbackRate(): float
    {
        $subscription = $this->currentUserSubscription;
        return $subscription ? $subscription->plan->cashback_percentage : 0;
    }

    /**
     * Get user's loyalty points multiplier
     */
    public function getLoyaltyMultiplier(): int
    {
        $subscription = $this->currentUserSubscription;
        return $subscription ? $subscription->plan->loyalty_points_multiplier : 1;
    }

    /**
     * Check if user has ad-free experience
     */
    public function hasAdFree(): bool
    {
        $subscription = $this->currentUserSubscription;
        return $subscription ? $subscription->plan->ad_free : false;
    }

    /**
     * Get user subscription tier
     */
    public function getUserSubscriptionTier(): ?string
    {
        $subscription = $this->currentUserSubscription;
        return $subscription ? $subscription->plan->tier : null;
    }

    /**
     * Check if user subscription is active
     */
    public function hasActiveUserSubscription(): bool
    {
        return $this->currentUserSubscription !== null;
    }

    /**
     * Get days until user subscription expires
     */
    public function getDaysUntilSubscriptionExpires(): int
    {
        $subscription = $this->currentUserSubscription;
        return $subscription ? $subscription->daysRemaining() : 0;
    }

    /**
     * Get user subscription usage details
     */
    public function getUserSubscriptionUsage(): array
    {
        $subscription = $this->currentUserSubscription;

        // Default free plan limits
        $maxFavorites = 5;
        $maxRedemptionsPerMonth = 10;
        $maxReviewsPerMonth = 3;

        if ($subscription) {
            $plan = $subscription->plan;
            $maxFavorites = $plan->max_favorites;
            $maxRedemptionsPerMonth = $plan->max_redemptions_per_month;
            $maxReviewsPerMonth = $plan->max_reviews_per_month;
        }

        return [
            'favorites' => [
                'used' => $this->favorites()->count(),
                'limit' => $maxFavorites,
                'unlimited' => $maxFavorites == -1,
            ],
            'redemptions_this_month' => [
                'used' => Redemption::where('user_id', $this->id)
                    ->whereMonth('created_at', now()->month)
                    ->whereYear('created_at', now()->year)
                    ->count(),
                'limit' => $maxRedemptionsPerMonth,
                'unlimited' => $maxRedemptionsPerMonth == -1,
            ],
            'reviews_this_month' => [
                'used' => Review::where('user_id', $this->id)
                    ->whereMonth('created_at', now()->month)
                    ->whereYear('created_at', now()->year)
                    ->count(),
                'limit' => $maxReviewsPerMonth,
                'unlimited' => $maxReviewsPerMonth == -1,
            ]
        ];
    }

//    get admins
    public static function getAdmins()
    {
        return self::where('account_type', 'admin')->get();
    }
}
