from django.contrib.auth import authenticate
from django.contrib.auth.models import User
from rest_framework import status
from rest_framework.authentication import TokenAuthentication
from rest_framework.decorators import api_view, permission_classes, authentication_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.authtoken.models import Token
from django.core.exceptions import ObjectDoesNotExist
from permissions import (
    resolve_effective_permission_strings,
    group_permissions_by_model,
    invalid_organization_header_response,
    user_has_organization_membership,
)


def get_assigned_organization_ids(user):
    """Distinct organization IDs from Membership (for frontend org context)."""
    from organization.models import Membership

    return list(
        Membership.objects.filter(user=user, organization_id__isnull=False)
        .values_list('organization_id', flat=True)
        .distinct()
    )


def get_user_permissions(
    user,
    organization=None,
    organization_header_provided=False,
):
    """
    Get all permissions for a user as a list of codenames.
    Format: ['app_label.codename', ...]

    If organization is provided:
    - Permissions come from org Membership groups only (no global perm fallback).
    - Only models with OrganizationModelAccess(is_enabled=True) for that org are
      included (whitelist). If none are enabled, returns [].
    """
    return resolve_effective_permission_strings(
        user=user,
        organization=organization,
        strict_enabled_only=organization is not None,
        organization_header_provided=organization_header_provided,
    )


@api_view(['POST'])
def login_view(request):
    """
    Login view that returns token and user info
    """
    bad_header = invalid_organization_header_response(request)
    if bad_header is not None:
        return bad_header

    username = request.data.get('username')
    password = request.data.get('password')

    if not username or not password:
        return Response(
            {'error': 'Username and password are required'},
            status=status.HTTP_400_BAD_REQUEST
        )

    user = authenticate(username=username, password=password)

    if user is None:
        return Response(
            {'error': 'Invalid credentials'},
            status=status.HTTP_401_UNAUTHORIZED
        )

    if not user.is_active:
        return Response(
            {'error': 'Account is disabled'},
            status=status.HTTP_401_UNAUTHORIZED
        )

    organization = getattr(request, 'organization', None)
    org_header = getattr(request, 'organization_header_provided', False)
    if organization is not None and not user_has_organization_membership(
        user, organization, organization_header_provided=org_header
    ):
        return Response(
            {'error': 'You are not assigned to this organization'},
            status=status.HTTP_403_FORBIDDEN,
        )

    # Get or create token
    token, created = Token.objects.get_or_create(user=user)

    # With org header/profile: same membership + Layer 1 rules as API; without org: full user/group perms.
    permissions = get_user_permissions(
        user,
        organization=organization,
        organization_header_provided=org_header,
    )
    model_permissions = group_permissions_by_model(permissions)

    return Response({
        'token': token.key,
        'user': {
            'id': user.id,
            'username': user.username,
            'email': user.email,
            'first_name': user.first_name,
            'last_name': user.last_name,
            'is_superuser': user.is_superuser,
            'is_staff': user.is_staff,
        },
        'permissions': permissions,
        'model_permissions': model_permissions,
        'assigned_organization_ids': get_assigned_organization_ids(user),
    })


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def logout_view(request):
    """
    Logout view that deletes the user's token
    """
    try:
        request.user.auth_token.delete()
        return Response({'message': 'Successfully logged out'})
    except (AttributeError, ObjectDoesNotExist):
        return Response(
            {'error': 'Token not found'},
            status=status.HTTP_400_BAD_REQUEST
        )


@api_view(['GET'])
@permission_classes([IsAuthenticated])
@authentication_classes([TokenAuthentication])
def user_info_view(request):
    """
    Get current user information including permissions
    """
    bad_header = invalid_organization_header_response(request)
    if bad_header is not None:
        return bad_header

    user = request.user
    organization = getattr(request, 'organization', None)
    org_header = getattr(request, 'organization_header_provided', False)
    if organization is not None and not user_has_organization_membership(
        user, organization, organization_header_provided=org_header
    ):
        return Response(
            {'detail': 'You are not assigned to this organization'},
            status=status.HTTP_403_FORBIDDEN,
        )
    permissions = get_user_permissions(
        user,
        organization=organization,
        organization_header_provided=org_header,
    )
    model_permissions = group_permissions_by_model(permissions)

    return Response({
        'id': user.id,
        'username': user.username,
        'email': user.email,
        'first_name': user.first_name,
        'last_name': user.last_name,
        'is_superuser': user.is_superuser,
        'is_staff': user.is_staff,
        'date_joined': user.date_joined,
        'last_login': user.last_login,
        'permissions': permissions,
        'model_permissions': model_permissions,
        'assigned_organization_ids': get_assigned_organization_ids(user),
    })


@api_view(['GET'])
@permission_classes([IsAuthenticated])
@authentication_classes([TokenAuthentication])
def permissions_view(request):
    """
    Get current user permissions for 30-minute refresh on frontend.
    Lightweight endpoint for periodic permission sync.
    """
    bad_header = invalid_organization_header_response(request)
    if bad_header is not None:
        return bad_header

    organization = getattr(request, 'organization', None)
    org_header = getattr(request, 'organization_header_provided', False)
    if organization is not None and not user_has_organization_membership(
        request.user, organization, organization_header_provided=org_header
    ):
        return Response(
            {'detail': 'You are not assigned to this organization'},
            status=status.HTTP_403_FORBIDDEN,
        )

    permissions = get_user_permissions(
        request.user,
        organization=organization,
        organization_header_provided=org_header,
    )
    model_permissions = group_permissions_by_model(permissions)
    return Response({
        'permissions': permissions,
        'model_permissions': model_permissions,
        'is_superuser': request.user.is_superuser,
        'assigned_organization_ids': get_assigned_organization_ids(request.user),
    })
