from django.http import JsonResponse
from django.contrib.auth import get_user_model, login
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
import json
import random
import smtplib
from datetime import datetime, timedelta
from django.conf import settings
from django.utils import timezone
from django.shortcuts import get_object_or_404
from django.contrib.auth.models import User

from Accounts.models import UserProfile
from Device.models import Devices
from .models import CheckDevice ,OTPVerification ,DeviceDetails
# @csrf_exempt
# def check_device_view(request):
#     if request.method == 'POST':
#         try:
#             # Check if the body is empty
#             if not request.body:
#                 return JsonResponse({'error': 'Empty request body'}, status=400)

#             # Parse the JSON data from the request body
#             try:
#                 data = json.loads(request.body)
#             except json.JSONDecodeError as e:
#                 return JsonResponse({'error': 'Invalid JSON format', 'details': str(e)}, status=400)

#             # Retrieve required fields from the parsed JSON
#             user_profile_id = data.get('user_profile')
#             unique_id = data.get('unique_id')
#             mac_address = data.get('mac_address')  # Get the MAC address

#             # Validate that required fields are provided
#             if not user_profile_id or not unique_id or not mac_address:
#                 return JsonResponse({'error': 'Missing required fields: user_profile, unique_id, or mac_address'}, status=400)

#             # Check if the device is already registered for this user using unique_id and mac_address
#             existing_device = CheckDevice.objects.filter(
#                 user_profile_id=user_profile_id,
#                 device__unique_id=unique_id,
#                 device__mac_address=mac_address  # Assuming you have a mac_address field
#             ).first()

#             if existing_device:
#                 return JsonResponse({
#                     "message": "Device is already registered.",
#                     "device_info": {
#                         "unique_id": existing_device.device.unique_id,
#                         "mac_address": existing_device.device.mac_address,  # Include MAC address
#                         "user_profile_id": existing_device.user_profile_id,
#                         "registered_at": existing_device.registered_at
#                     }
#                 }, status=200)
#             else:
#                 return JsonResponse({'message': 'You have to register.'}, status=201)

#         except Exception as e:
#             return JsonResponse({'error': str(e)}, status=500)
    
#     elif request.method == 'GET':
#         try:
#             # Get all records from CheckDevice table
#             all_devices = CheckDevice.objects.all()
#             print(all_devices)
#             # Serialize the data
#             device_data = []
#             for device in all_devices:
#                 device_data.append({
#                     "unique_id": device.device.unique_id,
#                     "mac_address": device.device.mac_address,
#                     "user_profile_id": device.user_profile_id,
#                     "registered_at": device.registered_at
#                 })
            
#             # Return the serialized data
#             return JsonResponse({"all_devices": device_data}, status=200)

#         except Exception as e:
#             return JsonResponse({'error': str(e)}, status=500)
@csrf_exempt
def check_device_view(request):
    if request.method == 'POST':
        try:
            # Check if the body is empty
            if not request.body:
                return JsonResponse({'error': 'Empty request body'}, status=400)

            # Parse the JSON data from the request body
            try:
                data = json.loads(request.body)
            except json.JSONDecodeError as e:
                return JsonResponse({'error': 'Invalid JSON format', 'details': str(e)}, status=400)

            # Retrieve required fields from the parsed JSON
            user_id = data.get('user_id')  # Get the user ID
            unique_id = data.get('unique_id')  # Get the unique ID
            mac_address = data.get('mac_address')  # Get the MAC address

            # Validate that required fields are provided
            if not user_id or not unique_id or not mac_address:
                return JsonResponse({'error': 'Missing required fields: user_id, unique_id, or mac_address'}, status=400)

            # Fetch the user profile using the user ID
            try:
                user = User.objects.get(id=user_id)  # Fetch the User instance based on user_id
                user_profile = UserProfile.objects.get(user=user)  # Fetch the UserProfile based on the User
            except User.DoesNotExist:
                return JsonResponse({'error': 'User not found'}, status=404)
            except UserProfile.DoesNotExist:
                return JsonResponse({'error': 'UserProfile not found'}, status=404)

            # Check if the device is already registered for this user using unique_id and mac_address
            existing_device = CheckDevice.objects.filter(
                user_profile=user_profile,  # Filter by UserProfile instance
                device__unique_id=unique_id,
                device__mac_address=mac_address
            ).first()

            if existing_device:
                return JsonResponse({
                    "message": "Device is already registered.",
                    "device_info": {
                        "unique_id": existing_device.device.unique_id,
                        "mac_address": existing_device.device.mac_address,
                        "user_profile_id": existing_device.user_profile_id,
                        "registered_at": existing_device.registered_at
                    }
                }, status=200)
            else:
                return JsonResponse({'message': 'You have to register.'}, status=201)

        except Exception as e:
            return JsonResponse({'error': str(e)}, status=500)

    elif request.method == 'GET':
        try:
            # Get all records from CheckDevice table
            all_devices = CheckDevice.objects.all()
            # Serialize the data
            device_data = []
            for device in all_devices:
                device_data.append({
                    "unique_id": device.device.unique_id,
                    "mac_address": device.device.mac_address,
                    "user_profile_id": device.user_profile_id,
                    "registered_at": device.registered_at
                })
            
            # Return the serialized data
            return JsonResponse({"all_devices": device_data}, status=200)

        except Exception as e:
            return JsonResponse({'error': str(e)}, status=500)



#====================================================================================================================================================================================
def send_otp_to_email(email):
    otp = str(random.randint(100000, 999999))  # Generate 6-digit OTP

    # Prepare the email message
    message = f"Subject: Your OTP Code\n\nYour OTP is {otp}"

    try:
        sender_email = settings.EMAIL_HOST_USER
        sender_password = settings.EMAIL_HOST_PASSWORD
        
        # SMTP setup
        server = smtplib.SMTP(settings.EMAIL_HOST, settings.EMAIL_PORT)
        server.starttls()  # Start TLS encryption
        server.login(sender_email, sender_password)
        server.sendmail(sender_email, email, message)
        server.quit()

        return otp  # Return OTP for further processing
    except Exception as e:
        print(f"Failed to send OTP: {e}")
        return None
#=================================================================================================
# Generate a unique 6-digit OTP (for mapping)
def generate_server_otp():
    return random.randint(100000, 999999)
#================================================================================================
# @csrf_exempt
# def send_otp(request):
#     if request.method == 'POST':
#         try:
#             # Access the email from form data
#             email = request.POST.get('email')

#             # Validate that the email is provided
#             if not email:
#                 return JsonResponse({'error': 'Email is required'}, status=400)

#             # # Fetch the user by email
#             # user = get_object_or_404(UserProfile, email=email)

#             # Send OTP to email
#             if send_otp_to_email(email):
#                 return JsonResponse({"message": "OTP sent to email"}, status=200)
#             else:
#                 return JsonResponse({"error": "Failed to send OTP"}, status=500)

#         except Exception as e:
#             return JsonResponse({"error": str(e)}, status=500)

#     return JsonResponse({"error": "Invalid request method"}, status=405)

@csrf_exempt
def send_otp(request):
    if request.method == 'POST':
        try:
            # Access the email from form data
            email = request.POST.get('email')

            # Validate that the email is provided
            if not email:
                return JsonResponse({'error': 'Email is required'}, status=400)

            # Send OTP to email
            otp = send_otp_to_email(email)
            if otp:
                # Create an OTPVerification entry with the email and OTP code
                OTPVerification.objects.create(email=email, otp_code=otp)

                return JsonResponse({"message": "OTP sent to email"}, status=200)
            else:
                return JsonResponse({"error": "Failed to send OTP"}, status=500)

        except Exception as e:
            return JsonResponse({"error": str(e)}, status=500)

    return JsonResponse({"error": "Invalid request method"}, status=405)




#========================================================================================================================================
@csrf_exempt
def re_registration(request):
    if request.method == 'POST':
        try:
            # Access the email from form data
            email = request.POST.get('email')

            # Validate that the email is provided
            if not email:
                return JsonResponse({'error': 'Email is required'}, status=400)

            # Fetch the user by email
            user = get_object_or_404(UserProfile, email=email)

            # You can add additional logic here if needed for re-registration
            
            # Send OTP to email
            if send_otp_to_email(email, user):
                return JsonResponse({"message": "OTP sent for re-registration to email"}, status=200)
            else:
                return JsonResponse({"error": "Failed to send OTP"}, status=500)

        except Exception as e:
            return JsonResponse({"error": str(e)}, status=500)

    return JsonResponse({"error": "Invalid request method"}, status=405)
#==================================================================================================================================
# @csrf_exempt
# def verify_otp(request):
#     if request.method == 'POST':
#         try:
#             # Retrieve email and otp_code from POST request
#             email = request.POST.get('email')
#             otp_code = request.POST.get('otp_code')

#             # Debugging: Print email and OTP code received
#             print(f"Email: {email}, OTP Code: {otp_code}")

#             # Validate that both fields are provided
#             if not email or not otp_code:
#                 return JsonResponse({'error': 'Email and OTP code are required'}, status=400)

#             # Retrieve the most recent OTPVerification entry for the email
#             otp_verification = OTPVerification.objects.filter(email=email).order_by('-created_at').first()

#             # If an OTP exists, debug its stored values
#             if otp_verification:
#                 print(f"Stored OTP: {otp_verification.otp_code}, Is Valid: {otp_verification.is_valid}")

#             # Check if the OTP exists, matches the submitted OTP, and is valid
#             if otp_verification and str(otp_verification.otp_code) == str(otp_code) and otp_verification.is_valid:
#                 # Mark the OTP as used (is_valid = False)
#                 otp_verification.is_valid = False
#                 otp_verification.save()

#                 return JsonResponse({"message": "OTP verified successfully"}, status=200)
#             else:
#                 return JsonResponse({"error": "Invalid or expired OTP"}, status=400)

#         except Exception as e:
#             return JsonResponse({"error": str(e)}, status=500)

#     return JsonResponse({"error": "Invalid request method"}, status=405)


@csrf_exempt
def verify_otp(request):
    if request.method == 'POST':
        try:
            # Retrieve email and otp_code from POST request
            email = request.POST.get('email')
            otp_code = request.POST.get('otp_code')

            # Debugging: Print email and OTP code received
            print(f"Email: {email}, OTP Code: {otp_code}")

            # Validate that both fields are provided
            if not email or not otp_code:
                return JsonResponse({'error': 'Email and OTP code are required'}, status=400)

            # Retrieve the most recent OTPVerification entry for the email
            otp_verification = OTPVerification.objects.filter(email=email).order_by('-created_at').first()

            # If an OTP exists, debug its stored values
            if otp_verification:
                print(f"Stored OTP: {otp_verification.otp_code}, Is Valid: {otp_verification.is_valid}, Is Expired: {otp_verification.is_expired()}")

            # Check if the OTP exists, matches the submitted OTP, and is valid, and not expired
            if (otp_verification and 
                str(otp_verification.otp_code) == str(otp_code) and 
                otp_verification.is_valid and 
                not otp_verification.is_expired()):
                
                # Mark the OTP as used (is_valid = False)
                otp_verification.is_valid = False
                otp_verification.save()

                return JsonResponse({"message": "OTP verified successfully"}, status=200)
            else:
                return JsonResponse({"error": "Invalid or expired OTP"}, status=400)

        except Exception as e:
            return JsonResponse({"error": str(e)}, status=500)

    return JsonResponse({"error": "Invalid request method"}, status=405)





#====================================================================================================================================
@csrf_exempt
def register_device(request):
    if request.method == 'POST':
        try:
            print("Received POST request")

            if not request.POST:
                print("Request body is empty")
                return JsonResponse({'error': 'Empty request body'}, status=400)

            print(f"Request data: {request.POST}")

            # Retrieve required fields from the form data
            user_profile_id = int(request.POST.get('user_profile_id'))  # Convert to int
            mac_address = request.POST.get('mac_address')
            unique_id = request.POST.get('unique_id')

            print(f"user_profile_id: {user_profile_id}, mac_address: {mac_address}, unique_id: {unique_id}")
            # Convert user_profile_id to an integer
            user_profile_id = int(user_profile_id)
            print(f"User Profile ID (as integer): {user_profile_id}, Type: {type(user_profile_id)}")

            # Validate that required fields are provided
            if not user_profile_id or not mac_address or not unique_id:
                print("Missing required fields")
                return JsonResponse({'error': 'Missing required fields: user_profile_id, mac_address, or unique_id'}, status=400)

            print(f"All UserProfiles: {UserProfile.objects.all()}")  # Print all UserProfiles
            print(f"UserProfile count: {UserProfile.objects.count()}")  # Count of UserProfiles

            # Fetch the user profile by ID
            print(f"Fetching UserProfile with ID: {user_profile_id}")
            user_profile = get_object_or_404(UserProfile, id=user_profile_id)
            print(f"UserProfile found: {user_profile}")

            # Create or fetch the device instance
            print(f"Fetching or creating device with MAC address: {mac_address}")
            device, created = Devices.objects.get_or_create(
                mac_address=mac_address,
                defaults={'unique_id': unique_id}
            )
            if created:
                print(f"New device created with unique_id: {unique_id}")
            else:
                print(f"Existing device found with MAC address: {mac_address}")

            # Create a CheckDevice entry
            print("Creating CheckDevice entry")
            check_device = CheckDevice.objects.create(user_profile=user_profile, device=device)

            print("Device registered successfully")
            return JsonResponse({
                'message': 'Device registered successfully.',
                'device_info': {
                    'unique_id': check_device.device.unique_id,
                    'mac_address': check_device.device.mac_address,
                    'registered_at': check_device.registered_at
                }
            }, status=201)

        except Exception as e:
            print(f"Error: {str(e)}")
            return JsonResponse({'error': str(e)}, status=500)

    print("Invalid request method")
    return JsonResponse({'error': 'Invalid request method'}, status=405)



#========================================================================================================================
@csrf_exempt
# def generate_second_otp(request):
#     if request.method == 'POST':
#         # Extract the email from request parameters (query string)
#         email = request.POST.get('email')

#         if not email:
#             return JsonResponse({'error': 'Email is required'}, status=400)

#         try:
#             # Fetch the associated UserProfile instance by email
#             user_profile = UserProfile.objects.get(email=email)

#             # Generate the second OTP
#             second_otp = generate_server_otp()

#             # Save the OTP to the OTPVerification model
#             otp_verification = OTPVerification.objects.create(
#                 email=user_profile,  # Set the foreign key relation to UserProfile
#                 second_otp=second_otp
#             )

#             return JsonResponse({
#                 'second_otp': otp_verification.second_otp,
#                 'message': 'Second OTP generated and saved successfully.'
#             }, status=200)

#         except UserProfile.DoesNotExist:
#             return JsonResponse({'error': 'UserProfile not found'}, status=404)

def generate_second_otp(request):
    if request.method == 'POST':
        email = request.POST.get('email')
        
        try:
            # Get the user object by email
            user = User.objects.get(email=email)

            # Get the user profile associated with this user
            user_profile = UserProfile.objects.get(user=user)

            # Logic to generate the second OTP
            second_otp = generate_server_otp()  # Example OTP generation logic

            # Create a new OTPVerification record
            otp_record = OTPVerification(
                user_profile=user_profile,
                second_otp=second_otp,
                is_valid=True,
                created_at=timezone.now()  # Set current time as created time
            )
            otp_record.save()  # Save the record to the database

            # Send the second OTP and user profile ID in the response
            return JsonResponse({
                "second_otp": second_otp,
                "user_profile_id": user_profile.id  # Return the user profile ID
            })
        except User.DoesNotExist:
            return JsonResponse({"error": "User not found."}, status=404)
        except UserProfile.DoesNotExist:
            return JsonResponse({'error': 'UserProfile not found'}, status=404)
    return JsonResponse({"error": "Invalid request method."}, status=405)
#============================================================================================================================
# @csrf_exempt
# def verify_second_otp(request):
#     if request.method == 'POST':
#         second_otp = request.POST.get('second_otp')
#         print(second_otp)

#         if not second_otp:
#             return JsonResponse({"error": "Second OTP is required"}, status=400)

#         # Find the OTP record with the provided second OTP and that is still valid
#         otp_record = OTPVerification.objects.filter(second_otp=second_otp, is_valid=True).first()
#         print(otp_record)

#         if otp_record:
#             # Check if OTP is not older than 10 minutes
#             if otp_record.created_at >= (timezone.now() - timedelta(minutes=10)):
#                 # Mark OTP as used (invalid)
#                 otp_record.is_valid = False
#                 otp_record.save()

#                 return JsonResponse({"message": "Second OTP is valid"}, status=200)
#             else:
#                 return JsonResponse({"error": "OTP expired"}, status=400)
#         else:
#             return JsonResponse({"error": "Invalid or used Second OTP"}, status=400)
#     return JsonResponse({"error": "Invalid request method"}, status=405)
@csrf_exempt
def verify_second_otp(request):
    if request.method == 'POST':
        second_otp = request.POST.get('second_otp')

        if not second_otp:
            return JsonResponse({"error": "Second OTP is required"}, status=400)

        # Find the OTP record with the provided second OTP and that is still valid
        otp_record = OTPVerification.objects.filter(second_otp=second_otp, is_valid=True).first()

        if otp_record:
            # Check if OTP is not older than 10 minutes
            if otp_record.created_at >= (timezone.now() - timedelta(minutes=10)):
                # Mark OTP as used (invalid)
                otp_record.is_valid = False
                otp_record.save()

                if otp_record.user_profile:
                    # Return the user_profile_id from the OTP record
                    return JsonResponse({
                        "message": "Second OTP is valid",
                        "user_profile_id": otp_record.user_profile.user.id
                    }, status=200)
                else:
                    return JsonResponse({"error": "No user profile associated with this OTP record."}, status=400)
            else:
                return JsonResponse({"error": "OTP expired"}, status=400)
        else:
            return JsonResponse({"error": "Invalid or used Second OTP"}, status=400)
    
    return JsonResponse({"error": "Invalid request method"}, status=405)

#===============================================================================================================================================
# @csrf_exempt  # Disable CSRF protection; use with caution
# def send_device_info(request):
#     if request.method == 'POST':
#         second_otp = request.POST.get('second_otp')
#         email = request.POST.get('email')
        

#         if not second_otp or not email :
#             return JsonResponse({"error": "Second OTP, email, and   are required"}, status=400)

#         try:
#             # Extract data from the request body
#             user_id = request.POST.get('user_id')  # This should be the User ID, not UserProfile ID
#             mac_address = request.POST.get('mac_address')  # Extract mac_address from the request
#             unique_id = request.POST.get('unique_id')  # Extract unique_id from the request

#             # Fetch the user instance directly from User model
#             user = User.objects.get(id=user_id)  # Retrieve User instance based on user_id
            
#             # Fetch the user profile based on the user instance
#             user_profile = UserProfile.objects.get(user=user)  # Retrieve UserProfile based on the user instance
            
#             # Create or fetch the device instance
#             print(f"Fetching or creating device with MAC address: {mac_address}")
#             device, created = Devices.objects.get_or_create(
#                 mac_address=mac_address,
#                 defaults={'unique_id': unique_id,
#                           'used_by': user_profile } # Set the used_by field to the current user profile
#             )
#             if created:
#                 print(f"New device created with unique_id: {unique_id}")
#             else:
#                 print(f"Existing device found with MAC address: {mac_address}")

#             # Create a CheckDevice entry
#             print("Creating CheckDevice entry")
#             check_device = CheckDevice.objects.create(
#                 user_profile=user_profile,
#                 device=device,
#                 registered_at=timezone.now()  # Automatically set the registration time
#             )
            
#             # Prepare a response with the created device info
#             response_data = {
#                 'user_id': check_device.user_profile.user.id,
#                 'mac_address': check_device.mac_address,
#                 'unique_id': check_device.unique_id,
#             }

#             return JsonResponse(response_data, status=201)  # Return success response with created device info

#         except UserProfile.DoesNotExist:
#             return JsonResponse({"error": "UserProfile not found"}, status=404)

#     return JsonResponse({"error": "Invalid request method"}, status=405)


#==============================================================================================================================================




# @csrf_exempt  # Disable CSRF protection; use with caution
# def send_device_info(request):
#     if request.method == 'POST':
#         try:
#             # Extract data from the request body
#             data = json.loads(request.body)  # Parse the incoming JSON data
#             user_id = data.get('user_id')  # Get the User ID
#             mac_address = data.get('mac_address')  # Get the MAC address
#             unique_id = data.get('unique_id')  # Get the Unique ID

#             # Validate that required fields are provided
#             if not user_id or not mac_address or not unique_id:
#                 return JsonResponse({'error': 'Missing required fields: user_id, mac_address, or unique_id'}, status=400)

#             # Fetch the user instance directly from User model
#             user = User.objects.get(id=user_id)  # Retrieve User instance based on user_id
#             print (user)
            
#             # Fetch the user profile based on the user instance
#             user_profile = UserProfile.objects.get(user=user)  # Retrieve UserProfile based on the user instance
#             print(user_profile)
            
#             # Create or fetch the device instance
#             device, created = Devices.objects.get_or_create(
#                 mac_address=mac_address,
#                 defaults={'unique_id': unique_id,
#                           'used_by': user_profile}  # Set the used_by field to the current user profile
#             )

#             # Create a CheckDevice entry with user.id directly
#             check_device = CheckDevice.objects.create(
#                 user_profile=user_profile,  # This still references the UserProfile
#                 device=device,
#                 registered_at=timezone.now()  # Automatically set the registration time
#             )

#             # Prepare a response with the created device info
#             response_data = {
#                 'user_id': user.id,  # Include the User ID from the User model
#                 'user_profile_id': user_profile.id,  # Include the UserProfile ID  # Include the User ID
#                 'mac_address': device.mac_address,  # Get MAC address from the device
#                 'unique_id': device.unique_id,  # Get Unique ID from the device
#                 'registered_at': check_device.registered_at,  # Include registration timestamp
#             }

#             return JsonResponse(response_data, status=200
#                                 )  # Return success response with created device info

#         except UserProfile.DoesNotExist:
#             return JsonResponse({'error': 'UserProfile not found'}, status=404)
#         except User.DoesNotExist:
#             return JsonResponse({'error': 'User not found'}, status=404)
#         except json.JSONDecodeError:
#             return JsonResponse({'error': 'Invalid JSON format'}, status=400)
#         except Exception as e:
#             return JsonResponse({'error': str(e)}, status=500)  # Return error message for any other exceptions

#     return JsonResponse({'error': 'Invalid request method'}, status=405)

@csrf_exempt  # Disable CSRF protection; use with caution
def send_device_info(request):
    if request.method == 'POST':
        try:
            # Extract data from the request body
            data = json.loads(request.body)  # Parse the incoming JSON data
            user_profile_id = data.get('user_profile_id')  # Get the User Profile ID
            mac_address = data.get('mac_address')  # Get the MAC address
            unique_id = data.get('unique_id')  # Get the Unique ID

            # Validate that required fields are provided
            if not user_profile_id or not mac_address or not unique_id:
                return JsonResponse({'error': 'Missing required fields: user_profile_id, mac_address, or unique_id'}, status=400)

            # Fetch the user profile directly from UserProfile model
            user_profile = UserProfile.objects.get(id=user_profile_id)  # Retrieve UserProfile instance based on user_profile_id
            
            # Print for debugging
            print(user_profile)
            
            # Create or fetch the device instance
            device, created = Devices.objects.get_or_create(
                mac_address=mac_address,
                defaults={'unique_id': unique_id,
                          'used_by': user_profile}  # Set the used_by field to the current user profile
            )

            # Create a CheckDevice entry with user_profile directly
            check_device = CheckDevice.objects.create(
                user_profile=user_profile,  # This references the UserProfile
                device=device,
                registered_at=timezone.now()  # Automatically set the registration time
            )

            # Prepare a response with the created device info
            response_data = {
                'user_profile_id': user_profile.id,  # Include the UserProfile ID
                'mac_address': device.mac_address,  # Get MAC address from the device
                'unique_id': device.unique_id,  # Get Unique ID from the device
                'registered_at': check_device.registered_at,  # Include registration timestamp
            }

            return JsonResponse(response_data, status=200)  # Return success response with created device info

        except UserProfile.DoesNotExist:
            return JsonResponse({'error': 'UserProfile not found'}, status=404)
        except json.JSONDecodeError:
            return JsonResponse({'error': 'Invalid JSON format'}, status=400)
        except Exception as e:
            return JsonResponse({'error': str(e)}, status=500)  # Return error message for any other exceptions

    return JsonResponse({'error': 'Invalid request method'}, status=405)



def get_user_id(request):
    user_id = request.session.get('user_id')  # Retrieve user ID from session
    if user_id:
        return JsonResponse({"user_id": user_id}, status=200)
    else:
        return JsonResponse({"error": "User ID not found"}, status=404)