import random
from django.core.management.base import BaseCommand
from django.db import transaction
from django.contrib.auth import get_user_model
from categories.models import Category
from posts.models import Post
from comments.models import Comment
from likes.models import LikePost, LikeComment
from follows.models import FollowUser, FollowCategory

try:
    from faker import Faker
except ImportError:
    Faker = None

class Command(BaseCommand):
    help = 'Generates fake data for testing: Users, Posts, Comments, Likes, Follows'

    def handle(self, *args, **kwargs):
        if not Faker:
            self.stdout.write(self.style.ERROR('Faker library is not installed. Please install it using: pip install faker'))
            return

        fake = Faker()
        User = get_user_model()

        # Configuration
        NUM_USERS = 300
        NUM_CATEGORIES = 20
        NUM_POSTS = 5000
        NUM_COMMENTS = 3589

        # Approximate numbers for relationships
        NUM_POST_LIKES = 10000
        NUM_COMMENT_LIKES = 5000
        NUM_FOLLOWS = 2000
        NUM_CATEGORY_FOLLOWS = 1000

        self.stdout.write('Starting data generation...')

        with transaction.atomic():
            # 1. Users
            self.stdout.write(f'Creating {NUM_USERS} users...')
            users = []
            for i in range(NUM_USERS):
                # Simple check to avoid duplicates if running multiple times without cleanup
                username = fake.user_name() + str(i)
                email = fake.email()
                if not User.objects.filter(username=username).exists():
                    user = User(
                        username=username,
                        email=email,
                        first_name=fake.first_name(),
                        last_name=fake.last_name(),
                        is_active=True,
                        bio=fake.text(max_nb_chars=150)
                    )
                    user.set_password('password123')
                    users.append(user)

            # Using bulk_create for speed (signals won't fire)
            User.objects.bulk_create(users, ignore_conflicts=True)
            # Fetch all users to have IDs
            all_users = list(User.objects.all())
            self.stdout.write(self.style.SUCCESS(f'Created {len(users)} new users. Total: {len(all_users)}'))

            # 2. Categories
            self.stdout.write(f'Creating {NUM_CATEGORIES} categories...')
            categories = []
            for _ in range(NUM_CATEGORIES):
                title = fake.unique.word().capitalize() + " " + fake.word()
                if not Category.objects.filter(title=title).exists():
                    categories.append(Category(
                        title=title,
                        description=fake.text(max_nb_chars=200),
                        created_by=random.choice(all_users)
                    ))
            Category.objects.bulk_create(categories, ignore_conflicts=True)
            all_categories = list(Category.objects.all())
            self.stdout.write(self.style.SUCCESS(f'Created categories. Total: {len(all_categories)}'))

            # 3. Posts
            self.stdout.write(f'Creating {NUM_POSTS} posts...')
            posts = []
            for _ in range(NUM_POSTS):
                user = random.choice(all_users)
                category = random.choice(all_categories) if all_categories and random.random() > 0.2 else None
                posts.append(Post(
                    created_by=user,
                    category=category,
                    content=fake.paragraph(nb_sentences=random.randint(1, 5)),
                    audience=random.choice(['PUBLIC', 'FOLLOWERS', 'ONLY_ME'])
                ))
            Post.objects.bulk_create(posts)
            all_posts = list(Post.objects.all())
            self.stdout.write(self.style.SUCCESS(f'Created {len(posts)} posts.'))

            # 4. Comments
            self.stdout.write(f'Creating {NUM_COMMENTS} comments...')
            comments = []
            for _ in range(NUM_COMMENTS):
                post = random.choice(all_posts)
                user = random.choice(all_users)
                comments.append(Comment(
                    post=post,
                    created_by=user,
                    content=fake.sentence()
                ))
            Comment.objects.bulk_create(comments)
            all_comments = list(Comment.objects.all())
            self.stdout.write(self.style.SUCCESS(f'Created {len(comments)} comments.'))

            # 5. Follows (User)
            self.stdout.write(f'Creating ~{NUM_FOLLOWS} user follows...')
            follows = []
            seen_follows = set()
            # Get existing to avoid duplicates in seen_follows if needed, but for speed we might just try
            # A simple loop ensuring uniqueness in memory before saving
            while len(follows) < NUM_FOLLOWS:
                u1 = random.choice(all_users)
                u2 = random.choice(all_users)
                if u1 != u2 and (u1.id, u2.id) not in seen_follows:
                     # Check DB existence loosely or just rely on ignore_conflicts
                     follows.append(FollowUser(follower=u1, followed=u2))
                     seen_follows.add((u1.id, u2.id))

            FollowUser.objects.bulk_create(follows, ignore_conflicts=True)
            self.stdout.write(self.style.SUCCESS(f'Follows created.'))

            # 6. Follows (Category)
            self.stdout.write(f'Creating ~{NUM_CATEGORY_FOLLOWS} category follows...')
            cat_follows = []
            seen_cat_follows = set()
            while len(cat_follows) < NUM_CATEGORY_FOLLOWS:
                u = random.choice(all_users)
                c = random.choice(all_categories)
                if (u.id, c.id) not in seen_cat_follows:
                    cat_follows.append(FollowCategory(user=u, category=c))
                    seen_cat_follows.add((u.id, c.id))
            FollowCategory.objects.bulk_create(cat_follows, ignore_conflicts=True)

            # 7. Post Likes
            self.stdout.write(f'Creating ~{NUM_POST_LIKES} post likes...')
            post_likes = []
            seen_post_likes = set()
            while len(post_likes) < NUM_POST_LIKES:
                u = random.choice(all_users)
                p = random.choice(all_posts)
                if (u.id, p.id) not in seen_post_likes:
                    post_likes.append(LikePost(user=u, post=p))
                    seen_post_likes.add((u.id, p.id))
            LikePost.objects.bulk_create(post_likes, ignore_conflicts=True)

            # 8. Comment Likes
            self.stdout.write(f'Creating ~{NUM_COMMENT_LIKES} comment likes...')
            comment_likes = []
            seen_comment_likes = set()
            while len(comment_likes) < NUM_COMMENT_LIKES:
                u = random.choice(all_users)
                c = random.choice(all_comments)
                if (u.id, c.id) not in seen_comment_likes:
                    comment_likes.append(LikeComment(user=u, comment=c))
                    seen_comment_likes.add((u.id, c.id))
            LikeComment.objects.bulk_create(comment_likes, ignore_conflicts=True)

        self.stdout.write(self.style.SUCCESS('Done! Database seeded successfully.'))
