const mongoose = require('mongoose');

const followerSchema = new mongoose.Schema({
    // User who is following (the follower)
    followerId: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'User',
        required: [true, 'Follower ID is required']
    },
    
    // User who is being followed (the followee)
    followingId: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'User',
        required: [true, 'Following ID is required']
    },
    
    // Status of the follow request
    status: {
        type: String,
        enum: ['requested', 'accepted', 'rejected'],
        default: 'requested'
    },
    
    // When the follow request was made
    requestedAt: {
        type: Date,
        default: Date.now
    },
    
    // When the request was accepted/rejected
    respondedAt: {
        type: Date,
        default: null
    },
    
    // Any message sent with the follow request
    message: {
        type: String,
        trim: true,
        maxlength: [200, 'Message cannot exceed 200 characters']
    }
}, {
    timestamps: true
});

// Compound index to ensure unique follower-following pairs
followerSchema.index({ followerId: 1, followingId: 1 }, { unique: true });

// Index for efficient queries
followerSchema.index({ followerId: 1, status: 1 });
followerSchema.index({ followingId: 1, status: 1 });

// Virtual for follower user details
followerSchema.virtual('followerDetails', {
    ref: 'User',
    localField: 'followerId',
    foreignField: '_id',
    justOne: true
});

// Virtual for following user details
followerSchema.virtual('followingDetails', {
    ref: 'User',
    localField: 'followingId',
    foreignField: '_id',
    justOne: true
});

// Ensure virtual fields are serialized
followerSchema.set('toJSON', { virtuals: true });
followerSchema.set('toObject', { virtuals: true });

// Static method to get followers of a user
followerSchema.statics.getFollowers = async function(userId, status = 'accepted') {
    try {
        const followers = await this.find({ 
            followingId: userId, 
            status: status 
        })
        .populate('followerId', 'name profileImage about interests')
        .sort({ createdAt: -1 });
        
        return followers;
    } catch (error) {
        console.error('Error getting followers:', error);
        throw error;
    }
};

// Static method to get users that a user is following
followerSchema.statics.getFollowing = async function(userId, status = 'accepted') {
    try {
        const following = await this.find({ 
            followerId: userId, 
            status: status 
        })
        .populate('followingId', 'name profileImage about interests')
        .sort({ createdAt: -1 });
        
        return following;
    } catch (error) {
        console.error('Error getting following:', error);
        throw error;
    }
};

// Static method to get follow requests (pending requests to user)
followerSchema.statics.getFollowRequests = async function(userId) {
    try {
        const requests = await this.find({ 
            followingId: userId, 
            status: 'requested' 
        })
        .populate('followerId', 'name profileImage about interests')
        .sort({ createdAt: -1 });
        
        return requests;
    } catch (error) {
        console.error('Error getting follow requests:', error);
        throw error;
    }
};

// Static method to check if user A follows user B
followerSchema.statics.isFollowing = async function(followerId, followingId) {
    try {
        const follow = await this.findOne({ 
            followerId: followerId, 
            followingId: followingId 
        });
        
        return follow ? follow.status : null;
    } catch (error) {
        console.error('Error checking follow status:', error);
        throw error;
    }
};

// Static method to get mutual friends between two users
followerSchema.statics.getMutualFriends = async function(userId1, userId2) {
    try {
        // Get users that both users follow
        const user1Following = await this.find({ 
            followerId: userId1, 
            status: 'accepted' 
        }).select('followingId');
        
        const user2Following = await this.find({ 
            followerId: userId2, 
            status: 'accepted' 
        }).select('followingId');
        
        // Find common following IDs
        const user1FollowingIds = user1Following.map(f => f.followingId.toString());
        const user2FollowingIds = user2Following.map(f => f.followingId.toString());
        
        const mutualIds = user1FollowingIds.filter(id => user2FollowingIds.includes(id));
        
        // Get user details for mutual friends
        const User = mongoose.model('User');
        const mutualFriends = await User.find({ 
            _id: { $in: mutualIds } 
        }).select('name profileImage about interests');
        
        return mutualFriends;
    } catch (error) {
        console.error('Error getting mutual friends:', error);
        throw error;
    }
};

module.exports = mongoose.model('Follower', followerSchema);
