import requests
from django.contrib.auth.models import Group
from django.contrib.auth.signals import user_logged_in
from django.core.files import File
from django.core.files.temp import NamedTemporaryFile
from django.db import transaction
from django.db.models.signals import post_save, pre_save
from django.dispatch import receiver

from .login_history import LoginHistory
from .models import User, UserProfile


@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    """Create UserProfile for new users"""
    try:
        if created:
            # Create profile
            profile = UserProfile.objects.create(user=instance)

            # If user has a social account with avatar, download it
            social_account = instance.socialaccount_set.first()
            if social_account:
                extra_data = social_account.extra_data
                avatar_url = None

                if social_account.provider == "google":
                    avatar_url = extra_data.get("picture")
                elif social_account.provider == "discord":
                    avatar = extra_data.get("avatar")
                    discord_id = extra_data.get("id")
                    if avatar:
                        avatar_url = f"https://cdn.discordapp.com/avatars/{discord_id}/{avatar}.png"

                if avatar_url:
                    try:
                        response = requests.get(avatar_url, timeout=60)
                        if response.status_code == 200:
                            img_temp = NamedTemporaryFile(delete=True)
                            img_temp.write(response.content)
                            img_temp.flush()

                            file_name = f"avatar_{instance.username}.png"
                            profile.avatar.save(file_name, File(img_temp), save=True)
                    except Exception as e:
                        print(
                            f"Error downloading avatar for user {instance.username}: {
                                str(e)
                            }"
                        )
    except Exception as e:
        print(f"Error creating profile for user {instance.username}: {str(e)}")


@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    """Ensure UserProfile exists and is saved"""
    try:
        # Try to get existing profile first
        try:
            profile = instance.profile
            profile.save()
        except UserProfile.DoesNotExist:
            # Profile doesn't exist, create it
            UserProfile.objects.create(user=instance)
    except Exception as e:
        print(f"Error saving profile for user {instance.username}: {str(e)}")


@receiver(pre_save, sender=User)
def sync_user_role_with_groups(sender, instance, **kwargs):
    """Sync user role with Django groups"""
    if instance.pk:  # Only for existing users
        try:
            old_instance = User.objects.get(pk=instance.pk)
            if old_instance.role != instance.role:
                # Role has changed, update groups
                with transaction.atomic():
                    # Remove from old role group if exists
                    if old_instance.role != User.Roles.USER:
                        old_group = Group.objects.filter(name=old_instance.role).first()
                        if old_group:
                            instance.groups.remove(old_group)

                    # Add to new role group
                    if instance.role != User.Roles.USER:
                        new_group, _ = Group.objects.get_or_create(name=instance.role)
                        instance.groups.add(new_group)

                        # Special handling for superuser role
                        if instance.role == User.Roles.SUPERUSER:
                            instance.is_superuser = True
                            instance.is_staff = True
                        elif old_instance.role == User.Roles.SUPERUSER:
                            # If removing superuser role, remove superuser
                            # status
                            instance.is_superuser = False
                            if instance.role not in [
                                User.Roles.ADMIN,
                                User.Roles.MODERATOR,
                            ]:
                                instance.is_staff = False

                        # Handle staff status for admin and moderator roles
                        if instance.role in [
                            User.Roles.ADMIN,
                            User.Roles.MODERATOR,
                        ]:
                            instance.is_staff = True
                        elif old_instance.role in [  # noqa: SIM102
                            User.Roles.ADMIN,
                            User.Roles.MODERATOR,
                        ]:
                            # If removing admin/moderator role, remove staff
                            # status
                            if instance.role not in [User.Roles.SUPERUSER]:
                                instance.is_staff = False
        except User.DoesNotExist:
            pass
        except Exception as e:
            print(f"Error syncing role with groups for user {instance.username}: {str(e)}")


def create_default_groups():
    """
    Create default groups with appropriate permissions.
    Call this in a migration or management command.
    """
    try:
        from django.contrib.auth.models import Permission

        # Create Moderator group
        moderator_group, _ = Group.objects.get_or_create(name=User.Roles.MODERATOR)
        moderator_permissions = [
            # Review moderation permissions
            "change_review",
            "delete_review",
            "change_reviewreport",
            "delete_reviewreport",
            # Edit moderation permissions
            "change_parkedit",
            "delete_parkedit",
            "change_rideedit",
            "delete_rideedit",
            "change_companyedit",
            "delete_companyedit",
            "change_manufactureredit",
            "delete_manufactureredit",
        ]

        # Create Admin group
        admin_group, _ = Group.objects.get_or_create(name=User.Roles.ADMIN)
        admin_permissions = moderator_permissions + [
            # User management permissions
            "change_user",
            "delete_user",
            # Content management permissions
            "add_park",
            "change_park",
            "delete_park",
            "add_ride",
            "change_ride",
            "delete_ride",
            "add_company",
            "change_company",
            "delete_company",
            "add_manufacturer",
            "change_manufacturer",
            "delete_manufacturer",
        ]

        # Assign permissions to groups
        for codename in moderator_permissions:
            try:
                perm = Permission.objects.get(codename=codename)
                moderator_group.permissions.add(perm)
            except Permission.DoesNotExist:
                print(f"Permission not found: {codename}")

        for codename in admin_permissions:
            try:
                perm = Permission.objects.get(codename=codename)
                admin_group.permissions.add(perm)
            except Permission.DoesNotExist:
                print(f"Permission not found: {codename}")
    except Exception as e:
        print(f"Error creating default groups: {str(e)}")


@receiver(user_logged_in)
def log_successful_login(sender, user, request, **kwargs):
    """
    Log successful login events to LoginHistory.

    This signal handler captures the IP address, user agent, and login method
    for auditing and security purposes.
    """
    try:
        # Get IP address
        x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR")
        ip_address = x_forwarded_for.split(",")[0].strip() if x_forwarded_for else request.META.get("REMOTE_ADDR")

        # Get user agent
        user_agent = request.META.get("HTTP_USER_AGENT", "")[:500]

        # Determine login method from session or request
        login_method = "PASSWORD"
        if hasattr(request, "session"):
            sociallogin = getattr(request, "_sociallogin", None)
            if sociallogin:
                provider = sociallogin.account.provider.upper()
                if provider in ["GOOGLE", "DISCORD"]:
                    login_method = provider

        # Create login history entry
        LoginHistory.objects.create(
            user=user,
            ip_address=ip_address,
            user_agent=user_agent,
            login_method=login_method,
            success=True,
        )
    except Exception as e:
        # Don't let login history failure prevent login
        print(f"Error logging login history for user {user.username}: {str(e)}")
