"""
Admin API endpoints for managing users, roles, and permissions.
These mirror the FastAPI admin router and are used when the Django backend is the active server.
"""
import secrets
from datetime import timedelta

from django.views.decorators.csrf import csrf_exempt
from passlib.context import CryptContext
from rest_framework.decorators import api_view, authentication_classes, permission_classes
from rest_framework.permissions import AllowAny
from rest_framework.response import Response

from app.services.email_service import send_invite_email
from integrations.models import Client, ClientUserMembership
from .models import Permission, Role, User, UserPermission
from .views import _session_user, _user_permissions, _resolve_request_client, _app_url

pwd_ctx = CryptContext(schemes=["bcrypt"], deprecated="auto")


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

def _require_permission(request, perm_key):
    """Returns (user, None) if authenticated and has permission, else (None, Response)."""
    _, user = _session_user(request)
    if not user:
        return None, Response({"detail": "Not authenticated"}, status=401)
    perms = _user_permissions(user)
    if perm_key not in perms:
        return None, Response({"detail": "Forbidden"}, status=403)
    return user, None


def _user_role_info(user):
    role = user.role_obj or Role.objects.filter(slug=(user.role or "user").lower()).first()
    if role:
        return {
            "role_id": user.role_obj_id,
            "role_name": role.name,
            "role": role.slug or user.role,
        }
    return {
        "role_id": None,
        "role_name": (user.role or "user").capitalize(),
        "role": user.role or "user",
    }


def _user_permission_keys(user):
    return list(
        UserPermission.objects.filter(user=user)
        .select_related("permission")
        .values_list("permission__key", flat=True)
    )


def _set_user_permissions(user, permission_keys):
    UserPermission.objects.filter(user=user).delete()
    if permission_keys:
        perms = Permission.objects.filter(key__in=permission_keys)
        for p in perms:
            UserPermission.objects.get_or_create(user=user, permission=p)


def _serialize_user(user):
    info = _user_role_info(user)
    return {
        "id": user.id,
        "username": user.username,
        "created_at": user.created_at.isoformat() if user.created_at else None,
        "invite_pending": bool(user.invite_token and user.invite_expires_at),
        "permission_keys": _user_permission_keys(user),
        **info,
    }


# ---------------------------------------------------------------------------
# Users
# ---------------------------------------------------------------------------

@csrf_exempt
@api_view(["GET", "POST"])
@authentication_classes([])
@permission_classes([AllowAny])
def admin_users(request):
    if request.method == "GET":
        admin_user, err = _require_permission(request, "admin.users")
        if err:
            return err
        users = User.objects.select_related("role_obj").order_by("-created_at")
        return Response({"users": [_serialize_user(u) for u in users]})

    # POST — create user
    admin_user, err = _require_permission(request, "admin.users")
    if err:
        return err
    data = request.data
    username = (data.get("username") or "").strip()
    password = data.get("password", "")
    permission_keys = list(data.get("permission_keys") or [])
    role_id = data.get("role_id")

    if not username:
        return Response({"detail": "username is required"}, status=400)
    if User.objects.filter(username=username).exists():
        return Response({"detail": "Username already exists"}, status=400)

    role = None
    if role_id:
        role = Role.objects.filter(id=role_id).first()
        if not role:
            return Response({"detail": "Role not found"}, status=400)

    if not permission_keys and role:
        permission_keys = list(role.permissions.values_list("key", flat=True))

    if not permission_keys:
        return Response(
            {"detail": "Provide permission_keys or role_id to copy permissions from"},
            status=400,
        )

    effective_role = (
        role.slug
        if role and role.slug
        else (role.name.lower() if role and role.name else "user")
    )

    new_user = User(username=username, role=effective_role, role_obj=role)
    new_user.set_password(password)
    new_user.save()
    _set_user_permissions(new_user, permission_keys)

    # Ensure the new user is a member of the current client workspace so they can log in.
    client = _resolve_request_client(request)
    if client:
        ClientUserMembership.objects.get_or_create(
            client=client, user=new_user, defaults={"is_active": True}
        )

    return Response(_serialize_user(new_user), status=201)


@csrf_exempt
@api_view(["PATCH", "DELETE"])
@authentication_classes([])
@permission_classes([AllowAny])
def admin_user_detail(request, user_id):
    admin_user, err = _require_permission(request, "admin.users")
    if err:
        return err

    target = User.objects.filter(id=user_id).first()
    if not target:
        return Response({"detail": "User not found"}, status=404)

    if request.method == "DELETE":
        if admin_user.id == target.id:
            return Response({"detail": "You cannot delete your own account"}, status=400)
        target.delete()
        return Response({"ok": True})

    # PATCH — update email/username
    new_email = (request.data.get("username") or "").strip().lower()
    if not new_email or "@" not in new_email:
        return Response({"detail": "Valid email required"}, status=400)
    if User.objects.filter(username=new_email).exclude(id=user_id).exists():
        return Response({"detail": "A user with this email already exists"}, status=400)
    target.username = new_email
    target.save(update_fields=["username"])
    return Response({"ok": True, "username": target.username})


@csrf_exempt
@api_view(["PUT"])
@authentication_classes([])
@permission_classes([AllowAny])
def admin_user_permissions(request, user_id):
    admin_user, err = _require_permission(request, "admin.users")
    if err:
        return err

    target = User.objects.filter(id=user_id).first()
    if not target:
        return Response({"detail": "User not found"}, status=404)

    permission_keys = list(request.data.get("permission_keys") or [])
    _set_user_permissions(target, permission_keys)

    return Response({
        "id": target.id,
        "username": target.username,
        "permission_keys": _user_permission_keys(target),
    })


@csrf_exempt
@api_view(["PUT"])
@authentication_classes([])
@permission_classes([AllowAny])
def admin_user_role(request, user_id):
    admin_user, err = _require_permission(request, "admin.manage_roles")
    if err:
        return err

    target = User.objects.filter(id=user_id).first()
    if not target:
        return Response({"detail": "User not found"}, status=404)

    role_id = request.data.get("role_id")
    role = Role.objects.filter(id=role_id).first() if role_id else None
    if not role:
        return Response({"detail": "Role not found"}, status=400)

    target.role_obj = role
    target.role = role.slug if role.slug else role.name.lower()
    target.save(update_fields=["role_obj", "role"])

    permission_keys = list(role.permissions.values_list("key", flat=True))
    _set_user_permissions(target, permission_keys)

    info = _user_role_info(target)
    return Response({
        "id": target.id,
        "username": target.username,
        "permission_keys": permission_keys,
        **info,
    })


# ---------------------------------------------------------------------------
# Invites
# ---------------------------------------------------------------------------

@csrf_exempt
@api_view(["POST"])
@authentication_classes([])
@permission_classes([AllowAny])
def admin_invites(request):
    admin_user, err = _require_permission(request, "admin.users")
    if err:
        return err

    email = (request.data.get("email") or "").strip().lower()
    if not email or "@" not in email:
        return Response({"detail": "Valid email required"}, status=400)
    if User.objects.filter(username=email).exists():
        return Response({"detail": "A user with this email already exists"}, status=400)

    permission_keys = list(request.data.get("permission_keys") or [])
    if not permission_keys:
        return Response({"detail": "permission_keys is required"}, status=400)

    from django.utils import timezone

    invite_token = secrets.token_urlsafe(32)
    invite_expires_at = timezone.now() + timedelta(days=7)
    placeholder_hash = pwd_ctx.hash(secrets.token_urlsafe(24))

    new_user = User(
        username=email,
        role="user",
        invite_token=invite_token,
        invite_expires_at=invite_expires_at,
    )
    new_user.password = placeholder_hash
    new_user.save()

    _set_user_permissions(new_user, permission_keys)

    # Ensure the invited user is a member of the current client workspace.
    client = _resolve_request_client(request)
    if client:
        ClientUserMembership.objects.get_or_create(
            client=client, user=new_user, defaults={"is_active": True}
        )

    app_url = _app_url()
    invite_link = f"{app_url}/set-password?token={invite_token}"
    sent = send_invite_email(email, invite_link, "User")

    return Response({
        "id": new_user.id,
        "username": new_user.username,
        "role": "user",
        "role_id": None,
        "role_name": "User",
        "permission_keys": _user_permission_keys(new_user),
        "invite_expires_at": new_user.invite_expires_at.isoformat() if new_user.invite_expires_at else None,
        "email_sent": sent,
    }, status=201)


# ---------------------------------------------------------------------------
# Permissions
# ---------------------------------------------------------------------------

@csrf_exempt
@api_view(["GET"])
@authentication_classes([])
@permission_classes([AllowAny])
def admin_permissions(request):
    admin_user, err = _require_permission(request, "admin.users")
    if err:
        return err

    perms = Permission.objects.order_by("category", "key")
    by_cat = {}
    all_perms = []
    for p in perms:
        by_cat.setdefault(p.category, []).append({"id": p.id, "key": p.key, "name": p.name})
        all_perms.append({"id": p.id, "key": p.key, "name": p.name, "category": p.category})

    return Response({"permissions": by_cat, "all": all_perms})


# ---------------------------------------------------------------------------
# Roles
# ---------------------------------------------------------------------------

@csrf_exempt
@api_view(["GET", "POST"])
@authentication_classes([])
@permission_classes([AllowAny])
def admin_roles(request):
    if request.method == "GET":
        admin_user, err = _require_permission(request, "admin.users")
        if err:
            return err
        roles = Role.objects.prefetch_related("permissions").order_by("-is_system", "name")
        return Response({
            "roles": [
                {
                    "id": r.id,
                    "name": r.name,
                    "slug": r.slug,
                    "is_system": r.is_system,
                    "permission_keys": list(r.permissions.values_list("key", flat=True)),
                }
                for r in roles
            ]
        })

    # POST — create role
    admin_user, err = _require_permission(request, "admin.manage_roles")
    if err:
        return err

    name = (request.data.get("name") or "").strip()
    if not name:
        return Response({"detail": "name is required"}, status=400)
    if Role.objects.filter(name=name).exists():
        return Response({"detail": "Role name already exists"}, status=400)

    permission_keys = list(request.data.get("permission_keys") or [])
    perms = list(Permission.objects.filter(key__in=permission_keys)) if permission_keys else []

    role = Role(name=name, is_system=False)
    role.save()
    role.permissions.set(perms)

    return Response({
        "id": role.id,
        "name": role.name,
        "slug": role.slug,
        "is_system": role.is_system,
        "permission_keys": list(role.permissions.values_list("key", flat=True)),
    }, status=201)


@csrf_exempt
@api_view(["PUT", "DELETE"])
@authentication_classes([])
@permission_classes([AllowAny])
def admin_role_detail(request, role_id):
    admin_user, err = _require_permission(request, "admin.manage_roles")
    if err:
        return err

    role = Role.objects.filter(id=role_id).first()
    if not role:
        return Response({"detail": "Role not found"}, status=404)

    if request.method == "DELETE":
        if role.is_system:
            return Response({"detail": "System roles cannot be deleted"}, status=400)
        role.delete()
        return Response({"ok": True})

    # PUT — update role
    name = request.data.get("name")
    permission_keys = request.data.get("permission_keys")

    if name is not None:
        role.name = name.strip()

    if permission_keys is not None and not role.is_system:
        perms = list(Permission.objects.filter(key__in=permission_keys))
        role.permissions.set(perms)

    role.save()

    return Response({
        "id": role.id,
        "name": role.name,
        "slug": role.slug,
        "is_system": role.is_system,
        "permission_keys": list(role.permissions.values_list("key", flat=True)),
    })
