"""
CODH Users Views
User management and authentication
"""

import uuid
from datetime import timedelta
from django.utils import timezone
from django.contrib.auth import authenticate
from django.db.models import Q
from rest_framework import status, generics, permissions
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework_simplejwt.tokens import RefreshToken

from .models import (
    User, Permission, Role, UserSession, UserActivity,
    UserPreference, PasswordResetToken, EmailVerificationToken,
    Team, TeamMember
)
from .serializers import (
    UserListSerializer, UserDetailSerializer, UserCreateSerializer,
    UserUpdateSerializer, PasswordChangeSerializer, PasswordResetRequestSerializer,
    PasswordResetConfirmSerializer, UserSessionSerializer, UserActivitySerializer,
    UserPreferenceSerializer, TeamSerializer, TeamCreateSerializer,
    AddTeamMemberSerializer, LoginSerializer, RegisterSerializer,
    PermissionSerializer, RoleSerializer
)
from .permissions import IsSuperAdmin, IsAdminOrAbove, HasPermission


class RegisterView(APIView):
    """User registration"""
    permission_classes = [permissions.AllowAny]
    
    def post(self, request):
        serializer = RegisterSerializer(data=request.data)
        if serializer.is_valid():
            user = serializer.save()
            user.role = 'client'
            user.save()
            
            # Create preferences
            UserPreference.objects.create(user=user)
            
            # Generate tokens
            refresh = RefreshToken.for_user(user)
            
            # Log activity
            UserActivity.objects.create(
                user=user,
                activity_type='other',
                description='Account created',
                ip_address=self._get_client_ip(request)
            )
            
            return Response({
                'status': 'success',
                'message': 'Registration successful',
                'user': UserDetailSerializer(user).data,
                'tokens': {
                    'refresh': str(refresh),
                    'access': str(refresh.access_token),
                }
            }, status=status.HTTP_201_CREATED)
        
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
    def _get_client_ip(self, request):
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            return x_forwarded_for.split(',')[0].strip()
        return request.META.get('REMOTE_ADDR')


class LoginView(APIView):
    """User login"""
    permission_classes = [permissions.AllowAny]
    
    def post(self, request):
        serializer = LoginSerializer(data=request.data)
        if serializer.is_valid():
            email = serializer.validated_data['email']
            password = serializer.validated_data['password']
            
            user = authenticate(request, username=email, password=password)
            
            if user is None:
                # Record failed attempt
                try:
                    user = User.objects.get(email=email)
                    user.record_failed_login()
                except User.DoesNotExist:
                    pass
                
                return Response({
                    'status': 'error',
                    'message': 'Invalid credentials'
                }, status=status.HTTP_401_UNAUTHORIZED)
            
            if not user.is_active:
                return Response({
                    'status': 'error',
                    'message': 'Account is disabled'
                }, status=status.HTTP_403_FORBIDDEN)
            
            if user.is_locked:
                return Response({
                    'status': 'error',
                    'message': f'Account locked until {user.locked_until}'
                }, status=status.HTTP_403_FORBIDDEN)
            
            # Record successful login
            ip = self._get_client_ip(request)
            user.record_login(ip)
            
            # Create session
            UserSession.objects.create(
                user=user,
                session_key=request.session.session_key or str(uuid.uuid4()),
                ip_address=ip,
                user_agent=request.META.get('HTTP_USER_AGENT', '')
            )
            
            # Log activity
            UserActivity.objects.create(
                user=user,
                activity_type='login',
                ip_address=ip
            )
            
            # Generate tokens
            refresh = RefreshToken.for_user(user)
            
            return Response({
                'status': 'success',
                'user': UserDetailSerializer(user).data,
                'tokens': {
                    'refresh': str(refresh),
                    'access': str(refresh.access_token),
                }
            })
        
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
    def _get_client_ip(self, request):
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            return x_forwarded_for.split(',')[0].strip()
        return request.META.get('REMOTE_ADDR')


class LogoutView(APIView):
    """User logout"""
    permission_classes = [permissions.IsAuthenticated]
    
    def post(self, request):
        # Log activity
        UserActivity.objects.create(
            user=request.user,
            activity_type='logout',
            ip_address=self._get_client_ip(request)
        )
        
        # Deactivate session
        UserSession.objects.filter(
            user=request.user,
            session_key=request.session.session_key
        ).update(is_active=False, ended_at=timezone.now())
        
        return Response({'status': 'success', 'message': 'Logged out successfully'})
    
    def _get_client_ip(self, request):
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            return x_forwarded_for.split(',')[0].strip()
        return request.META.get('REMOTE_ADDR')


class UserProfileView(generics.RetrieveUpdateAPIView):
    """Get/Update current user profile"""
    serializer_class = UserDetailSerializer
    permission_classes = [permissions.IsAuthenticated]
    
    def get_object(self):
        return self.request.user


class UserListView(generics.ListAPIView):
    """List all users (admin only)"""
    serializer_class = UserListSerializer
    permission_classes = [IsAdminOrAbove]
    
    def get_queryset(self):
        queryset = User.objects.all()
        
        # Search
        search = self.request.query_params.get('search')
        if search:
            queryset = queryset.filter(
                Q(email__icontains=search) |
                Q(first_name__icontains=search) |
                Q(last_name__icontains=search) |
                Q(company_name__icontains=search)
            )
        
        # Filter by role
        role = self.request.query_params.get('role')
        if role:
            queryset = queryset.filter(role=role)
        
        # Filter by status
        is_active = self.request.query_params.get('is_active')
        if is_active is not None:
            queryset = queryset.filter(is_active=is_active.lower() == 'true')
        
        return queryset


class UserDetailView(generics.RetrieveUpdateDestroyAPIView):
    """Get/Update/Delete specific user"""
    queryset = User.objects.all()
    serializer_class = UserDetailSerializer
    permission_classes = [IsAdminOrAbove]
    lookup_field = 'pk'


class UserCreateView(generics.CreateAPIView):
    """Create new user (admin only)"""
    serializer_class = UserCreateSerializer
    permission_classes = [IsAdminOrAbove]


class PasswordChangeView(APIView):
    """Change password"""
    permission_classes = [permissions.IsAuthenticated]
    
    def post(self, request):
        serializer = PasswordChangeSerializer(data=request.data, context={'request': request})
        if serializer.is_valid():
            user = request.user
            user.set_password(serializer.validated_data['new_password'])
            user.password_changed_at = timezone.now()
            user.save()
            
            # Log activity
            UserActivity.objects.create(
                user=user,
                activity_type='password_change',
                ip_address=self._get_client_ip(request)
            )
            
            return Response({'status': 'success', 'message': 'Password changed successfully'})
        
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
    def _get_client_ip(self, request):
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            return x_forwarded_for.split(',')[0].strip()
        return request.META.get('REMOTE_ADDR')


class PasswordResetRequestView(APIView):
    """Request password reset"""
    permission_classes = [permissions.AllowAny]
    
    def post(self, request):
        serializer = PasswordResetRequestSerializer(data=request.data)
        if serializer.is_valid():
            email = serializer.validated_data['email']
            
            try:
                user = User.objects.get(email=email)
                
                # Create reset token
                token = PasswordResetToken.objects.create(
                    user=user,
                    token=str(uuid.uuid4()),
                    expires_at=timezone.now() + timedelta(hours=24)
                )
                
                # Send email (async)
                from codh_core.tasks import send_notification
                send_notification.delay(
                    user.id,
                    'password_reset',
                    {'token': token.token}
                )
                
            except User.DoesNotExist:
                pass  # Don't reveal if email exists
            
            return Response({
                'status': 'success',
                'message': 'If the email exists, a reset link has been sent'
            })
        
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class PasswordResetConfirmView(APIView):
    """Confirm password reset"""
    permission_classes = [permissions.AllowAny]
    
    def post(self, request):
        serializer = PasswordResetConfirmSerializer(data=request.data)
        if serializer.is_valid():
            try:
                token = PasswordResetToken.objects.get(
                    token=serializer.validated_data['token'],
                    is_used=False
                )
                
                if token.is_expired:
                    return Response({
                        'status': 'error',
                        'message': 'Token has expired'
                    }, status=status.HTTP_400_BAD_REQUEST)
                
                # Reset password
                user = token.user
                user.set_password(serializer.validated_data['new_password'])
                user.last_password_reset = timezone.now()
                user.save()
                
                # Mark token as used
                token.is_used = True
                token.save()
                
                return Response({
                    'status': 'success',
                    'message': 'Password reset successfully'
                })
                
            except PasswordResetToken.DoesNotExist:
                return Response({
                    'status': 'error',
                    'message': 'Invalid token'
                }, status=status.HTTP_400_BAD_REQUEST)
        
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class UserSessionListView(generics.ListAPIView):
    """List user sessions"""
    serializer_class = UserSessionSerializer
    permission_classes = [permissions.IsAuthenticated]
    
    def get_queryset(self):
        return UserSession.objects.filter(user=self.request.user)


class UserSessionRevokeView(APIView):
    """Revoke a session"""
    permission_classes = [permissions.IsAuthenticated]
    
    def post(self, request, session_id):
        try:
            session = UserSession.objects.get(id=session_id, user=request.user)
            session.is_active = False
            session.ended_at = timezone.now()
            session.save()
            
            return Response({'status': 'success', 'message': 'Session revoked'})
        except UserSession.DoesNotExist:
            return Response({'status': 'error', 'message': 'Session not found'}, status=404)


class UserActivityListView(generics.ListAPIView):
    """List user activities"""
    serializer_class = UserActivitySerializer
    permission_classes = [permissions.IsAuthenticated]
    
    def get_queryset(self):
        return UserActivity.objects.filter(user=self.request.user)[:100]


class UserPreferenceView(generics.RetrieveUpdateAPIView):
    """Get/Update user preferences"""
    serializer_class = UserPreferenceSerializer
    permission_classes = [permissions.IsAuthenticated]
    
    def get_object(self):
        pref, created = UserPreference.objects.get_or_create(user=self.request.user)
        return pref


# Role Management
class RoleListView(generics.ListCreateAPIView):
    """List/Create roles"""
    queryset = Role.objects.all()
    serializer_class = RoleSerializer
    permission_classes = [IsSuperAdmin]


class RoleDetailView(generics.RetrieveUpdateDestroyAPIView):
    """Get/Update/Delete role"""
    queryset = Role.objects.all()
    serializer_class = RoleSerializer
    permission_classes = [IsSuperAdmin]


class PermissionListView(generics.ListAPIView):
    """List all permissions"""
    queryset = Permission.objects.all()
    serializer_class = PermissionSerializer
    permission_classes = [IsAdminOrAbove]


# Team Management
class TeamListView(generics.ListCreateAPIView):
    """List/Create teams"""
    permission_classes = [permissions.IsAuthenticated]
    
    def get_serializer_class(self):
        if self.request.method == 'POST':
            return TeamCreateSerializer
        return TeamSerializer
    
    def get_queryset(self):
        return Team.objects.filter(
            Q(owner=self.request.user) |
            Q(members=self.request.user)
        ).distinct()
    
    def perform_create(self, serializer):
        team = serializer.save(owner=self.request.user)
        # Add owner as member
        TeamMember.objects.create(team=team, user=self.request.user, role='owner')


class TeamDetailView(generics.RetrieveUpdateDestroyAPIView):
    """Get/Update/Delete team"""
    serializer_class = TeamSerializer
    permission_classes = [permissions.IsAuthenticated]
    
    def get_queryset(self):
        return Team.objects.filter(
            Q(owner=self.request.user) |
            Q(members=self.request.user)
        ).distinct()


class AddTeamMemberView(APIView):
    """Add member to team"""
    permission_classes = [permissions.IsAuthenticated]
    
    def post(self, request, team_id):
        try:
            team = Team.objects.get(id=team_id)
            
            # Check permission
            if not TeamMember.objects.filter(
                team=team,
                user=request.user,
                role__in=['owner', 'admin']
            ).exists():
                return Response({'status': 'error', 'message': 'Permission denied'}, status=403)
            
            serializer = AddTeamMemberSerializer(data=request.data)
            if serializer.is_valid():
                email = serializer.validated_data['email']
                role = serializer.validated_data['role']
                
                try:
                    user = User.objects.get(email=email)
                except User.DoesNotExist:
                    return Response({
                        'status': 'error',
                        'message': 'User not found'
                    }, status=404)
                
                # Check if already member
                if TeamMember.objects.filter(team=team, user=user).exists():
                    return Response({
                        'status': 'error',
                        'message': 'User is already a member'
                    }, status=400)
                
                TeamMember.objects.create(team=team, user=user, role=role)
                
                return Response({
                    'status': 'success',
                    'message': 'Member added successfully'
                })
            
            return Response(serializer.errors, status=400)
            
        except Team.DoesNotExist:
            return Response({'status': 'error', 'message': 'Team not found'}, status=404)


class RemoveTeamMemberView(APIView):
    """Remove member from team"""
    permission_classes = [permissions.IsAuthenticated]
    
    def post(self, request, team_id, member_id):
        try:
            team = Team.objects.get(id=team_id)
            member = TeamMember.objects.get(id=member_id, team=team)
            
            # Check permission
            if not TeamMember.objects.filter(
                team=team,
                user=request.user,
                role__in=['owner', 'admin']
            ).exists() and request.user != member.user:
                return Response({'status': 'error', 'message': 'Permission denied'}, status=403)
            
            # Can't remove owner
            if member.role == 'owner':
                return Response({
                    'status': 'error',
                    'message': 'Cannot remove team owner'
                }, status=400)
            
            member.delete()
            
            return Response({'status': 'success', 'message': 'Member removed'})
            
        except (Team.DoesNotExist, TeamMember.DoesNotExist):
            return Response({'status': 'error', 'message': 'Not found'}, status=404)


@api_view(['GET'])
@permission_classes([permissions.IsAuthenticated])
def get_user_stats(request):
    """Get user statistics"""
    from apps.projects.models import Project
    from apps.hosting.models import HostingAccount
    from apps.subscriptions.models import Subscription
    
    user = request.user
    
    return Response({
        'projects': {
            'total': Project.objects.filter(user=user).count(),
            'active': Project.objects.filter(user=user, status='active').count(),
        },
        'hosting': {
            'total': HostingAccount.objects.filter(user=user).count(),
            'active': HostingAccount.objects.filter(user=user, status='active').count(),
        },
        'subscriptions': {
            'total': Subscription.objects.filter(user=user).count(),
            'active': Subscription.objects.filter(user=user, status='active').count(),
        }
    })
