from django.core.paginator import Paginator
from django.db.models import Q
from django.contrib.auth import get_user_model

from ..serializers import UserSerializer

User = get_user_model()


def _serialize_user(u):
    return UserSerializer(u).data


def list_users(params: dict = None):
    """Return users list. If pagination params provided (page, page_size) returns
    a dict with `count` and `results`, otherwise returns a plain list.

    Supported filter params: search, role, is_active, email_verified, page, page_size
    """
    params = params or {}
    qs = User.objects.all().order_by('-date_joined')

    # Filters
    search = params.get('search')
    if search:
        s = search.strip()
        tokens = [token for token in s.split() if token]

        if tokens:
            for token in tokens:
                qs = qs.filter(
                    Q(first_name__icontains=token)
                    | Q(last_name__icontains=token)
                    | Q(email__icontains=token)
                    | Q(mobile__icontains=token)
                    | Q(referral_code__icontains=token)
                )
        else:
            qs = qs.none()

    role = params.get('role')
    if role:
        qs = qs.filter(role__iexact=role)

    is_active = params.get('is_active')
    if is_active is not None:
        # Accept strings 'true'/'false' as well
        if isinstance(is_active, str):
            is_active = is_active.lower() in ('1', 'true', 'yes')
        qs = qs.filter(is_active=bool(is_active))

    email_verified = params.get('email_verified')
    if email_verified is not None:
        if isinstance(email_verified, str):
            email_verified = email_verified.lower() in ('1', 'true', 'yes')
        qs = qs.filter(is_email_verified=bool(email_verified))

    # Location presence filter (legacy compatibility with location_approval param)
    loc_approval = params.get('location_approval') or params.get('location_approved')
    if loc_approval:
        v = str(loc_approval).lower()
        if v == 'approved' or v == 'true':
            qs = qs.exclude(Q(location__isnull=True) | Q(location=''))
        elif v == 'pending':
            qs = qs.filter(Q(location__isnull=True) | Q(location=''))
        elif v == 'rejected' or v == 'false':
            qs = qs.filter(Q(location__isnull=True) | Q(location=''))

    # Pagination
    page = params.get('page')
    page_size = params.get('page_size') or params.get('page_size', 20)
    try:
        page = int(page) if page is not None else None
    except Exception:
        page = None

    try:
        page_size = int(page_size)
    except Exception:
        page_size = 20

    if page is not None:
        paginator = Paginator(qs, page_size)
        page_obj = paginator.get_page(page)
        results = [_serialize_user(u) for u in page_obj.object_list]
        return {'count': paginator.count, 'results': results}

    # No pagination requested
    return [_serialize_user(u) for u in qs]


def get_user(user_id):
    try:
        u = User.objects.get(pk=user_id)
    except User.DoesNotExist:
        return None
    return _serialize_user(u)


def update_user(user_id, data: dict):
    """Update allowed user fields and return serialized user or None if not found."""
    allowed = {
        'first_name', 'last_name', 'email', 'mobile', 'is_active', 'role', 'is_staff',
        'is_email_verified', 'is_mobile_verified', 'pan_number', 'date_of_birth', 'location',
        'accept_terms', 'is_onboarding_complete', 'occupation', 'pincode', 'referred_by',
        'referred_by_code', 'referred_by_mobile'
    }
    try:
        u = User.objects.get(pk=user_id)
    except User.DoesNotExist:
        return None

    changed = False
    for k, v in data.items():
        if k in allowed:
            if k in {'occupation', 'pincode'}:
                setattr(u, f'{k}_id', v or None)
            elif k == 'referred_by':
                if v in (None, ''):
                    u.referred_by_id = None
                else:
                    # Accept direct user id, mobile number, or referral code.
                    ref = User.objects.filter(pk=v).first()
                    if ref is None:
                        ref = User.objects.filter(mobile=str(v).strip()).first()
                    if ref is None:
                        ref = User.objects.filter(referral_code=str(v).strip()).first()
                    if ref is None:
                        raise ValueError('Referred by user not found.')
                    u.referred_by = ref
            elif k == 'referred_by_code':
                if v in (None, ''):
                    u.referred_by_id = None
                else:
                    ref = User.objects.filter(referral_code=str(v).strip()).first()
                    if ref is None:
                        raise ValueError('Referred by referral code not found.')
                    u.referred_by = ref
            elif k == 'referred_by_mobile':
                if v in (None, ''):
                    u.referred_by_id = None
                else:
                    ref = User.objects.filter(mobile=str(v).strip()).first()
                    if ref is None:
                        raise ValueError('Referred by mobile not found.')
                    u.referred_by = ref
            else:
                setattr(u, k, v)
            changed = True

    if changed:
        u.save()

    return _serialize_user(u)
