import random

from django.utils import timezone
from django.utils.safestring import mark_safe
from datetime import timedelta
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

from .serializers import (
    RegisterSerializer, LoginSerializer, SendOTPSerializer, VerifyOTPSerializer,
    LinkMobileSerializer, UserSerializer,
)
from .models import User
from apps.core.utils import standard_response
from django.conf import settings


def _generate_otp():
    return f'{random.randint(100000, 999999)}'


import secrets
from .models import EmailVerificationToken

class RegisterAPIView(APIView):
    def post(self, request):

        import logging
        logger = logging.getLogger(__name__)
        logger.info("Starting registration flow")
        serializer = RegisterSerializer(data=request.data)
        logger.info("Serializer initialized")
        serializer.is_valid(raise_exception=True)
        logger.info("Serializer is valid")
        user = serializer.save(is_active=False)
        logger.info(f"User created: {user.email}")

        # Generate verification token and store
        token = secrets.token_urlsafe(32)
        expiry = timezone.now() + timedelta(minutes=settings.EMAIL_OTP_EXPIRY_MINUTES)
        logger.info(f"Creating EmailVerificationToken for {user.email}")
        EmailVerificationToken.objects.filter(email=user.email).delete()
        EmailVerificationToken.objects.create(email=user.email, token=token, expires_at=expiry)
        logger.info(f"Token created for {user.email}")

        # Build verification link
        frontend_url = os.getenv('FRONTEND_URL', 'http://localhost:5173')
        verify_link = f"{frontend_url}/verify-email?token={token}&email={user.email}"
        logger.info(f"Verification link: {verify_link}")

        # Send verification link via notification service
        try:
            from apps.notifications.services import send_notification
            logger.info(f"Attempting to send verification email to {user.email}")
            context = {
                'user': user,
                'verify_link': mark_safe(verify_link),
                'expiry_minutes': settings.EMAIL_OTP_EXPIRY_MINUTES,
            }
            result = send_notification(
                channel='email',
                recipient=user.email,
                template_code='email_verification',
                context=context,
                user=user,
            )
            logger.info(f"Notification send result: {result}")
        except Exception as e:
            logger.error(f"Failed to send notification: {e}")

        return standard_response(
            True,
            data={'id': str(user.id), 'email': user.email},
            message='Registered. Please verify your email using the link sent.',
        )


class VerifyEmailView(APIView):
    def post(self, request):
        token = request.data.get('token')
        email = request.data.get('email')
        if not token or not email:
            return standard_response(False, message='Token and email required')
        record = EmailVerificationToken.objects.filter(email=email, token=token).first()
        if not record:
            return standard_response(False, message='Invalid or expired token')
        if record.is_expired:
            record.delete()
            return standard_response(False, message='Token expired. Please register again.')
        try:
            user = User.objects.get(email=email)
            user.is_active = True
            user.is_email_verified = True
            user.save(update_fields=['is_active', 'is_email_verified'])
            record.delete()
            return standard_response(True, message='Email verified. Account activated.')
        except User.DoesNotExist:
            record.delete()
            return standard_response(False, message='User not found.')


class LoginAPIView(APIView):
    def post(self, request):
        serializer = LoginSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.validated_data['user']

        from rest_framework_simplejwt.tokens import RefreshToken
        refresh = RefreshToken.for_user(user)

        # If admin, add a flag for frontend redirect
        is_admin = bool(user.is_staff or str(getattr(user, 'role', '') or '').upper() == 'ADMIN')

        return standard_response(True, data={
            'access_token': str(refresh.access_token),
            'refresh_token': str(refresh),
            'user': UserSerializer(user).data,
            'is_admin': is_admin,
        }, message='Logged in')


class SendEmailOTPView(APIView):
    def post(self, request):
        serializer = SendOTPSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        email = serializer.validated_data.get('email')
        if not email:
            return standard_response(False, message='email required', errors=['email required'])
        # Generate OTP locally and store on user record if exists
        otp = '000000'  # placeholder for integration
        try:
            user = User.objects.get(email=email)
            user.email_otp = otp
            user.otp_expiry = timezone.now() + timedelta(minutes=settings.EMAIL_OTP_EXPIRY_MINUTES)
            user.save()
        except User.DoesNotExist:
            pass
        return standard_response(True, message='OTP generated (not sent in template)')


class VerifyEmailOTPView(APIView):
    def post(self, request):
        serializer = VerifyOTPSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        email = serializer.validated_data.get('email')
        otp = serializer.validated_data.get('otp')
        if not email:
            return standard_response(False, message='email required', errors=['email required'])

        # Check the EmailOTP table first (registration flow)
        otp_record = EmailOTP.objects.filter(email=email, otp=otp).first()
        if otp_record:
            if otp_record.is_expired:
                otp_record.delete()
                return standard_response(False, message='OTP has expired. Please register again.')
            try:
                user = User.objects.get(email=email)
                user.is_active = True
                user.is_email_verified = True
                user.save(update_fields=['is_active', 'is_email_verified'])
                otp_record.delete()
                return standard_response(True, message='Email verified. Account activated.')
            except User.DoesNotExist:
                otp_record.delete()
                return standard_response(False, message='User not found.')

        # Fallback: check inline OTP on user (existing post-login verification flow)
        try:
            user = User.objects.get(email=email)
            if user.email_otp == otp and user.otp_expiry and user.otp_expiry > timezone.now():
                user.is_email_verified = True
                user.email_otp = None
                user.otp_expiry = None
                user.save(update_fields=['is_email_verified', 'email_otp', 'otp_expiry'])
                return standard_response(True, message='Email verified')
        except User.DoesNotExist:
            pass
        return standard_response(False, message='Invalid or expired OTP')


class SendMobileOTPView(APIView):
    def post(self, request):
        serializer = SendOTPSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        mobile = serializer.validated_data.get('mobile')
        if not mobile:
            return standard_response(False, message='mobile required', errors=['mobile required'])
        otp = '000000'
        try:
            user = User.objects.get(mobile=mobile)
            user.mobile_otp = otp
            user.otp_expiry = timezone.now() + timedelta(minutes=settings.MOBILE_OTP_EXPIRY_MINUTES)
            user.save()
        except User.DoesNotExist:
            pass
        return standard_response(True, message='OTP generated (not sent in template)')


class VerifyMobileOTPView(APIView):
    def post(self, request):
        serializer = VerifyOTPSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        mobile = serializer.validated_data.get('mobile')
        otp = serializer.validated_data.get('otp')
        if not mobile:
            return standard_response(False, message='mobile required', errors=['mobile required'])
        try:
            user = User.objects.get(mobile=mobile)
            if user.mobile_otp == otp and user.otp_expiry and user.otp_expiry > timezone.now():
                user.is_mobile_verified = True
                user.mobile_otp = None
                user.otp_expiry = None
                user.save()
                return standard_response(True, message='Mobile verified')
        except User.DoesNotExist:
            pass
        return standard_response(False, message='Invalid or expired OTP')


class LinkMobileView(APIView):
    """Link a mobile number to the authenticated (Google) user.

    POST /api/auth/link-mobile
    Requires: JWT authentication
    Input: { "mobile": "...", "otp": "..." }

    Flow:
      1. User calls send-mobile-otp with the desired mobile number first.
      2. User submits mobile + otp here.
      3. OTP is verified against the authenticated user's stored mobile_otp.
      4. Mobile is attached and marked verified.

    Prepared for future integration — not wired into the onboarding flow yet.
    """
    from rest_framework.permissions import IsAuthenticated
    permission_classes = [IsAuthenticated]

    def post(self, request):
        serializer = LinkMobileSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        mobile = serializer.validated_data['mobile']
        otp = serializer.validated_data['otp']
        user = request.user

        # Verify OTP stored on the requesting user
        if (
            not user.mobile_otp
            or user.mobile_otp != otp
            or not user.otp_expiry
            or user.otp_expiry <= timezone.now()
        ):
            return standard_response(
                False,
                message='Invalid or expired OTP',
                errors=['Invalid or expired OTP'],
            )

        # Attach mobile and mark verified
        user.mobile = mobile
        user.is_mobile_verified = True
        user.mobile_otp = None
        user.otp_expiry = None
        user.save(update_fields=[
            'mobile', 'is_mobile_verified', 'mobile_otp', 'otp_expiry',
        ])

        return standard_response(
            True,
            data=UserSerializer(user).data,
            message='Mobile number linked successfully',
        )
