from bson import ObjectId,errors
from flask import Blueprint
from flask_restful import Resource, Api, reqparse
from models.user import User
from models.image import Image
from models.user_referral import UserReferral
from models.quiz_share import QuizShare
from test import SECRET
from utils.sms_service import send_sms
from utils.email_service import send_email
from werkzeug.security import generate_password_hash
import random
import string
import re
from datetime import datetime
from mongoengine import ValidationError
from werkzeug.security import check_password_hash
import os
from utils.jwt_service import generate_token
from utils.jwt_service import jwt_required
from flask import request, current_app, jsonify
from werkzeug.utils import secure_filename
import jwt
import hashlib
from models.slider import Slider
import time
import requests
import logging
from urllib.parse import urlparse
from models.exam import Exam
from models.exam import  StudyMaterial
from models.notification_model import Notification
from mongoengine.errors import NotUniqueError, ValidationError
from models.eduruby_configuration import EdurubyConfiguration
from models.transaction_history import TransactionHistory
from mongoengine.errors import NotUniqueError



# Setup logger
logger = logging.getLogger(__name__)

# Create Blueprint
auth_bp = Blueprint('auth', __name__)
auth_api = Api(auth_bp)

class Register(Resource):
    parser = reqparse.RequestParser()
    parser.add_argument('mobile_no', type=str, required=False)
    parser.add_argument('name', type=str, required=False)
    parser.add_argument('email', type=str, required=False)
    parser.add_argument('password', type=str, required=False)
    parser.add_argument('confirm_password', type=str, required=False)
    parser.add_argument('register_type', type=str, required=True, help='Select user type')
    parser.add_argument('refer_by', type=str, required=False)
    parser.add_argument('shared_quiz_id', type=str, required=False)

    def validate_email(self, email):
        email_regex = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
        return bool(re.match(email_regex, email))

    def generate_referral_code(self, length=8, max_attempts=10):
        for _ in range(max_attempts):
            code = ''.join(random.choices(string.ascii_uppercase + string.digits, k=length))
            if not User.objects(referral_code=code).first():
                return code
        raise Exception("Failed to generate unique referral code")

    def post(self):
        logger.debug("📩 Reached Register POST endpoint")
        data = self.parser.parse_args()

        # --- Validate input ---
        if not data['mobile_no'] and not data['email']:
            return {'status': False, 'message': 'Mobile number or email is required'}, 400

        if data['mobile_no']:
            if not data['password'] or not data['confirm_password']:
                return {'status': False, 'message': 'Enter password and confirm password'}, 400
            if data['password'] != data['confirm_password']:
                return {'status': False, 'message': 'Password and Confirm Password do not match'}, 400
            if User.objects(phone=data['mobile_no']).first():
                return {'status': False, 'message': 'Mobile number already exists'}, 400

        if data['email']:
            if not self.validate_email(data['email']):
                return {'status': False, 'message': 'Enter a valid email'}, 400
            if not data['name']:
                return {'status': False, 'message': 'Enter name'}, 400
            if not data['password'] or not data['confirm_password']:
                return {'status': False, 'message': 'Enter password and confirm password'}, 400
            if data['password'] != data['confirm_password']:
                return {'status': False, 'message': 'Password and Confirm Password do not match'}, 400
            if User.objects(email=data['email']).first():
                return {'status': False, 'message': 'Email already exists'}, 400

        reg_type = data['register_type']

        # --- OTP ---
        otp = str(random.randint(10000, 99999))

        user_data = {
            'name': data['name'],
            'user_type': reg_type,
            'password': generate_password_hash(data['password']) if data['password'] else None,
            'referral_code': self.generate_referral_code(),
            'status': 0,  # inactive until OTP/email verified
            'created_date': datetime.utcnow(),
            'login_otp': otp,
            'coins_wallet_balance': 0
        }

        if data.get('mobile_no'):
            user_data['phone'] = data['mobile_no']
            sms_response = send_sms(data['mobile_no'], otp)
            if not sms_response['status']:
                return {'status': False, 'message': 'Failed to send OTP due to server error.'}, 500

        if data.get('email'):
            user_data['email'] = data['email']
            user_data['is_email_verified'] = 0
            email_response = send_email(data['email'], otp, reg_type)
            if not email_response['status']:
                return {'status': False, 'message': 'Failed to send OTP via email.'}, 500

        # --- Save new user ---
        try:
            user = User(**user_data).save()
        except NotUniqueError:
            return {'status': False, 'message': 'Duplicate user found'}, 400
        except ValidationError as e:
            return {'status': False, 'message': f'Validation failed: {str(e)}'}, 400
        except Exception as e:
            return {'status': False, 'message': f'Unexpected error: {str(e)}'}, 500

        # --- If referral code supplied, just record the relation now (no coins yet) ---
        if data.get('refer_by'):
            referrer = User.objects(referral_code=data['refer_by']).first()
            if not referrer:
                return {'status': False, 'message': 'Invalid referral code'}, 401
            if referrer.status == 0:
                return {'status': False, 'message': 'Referral user is not active. Kindly verify OTP.'}, 403

            # Save referral record for later bonus at activation
            UserReferral(
                user_id=user,
                referred_by_user_id=referrer,
                # points can be computed at activation; store 0 or omit if your model allows
                points=0,
                created_date=datetime.utcnow()
            ).save()

        # --- Shared quiz ---
        if data.get('shared_quiz_id'):
            image = Image.objects(id=data['shared_quiz_id']).first()
            if not image:
                return {'status': False, 'message': 'Invalid quiz id'}, 401
            QuizShare(
                shared_by_user_id=image.user_id,
                quiz_id=image,
                user_id=user,
                created_date=datetime.utcnow()
            ).save()

        message = (
            f"OTP sent successfully, verify your mobile number."
            if data.get('mobile_no')
            else f"OTP sent to your email address."
        )

        return {
            'status': True,
            'message': message,
            'last_id': str(user.id)
        }, 201
auth_api.add_resource(Register, '/register')

class VerifyOTP(Resource):
    parser = reqparse.RequestParser()
    parser.add_argument('userid', type=str, required=True, help='Enter user id')
    parser.add_argument('otp', type=str, required=True, help='Enter OTP')
    parser.add_argument('type', type=str, required=True, help='Enter type (otp/email/forget)')

    def post(self):
        data = self.parser.parse_args()
        user = User.objects(id=data['userid']).first()

        if not user:
            return {'status': False, 'message': 'User id not exists.'}, 404

        # Pre-check already verified
        if data['type'] == 'otp' and user.status == 1:
            return {'status': False, 'message': 'User already verified.'}, 409
        if data['type'] == 'email' and user.is_email_verified:
            return {'status': False, 'message': 'Email already verified.'}, 409

        if user.login_otp != data['otp']:
            return {'status': False, 'message': 'Invalid OTP.'}, 401

        # Flip flags
        if data['type'] == 'otp':
            user.update(set__status=1)
            msg = 'OTP verified successfully'
        elif data['type'] == 'email':
            user.update(set__is_email_verified=1, set__status=1)
            msg = 'Email verified successfully'
        elif data['type'] == 'forget':
            msg = 'Otp verified successfully. Continue to reset password'
            # No activation here; no bonuses
            updated_user = User.objects(id=data['userid']).first().to_json()
            return {'status': True, 'message': msg, 'user': updated_user}, 200
        else:
            user.update(set__status=1)
            msg = 'OTP verified successfully'

        # Reload fresh user (now active)
        user = User.objects(id=data['userid']).first()

        # --- CREDIT BONUSES NOW (once) ---
        cfg = EdurubyConfiguration.objects.order_by('-created_date').first()
        if cfg:
            # 1) Signup bonus to the user (once)
            signup_bonus = int(cfg.user_signup_bonus_coins or 0)
            already_signup = TransactionHistory.objects(
                user_id=user, transaction_type='signup_bonus'
            ).first()

            if signup_bonus > 0 and not already_signup:
                ub_before = int(user.coins_wallet_balance or 0)
                ub_after = ub_before + signup_bonus
                user.coins_wallet_balance = ub_after
                user.save()
                TransactionHistory(
                    user_id=user,
                    transaction_type='signup_bonus',
                    entry_type='credit',
                    amount=signup_bonus,
                    description=f"Signup bonus: {signup_bonus} coins credited after account activation",
                    related_user_id=None,
                    balance_before=ub_before,
                    balance_after=ub_after,
                    transaction_status=1
                ).save()

            # 2) Referral bonus to referrer (once, if referral exists)
            # Try to resolve referrer: from UserReferral or user.refer_by
            ref_rel = UserReferral.objects(user_id=user).first()
            referrer = ref_rel.referred_by_user_id if ref_rel else (
                User.objects(referral_code=user.refer_by).first() if user.refer_by else None
            )

            if referrer:
                if user.user_type == 'Learner':
                    ref_points = int(cfg.learner_signup_referral_coins or 0)
                elif user.user_type == 'Teacher':
                    ref_points = int(cfg.teacher_signup_referral_coins or 0)
                else:
                    ref_points = 0

                # Ensure not already credited for this user
                already_ref = TransactionHistory.objects(
                    user_id=referrer,
                    transaction_type='referral_bonus',
                    related_user_id=user
                ).first()

                if ref_points > 0 and not already_ref:
                    rb_before = int(referrer.coins_wallet_balance or 0)
                    rb_after = rb_before + ref_points
                    referrer.coins_wallet_balance = rb_after
                    referrer.save()

                    # aggregates
                    inc_ops = {'inc__total_referrals': 1}
                    inc_ops['inc__total_referral_points'] = ref_points
                    if user.user_type == 'Learner':
                        inc_ops['inc__referral_points_learner'] = ref_points
                    else:
                        inc_ops['inc__referral_points_teacher'] = ref_points
                    try:
                        referrer.modify(**inc_ops)
                    except Exception as e:
                        logger.error(f"Failed to update referrer aggregates: {e}")

                    TransactionHistory(
                        user_id=referrer,
                        transaction_type='referral_bonus',
                        entry_type='credit',
                        amount=ref_points,
                        description=f"Referral bonus: {ref_points} coins received for referring a {user.user_type.lower()} signup",
                        related_user_id=user,
                        balance_before=rb_before,
                        balance_after=rb_after,
                        transaction_status=1
                    ).save()

        updated_user = User.objects(id=data['userid']).first().to_json()
        return {'status': True, 'message': msg, 'user': updated_user}, 200

auth_api.add_resource(VerifyOTP, '/verifyotp')


# class VerifyEmail(Resource):
#     parser = reqparse.RequestParser()
#     parser.add_argument('userid', type=str, required=True, help='Enter user id')
#     parser.add_argument('otp', type=str, required=True, help='Enter OTP')

#     def post(self):
#         data = self.parser.parse_args()
#         user = User.objects(id=data['userid']).first()

#         if not user:
#             return {'status': False, 'message': 'User id not exists.'}, 404

#         if user.is_email_verified:
#             return {'status': False, 'message': 'Email already verified.'}, 409

#         if user.login_otp != data['otp']:
#             return {'status': False, 'message': 'Invalid OTP.'}, 401

#         user.update(set__is_email_verified=True, set__status=1)
#         updated_user = User.objects(id=data['userid']).first().to_json()
#         return {
#             'status': True,
#             'message': 'Email verified successfully.',
#             'user': updated_user
#         }, 200

# auth_api.add_resource(VerifyEmail, '/verify-email')
class ResetPassword(Resource):
    parser = reqparse.RequestParser()
    parser.add_argument('userid', type=str, required=True, help='Enter user id')
    parser.add_argument('password', type=str, required=True, help='Enter password')
    parser.add_argument('confirm_password', type=str, required=True, help='Enter confirm password')

    def post(self):
        data = self.parser.parse_args()

        password = data['password'].strip()
        confirm_password = data['confirm_password'].strip()

        if not password and not confirm_password:
            return {
                'status': False,
                'message': 'Password and Confirm Password cannot be empty'
            }, 400

        if not password:
            return {
                'status': False,
                'message': 'Password cannot be empty'
            }, 400

        if not confirm_password:
            return {
                'status': False,
                'message': 'Confirm Password cannot be empty'
            }, 400

        if password != confirm_password:
            return {
                'status': False,
                'message': 'Password and Confirm Password do not match'
            }, 400

        user = User.objects(id=data['userid']).first()
        if not user:
            return {
                'status': False,
                'message': 'Invalid user id.'
            }, 404

        hashed_password = generate_password_hash(password)
        user.update(set__password=hashed_password)

        return {
            'status': True,
            'message': 'Password reset successfully'
        }, 200

auth_api.add_resource(ResetPassword, '/reset-password')



class Login(Resource):
    parser = reqparse.RequestParser()
    parser.add_argument('mobile_no', type=str, required=False)
    parser.add_argument('email', type=str, required=False)
    parser.add_argument('password', type=str, required=True, help='Enter password')
    parser.add_argument('shared_quiz_id', type=str, required=False)

    def post(self):
        data = self.parser.parse_args()

        mobile_no = data.get("mobile_no")
        email = data.get("email")
        password = data.get("password")
        shared_quiz_id = data.get("shared_quiz_id")

        if not mobile_no and not email:
            return {
                'status': False,
                'message': 'Mobile number or email is required'
            }, 400

        # Lookup field config
        if mobile_no:
            lookup_field = "phone"
            lookup_value = mobile_no
            missing_msg = "Mobile number not exists."
        else:
            lookup_field = "email"
            lookup_value = email
            missing_msg = "Email not exists."

        user = User.objects(**{lookup_field: lookup_value}).first()
        if not user:
            return {
                'status': False,
                'message': missing_msg
            }, 404

        if not user.password:
            return {
                'status': False,
                'message': 'Password is not set for this account.'
            }, 401

        if not check_password_hash(user.password, password):
            return {
                'status': False,
                'message': 'Password is incorrect.'
            }, 401

        # Check for deleted account
        if user.is_deleted == 1:
            return {
                'status': False,
                'message': 'Account is deleted.'
            }, 401

        # Unverified or deactivated users → resend OTP
        if user.status != 1:
            otp = str(random.randint(10000, 99999))
            user.update(set__login_otp=otp)

            if email:
                if not user.is_email_verified:
                    email_response = send_email(email, otp, user.user_type or 'Learner')
                    if not email_response['status']:
                        return {
                            'status': False,
                            'message': 'OTP sending failed for email.'
                        }, 500

                    return {
                        'status': False,
                        'message': 'Verify your email to login.',
                        'user_id': str(user.id),
                        'type': 'email'
                    }, 401
                else:
                    return {
                        'status': False,
                        'message': 'Account is deactivated.',
                        'user_id': str(user.id),
                        'type': 'email'
                    }, 401

            elif mobile_no:
                sms_response = send_sms(mobile_no, otp)
                if not sms_response['status']:
                    return {
                        'status': False,
                        'message': 'OTP sending failed for mobile.'
                    }, 500

                return {
                    'status': False,
                    'message': 'Verify your mobile number to login.',
                    'user_id': str(user.id),
                    'type': 'otp'
                }, 401

        # Prepare user dict (safe for JSON)
        user_dict = user.to_mongo().to_dict()
        user_dict.pop("password", None)
        user_dict.pop("login_otp", None)
        user_dict["_id"] = str(user_dict["_id"])
        if "created_date" in user_dict and user_dict["created_date"]:
            user_dict["created_date"] = user_dict["created_date"].strftime('%Y-%m-%d %H:%M:%S')

        # JWT Token
        token_payload = {
            "id": str(user.id),
            "email": user.email,
            "role": user.user_type or 'Learner'
        }
        token = generate_token(token_payload)

        # Fetch referrals
        referrals = []
        if user.referral_code:
            referred_users = User.objects(refer_by=user.referral_code)
            for ref_user in referred_users:
                ref_user_data = ref_user.to_mongo().to_dict()
                ref_user_data.pop("password", None)
                ref_user_data.pop("login_otp", None)
                ref_user_data["_id"] = str(ref_user_data["_id"])
                if "created_date" in ref_user_data and ref_user_data["created_date"]:
                    ref_user_data["created_date"] = ref_user_data["created_date"].strftime('%Y-%m-%d %H:%M:%S')
                referrals.append(ref_user_data)

        # Handle shared quiz
        if shared_quiz_id:
            image = Image.objects(id=shared_quiz_id).first()
            if not image:
                return {
                    'status': False,
                    'message': 'Invalid quiz id'
                }, 401

            QuizShare(
                shared_by_user_id=image.user_id,
                quiz_id=image,
                user_id=user,
                created_at=datetime.utcnow()  # DateTimeField expects datetime object
            ).save()

        # Final response
        response = {
            'status': True,
            'message': 'Login successfully.',
            'token': token,
            'user': user_dict,
            'referrals': referrals
        }
        return response, 200
auth_api.add_resource(Login, '/login')



# class Profile(Resource):
#     @jwt_required
#     def get(self):
#         user_id = getattr(request, "user_id", None)

#         if not user_id:
#             return {
#                 "status": False,
#                 "message": "Pass user id"
#             }, 401

#         user = User.objects(id=user_id).first()
#         if not user:
#             return {
#                 "status": False,
#                 "message": "Invalid user id"
#             }, 404

#         user_data = user.to_mongo().to_dict()
#         user_data["id"] = str(user_data["_id"])
#         user_data.pop("_id", None)
#         user_data.pop("password", None)
#         user_data.pop("login_otp", None)

#         referrals = []
#         if user_data.get("referral_code"):
#             referral_users = User.objects(refer_by=user_data["referral_code"])
#             for ref_user in referral_users:
#                 ref_data = ref_user.to_mongo().to_dict()
#                 ref_data["id"] = str(ref_data["_id"])
#                 ref_data.pop("_id", None)
#                 ref_data.pop("password", None)
#                 ref_data.pop("login_otp", None)
#                 referrals.append(ref_data)

#         return {
#             "status": True,
#             "message": "Profile information fetched successfully",
#             "user": user_data,
#             "referrals": referrals
#         }, 200

class Profile(Resource):
    @jwt_required
    def get(self):
        user_id = getattr(request, "user_id", None)

        if not user_id:
            return {
                "status": False,
                "message": "Pass user id"
            }, 401

        user = User.objects(id=user_id).first()
        if not user:
            return {
                "status": False,
                "message": "Invalid user id"
            }, 404

        # Prepare main user data
        user_data = user.to_mongo().to_dict()
        user_data["id"] = str(user_data["_id"])
        user_data.pop("_id", None)
        user_data.pop("password", None)
        user_data.pop("login_otp", None)

        # Fix datetime for created_date
        if "created_date" in user_data and user_data["created_date"]:
            user_data["created_date"] = user_data["created_date"].strftime('%Y-%m-%d %H:%M:%S')

        # Prepare referrals list
        referrals = []
        if user_data.get("referral_code"):
            referral_users = User.objects(refer_by=user_data["referral_code"])
            for ref_user in referral_users:
                ref_data = ref_user.to_mongo().to_dict()
                ref_data["id"] = str(ref_data["_id"])
                ref_data.pop("_id", None)
                ref_data.pop("password", None)
                ref_data.pop("login_otp", None)

                if "created_date" in ref_data and ref_data["created_date"]:
                    ref_data["created_date"] = ref_data["created_date"].strftime('%Y-%m-%d %H:%M:%S')

                referrals.append(ref_data)

        return {
            "status": True,
            "message": "Profile information fetched successfully",
            "user": user_data,
            "referrals": referrals
        }, 200

auth_api.add_resource(Profile, "/profile")



class ForgotPassword(Resource):
    parser = reqparse.RequestParser()
    parser.add_argument('email', type=str, required=True, help='Enter email')

    def post(self):
        data = self.parser.parse_args()

        email = data.get('email')

        user = User.objects(email=email).first()
        if not user:
            return {
                'status': False,
                'message': 'Email does not exists in our record.'
            }, 404

        # Generate OTP
        new_random = str(random.randint(10000, 99999))
        user.update(set__login_otp=new_random)

        # Send email using your email service
        email_response = send_email(
            to_email=email,
            otp=new_random,
            user_type='Forget Password'
        )

        if not email_response['status']:
            return {
                'status': False,
                'message': 'Failed to send OTP email.'
            }, 500

        return {
            'status': True,
            'message': f'Enter code sent to your registered email',
            'user_id': str(user.id)
        }, 200

auth_api.add_resource(ForgotPassword, '/forget-password')



from utils.auth_middleware import auth_required

class UpdateProfile(Resource):
    @auth_required
    def post(self):
        user_id = getattr(request, "user_id", None)
        if not user_id:
            return {"status": False, "message": "Pass user id"}, 401

        user = User.objects(id=user_id).first()
        if not user:
            return {"status": False, "message": "Invalid user id"}, 404

        # Accept both JSON and form-data
        if request.is_json:
            data = request.get_json(silent=True) or {}
            get_val = data.get
            profile_image_file = None  # JSON path doesn't carry files
        else:
            get_val = request.form.get
            profile_image_file = request.files.get("profile_image")

        update_data = {}

        # email
        email = get_val("email")
        if email and email.strip():
            email = email.strip()
            if "@" not in email or "." not in email.split("@")[-1]:
                return {"status": False, "message": "Enter a valid email"}, 400
            if User.objects(email=email, id__ne=user.id).first():
                return {"status": False, "message": "Email already exists"}, 400
            update_data["email"] = email

        # mobile_no
        mobile_no = get_val("mobile_no")
        if mobile_no and mobile_no.strip():
            mobile_no = mobile_no.strip()
            if User.objects(phone=mobile_no, id__ne=user.id).first():
                return {"status": False, "message": "Mobile number already exists"}, 400
            update_data["phone"] = mobile_no

        # name
        name = get_val("name")
        if name and name.strip():
            update_data["name"] = name.strip()

        # profile image only if sent as form-data file
        if profile_image_file:
            allowed_types = {"image/jpeg", "image/jpg", "image/png"}
            mimetype = (profile_image_file.mimetype or "").lower()
            if mimetype not in allowed_types:
                return {"status": False, "message": "Only JPG, JPEG, and PNG images are allowed"}, 400

            profile_image_file.stream.seek(0, os.SEEK_END)
            size = profile_image_file.stream.tell()
            profile_image_file.stream.seek(0)
            if size > 1024 * 1024:
                return {"status": False, "message": "Profile image size should not exceed 1MB"}, 400

            filename = secure_filename(profile_image_file.filename or "")
            ext = os.path.splitext(filename)[-1]
            new_name = f"{int(datetime.utcnow().timestamp())}_{os.urandom(10).hex()}{ext}"

            upload_dir = os.path.join(current_app.root_path, "public", "images", "uploads", "profile")
            os.makedirs(upload_dir, exist_ok=True)
            new_path = os.path.join(upload_dir, new_name)
            profile_image_file.save(new_path)

            base = request.host_url.rstrip("/")
            public_url = f"{base}/public/images/uploads/profile/{new_name}"
            update_data["profile_image"] = public_url

            # delete old
            old_url = getattr(user, "profile_image", None)
            if old_url:
                try:
                    from urllib.parse import urlparse
                    old_name = os.path.basename(urlparse(old_url).path)
                    old_path = os.path.join(upload_dir, old_name)
                    if os.path.exists(old_path):
                        os.unlink(old_path)
                except Exception:
                    pass

        if not update_data:
            return {"status": False, "message": "No fields provided for update"}, 400

        try:
            user.update(**update_data)
        except NotUniqueError:
            return {"status": False, "message": "Email or mobile already exists"}, 400

        updated = User.objects(id=user_id).only(
            "id", "name", "email", "phone", "user_type", "status", "is_email_verified", "profile_image"
        ).first()
        u = updated.to_json()
        # u["id"] = str(u.pop("_id"))
        u.pop("password", None)
        u.pop("login_otp", None)

        return {"status": True, "message": "Profile updated successfully", "user": u}, 200

auth_api.add_resource(UpdateProfile, "/update-profile")

# class GoogleLogin(Resource):

#     def post(self):
#         data = request.get_json(force=True)

#         clerk_token = data.get("token")
#         register_type = data.get("register_type")
#         refer_by = data.get("refer_by")
#         shared_quiz_id = data.get("shared_quiz_id")

#         if not clerk_token:
#             return {
#                 "status": False,
#                 "message": "Clerk token not provided"
#             }, 400

#         if not register_type:
#             return {
#                 "status": False,
#                 "message": "Select user type"
#             }, 400

#         # Verify Clerk token
#         user_data = self.verifyClerkToken(clerk_token)
#         if user_data.get("error"):
#             return {
#                 "status": False,
#                 "message": user_data["error"]
#             }, 401

#         email = user_data.get("email")
#         name = f"{user_data.get('firstName', '')} {user_data.get('lastName', '')}".strip()

#         if not email:
#             return {
#                 "status": False,
#                 "message": "Clerk token does not contain an email"
#             }, 401

#         # Check if user exists
#         user = User.objects(email=email).first()

#         if not user:
#             # New user registration
#             referral_code = self.generate_referral_code()
#             user_data_dict = {
#                 "name": name,
#                 "email": email,
#                 "user_type": register_type,
#                 "referral_code": referral_code,
#                 "is_email_verified": 1,
#                 "status": 1
#             }

#             if refer_by:
#                 referrer = User.objects(referral_code=refer_by).first()
#                 if referrer:
#                     user_data_dict["refer_by"] = refer_by

#                     points = 40 if register_type == "Learner" else 50
#                     referrer_update_data = {}

#                     if register_type == "Learner":
#                         referrer_update_data["referral_points_learner"] = referrer.referral_points_learner + points
#                     elif register_type == "Teacher":
#                         referrer_update_data["referral_points_teacher"] = referrer.referral_points_teacher + points

#                     referrer_update_data["total_referral_points"] = referrer.total_referral_points + points
#                     referrer_update_data["total_referrals"] = referrer.total_referrals + 1

#                     referrer.update(**referrer_update_data)

#                     new_user = User(**user_data_dict).save()

#                     # Save referral record
#                     UserReferral(
#                         user_id=new_user.id,
#                         referred_by_user_id=referrer.id,
#                         points=points
#                     ).save()
#                 else:
#                     return {
#                         "status": False,
#                         "message": "Invalid referral code"
#                     }, 401
#             else:
#                 new_user = User(**user_data_dict).save()

#             user = new_user
#         else:
#             if user.is_deleted == 1:
#                 return {
#                     "status": False,
#                     "message": "Account is deleted."
#                 }, 401

#             if user.status != 1:
#                 return {
#                     "status": False,
#                     "message": "Account is deactivated."
#                 }, 401

#         # Remove sensitive fields
#         user_dict = user.to_mongo().to_dict()
#         user_dict.pop("password", None)
#         user_dict.pop("login_otp", None)
#         user_dict["_id"] = str(user_dict["_id"])

#         # Generate JWT
#         token_payload = {
#             "id": str(user.id),
#             "email": user.email,
#             "role": user.user_type or "Learner"
#         }
#         token = generate_token(token_payload)

#         # Fetch referrals
#         referrals = []
#         if user.referral_code:
#             referred_users = User.objects(refer_by=user.referral_code)
#             for ref_user in referred_users:
#                 ref_user_data = ref_user.to_mongo().to_dict()
#                 ref_user_data.pop("password", None)
#                 ref_user_data.pop("login_otp", None)
#                 ref_user_data["_id"] = str(ref_user_data["_id"])
#                 referrals.append(ref_user_data)

#         # Handle shared quiz
#         if shared_quiz_id:
#             image = Image.objects(id=shared_quiz_id).first()
#             if not image:
#                 return {
#                     'status': False,
#                     'message': 'Invalid quiz id'
#                 }, 401

#             # Create quiz share record
#             QuizShare(
#                 shared_by_user_id=image.user_id,
#                 quiz_id=image,
#                 user_id=user,
#                 created_date=datetime.now().strftime('%Y-%m-%d %H:%M:%S')
#             ).save()

#         return {
#             "status": True,
#             "message": "Login successfully.",
#             "token": token,
#             "user": user_dict,
#             "referrals": referrals
#         }, 200

    # def generate_referral_code(self, length=8):
    #     """PHP logic uses md5(uniqid). Replicate that exactly."""
    #     raw = f"{random.random()}-{time.time()}"
    #     return hashlib.md5(raw.encode()).hexdigest().upper()[:length]

    # def verify_clerk_token(self, token):
    #     """
    #     Replicates the PHP private method verifyClerkToken.
    #     Uses Clerk's /v1/me API to fetch the user.
    #     """
    #     clerk_api_key = "YOUR_CLERK_SECRET_KEY"
    #     url = "https://api.clerk.com/v1/me"

    #     headers = {
    #         "Authorization": f"Bearer {token}",
    #         "Content-Type": "application/json"
    #     }

    #     try:
    #         response = requests.get(url, headers=headers, timeout=10)
    #         if response.status_code == 200:
    #             data = response.json()
    #             email = ""
    #             # Find primary email
    #             for email_obj in data.get("email_addresses", []):
    #                 if email_obj.get("id") == data.get("primary_email_address_id"):
    #                     email = email_obj.get("email_address")
    #                     break
    #             if not email and data.get("email_addresses"):
    #                 email = data["email_addresses"][0].get("email_address")

    #             return {
    #                 "id": data.get("id"),
    #                 "email": email,
    #                 "firstName": data.get("first_name", ""),
    #                 "lastName": data.get("last_name", "")
    #             }
    #         else:
    #             return {
    #                 "error": f"Failed to fetch user from Clerk: {response.status_code}"
    #             }
    #     except Exception as e:
    #         return {
    #             "error": f"Exception during Clerk API call: {str(e)}"
    #         }
    # def verifyClerkToken(self, token):
    #     payload = jwt.decode(token, SECRET, algorithms=["HS256"])
    #     return {
    #         'id': payload['sub'],
    #         'email': payload['email'],
    #         'firstName': payload['firstName'],
    #         'lastName': payload['lastName']
    #     }

class GoogleLogin(Resource):

    def post(self):
        data = request.get_json(force=True)

        clerk_token = data.get("token")
        register_type = data.get("register_type")
        refer_by = data.get("refer_by")
        shared_quiz_id = data.get("shared_quiz_id")

        if not clerk_token:
            return {"status": False, "message": "Clerk token not provided"}, 400
        if not register_type:
            return {"status": False, "message": "Select user type"}, 400

        # Verify token (your local HS256)
        user_data = self.verifyClerkToken(clerk_token)
        if user_data.get("error"):
            return {"status": False, "message": user_data["error"]}, 401

        email = user_data.get("email")
        name = f"{user_data.get('firstName', '')} {user_data.get('lastName', '')}".strip()
        if not email:
            return {"status": False, "message": "Clerk token does not contain an email"}, 401

        # Existing user?
        user = User.objects(email=email).first()

        first_time = False
        if not user:
            # New user is considered verified/active immediately
            first_time = True
            referral_code = self.generate_referral_code()
            user_data_dict = {
                "name": name,
                "email": email,
                "user_type": register_type,
                "referral_code": referral_code,
                "is_email_verified": 1,
                "status": 1,
                "coins_wallet_balance": 0,
                "created_date": datetime.utcnow()
            }

            referrer = None
            if refer_by:
                referrer = User.objects(referral_code=refer_by).first()
                if not referrer:
                    return {"status": False, "message": "Invalid referral code"}, 401
                user_data_dict["refer_by"] = refer_by

            new_user = User(**user_data_dict).save()
            user = new_user

            # Save referral relation (no coins yet; coins come below)
            if referrer:
                UserReferral(
                    user_id=user,
                    referred_by_user_id=referrer,
                    points=0,
                    created_date=datetime.utcnow()
                ).save()

        else:
            if user.is_deleted == 1:
                return {"status": False, "message": "Account is deleted."}, 401
            if user.status != 1:
                return {"status": False, "message": "Account is deactivated."}, 401

        # Sensitive strips
        user_dict = user.to_mongo().to_dict()
        user_dict.pop("password", None)
        user_dict.pop("login_otp", None)
        user_dict["_id"] = str(user_dict["_id"])

        # JWT
        token_payload = {"id": str(user.id), "email": user.email, "role": user.user_type or "Learner"}
        token = generate_token(token_payload)

        # Credit bonuses ONLY once for first-time social login
        if first_time:
            cfg = EdurubyConfiguration.objects.order_by('-created_date').first()
            if cfg:
                # Signup bonus (once)
                signup_bonus = int(cfg.user_signup_bonus_coins or 0)
                if signup_bonus > 0 and not TransactionHistory.objects(user_id=user, transaction_type='signup_bonus').first():
                    ub_before = int(user.coins_wallet_balance or 0)
                    ub_after = ub_before + signup_bonus
                    user.coins_wallet_balance = ub_after
                    user.save()
                    TransactionHistory(
                        user_id=user,
                        transaction_type='signup_bonus',
                        entry_type='credit',
                        amount=signup_bonus,
                        description=f"Signup bonus: {signup_bonus} coins credited on social login registration",
                        related_user_id=None,
                        balance_before=ub_before,
                        balance_after=ub_after,
                        transaction_status=1
                    ).save()

                # Referral bonus to referrer (if provided, once)
                ref_rel = UserReferral.objects(user_id=user).first()
                referrer = ref_rel.referred_by_user_id if ref_rel else (User.objects(referral_code=user.refer_by).first() if user.refer_by else None)
                if referrer:
                    if register_type == "Learner":
                        ref_points = int(cfg.learner_signup_referral_coins or 0)
                    elif register_type == "Teacher":
                        ref_points = int(cfg.teacher_signup_referral_coins or 0)
                    else:
                        ref_points = 0

                    already_ref = TransactionHistory.objects(
                        user_id=referrer, transaction_type='referral_bonus', related_user_id=user
                    ).first()

                    if ref_points > 0 and not already_ref:
                        rb_before = int(referrer.coins_wallet_balance or 0)
                        rb_after = rb_before + ref_points
                        referrer.coins_wallet_balance = rb_after
                        referrer.save()

                        inc_ops = {'inc__total_referrals': 1, 'inc__total_referral_points': ref_points}
                        if register_type == 'Learner':
                            inc_ops['inc__referral_points_learner'] = ref_points
                        else:
                            inc_ops['inc__referral_points_teacher'] = ref_points
                        try:
                            referrer.modify(**inc_ops)
                        except Exception as e:
                            logger.error(f"Failed to update referrer aggregates: {e}")

                        TransactionHistory(
                            user_id=referrer,
                            transaction_type='referral_bonus',
                            entry_type='credit',
                            amount=ref_points,
                            description=f"Referral bonus: {ref_points} coins received for referring a {register_type.lower()} signup",
                            related_user_id=user,
                            balance_before=rb_before,
                            balance_after=rb_after,
                            transaction_status=1
                        ).save()

        # Referrals list (unchanged)
        referrals = []
        if user.referral_code:
            referred_users = User.objects(refer_by=user.referral_code)
            for ref_user in referred_users:
                ref_user_data = ref_user.to_mongo().to_dict()
                ref_user_data.pop("password", None)
                ref_user_data.pop("login_otp", None)
                ref_user_data["_id"] = str(ref_user_data["_id"])
                referrals.append(ref_user_data)

        # Shared quiz
        if shared_quiz_id:
            image = Image.objects(id=shared_quiz_id).first()
            if not image:
                return {'status': False, 'message': 'Invalid quiz id'}, 401
            QuizShare(
                shared_by_user_id=image.user_id,
                quiz_id=image,
                user_id=user,
                created_date=datetime.utcnow()
            ).save()

        return {
            "status": True,
            "message": "Login successfully.",
            "token": token,
            "user": user_dict,
            "referrals": referrals
        }, 200

    def generate_referral_code(self, length=8):
        raw = f"{random.random()}-{time.time()}"
        return hashlib.md5(raw.encode()).hexdigest().upper()[:length]

    def verifyClerkToken(self, token):
        payload = jwt.decode(token, SECRET, algorithms=["HS256"])
        return {
            'id': payload['sub'],
            'email': payload['email'],
            'firstName': payload['firstName'],
            'lastName': payload['lastName']
        }

        
auth_api.add_resource(GoogleLogin, '/google-login')

class GetSliderInfo(Resource):
    def get(self):
        try:
            # Fetch only documents with status == 1
            sliders = Slider.objects(status=1).order_by('slide_position')
            
            result = []
            for slider in sliders:
                result.append({
                    "id": str(slider.id),
                    "image": slider.image,
                    "slide_position": slider.slide_position,
                    "status": slider.status,
                    "created_date": slider.created_date.isoformat() if slider.created_date else None
                })
            if result== []:
                return {
                    "status": False,
                    "data": result
                }, 200
            else:

                return {
                    "status": True,
                    "data": result
                }, 200
        
        except Exception as e:
            return {
                "status": False,
                "message": str(e)
            }, 500

auth_api.add_resource(GetSliderInfo, '/getsliderinfo')




# class GetStudyMaterialContent(Resource):
#     parser = reqparse.RequestParser()
#     parser.add_argument("exam_id", type=str, required=True, help="exam_id is required")
#     parser.add_argument("study_material_id", type=int, required=True, help="study_material_id is required")

#     def post(self):
#         data = self.parser.parse_args()
#         exam_id_str = data["exam_id"]
#         study_material_id = data["study_material_id"]

#         # ✅ Step 1: Convert exam_id to ObjectId
#         try:
#             exam_object_id = ObjectId(exam_id_str)
#         except errors.InvalidId:
#             return {
#                 "status": False,
#                 "message": f"Invalid ObjectId format for exam_id: {exam_id_str}"
#             }, 400

#         # ✅ Step 2: Check if exam exists and is active
#         exam_exists = Exam.objects(id=exam_object_id, status=1).first()
#         if not exam_exists:
#             return {
#                 "status": False,
#                 "message": f"Invalid or inactive exam_id: {exam_id_str}"
#             }, 400

#         # ✅ Step 3: Check if study material exists
#         material_exists = StudyMaterial.objects(id=study_material_id).first()
#         if not material_exists:
#             return {
#                 "status": False,
#                 "message": f"Invalid study_material_id: {study_material_id}"
#             }, 400

#         # ✅ Step 4: Query study_material_content
#         contents = StudyMaterialContent.objects(
#             exam_id=exam_object_id,
#             study_material_id=study_material_id,
#             status=1
#         )

#         if not contents:
#             return {
#                 "status": False,
#                 "message": "No study material content found for the given IDs"
#             }, 404

#         results = []
#         for content in contents:
#             item = {
#                 "id": str(content.id),
#                 "exam_id": str(content.exam_id),
#                 "study_material_id": content.study_material_id,
#                 "content_file_path": content.content_file_path,
#                 "content_description": content.content_description,
#                 "status": content.status,
#                 "created_date": content.created_date.isoformat()
#             }
#             results.append(item)

#         return {
#             "status": True,
#             "message": "Study material content fetched successfully",
#             "data": results
#         }, 200
    
#auth_api.add_resource(GetStudyMaterialContent, "/get-study-material-content")

@auth_bp.route('/notification_count', methods=['GET'])
def notification_count():
    try:
        count = Notification.objects(status=1).count()
        return jsonify({"status": True, "count": count}), 200
    except Exception as e:
        return jsonify({"status": False, "message": str(e)}), 500