"""
API views for user authentication
"""
import secrets
from django.conf import settings
from django.utils import timezone
from django.shortcuts import get_object_or_404
from django.contrib.auth import authenticate
from rest_framework import status
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.response import Response
from rest_framework.authtoken.models import Token

from .models import User, EmailVerificationToken, StaffInvitation, TrustedDevice
from .mfa_services import mfa_manager
from smoothschedule.identity.core.permissions import can_hijack
from rest_framework import serializers
from smoothschedule.scheduling.schedule.models import Resource, ResourceType
from smoothschedule.identity.core.models import Tenant, Domain
from smoothschedule.communication.messaging.email_service import send_plain_email
from django_tenants.utils import schema_context


@api_view(['POST'])
@permission_classes([AllowAny])
def login_view(request):
    """
    Login user with email and password.
    POST /api/auth/login/

    If MFA is enabled:
    - Returns mfa_required=True with user_id and available methods
    - Frontend should redirect to MFA verification page

    If MFA is not enabled or device is trusted:
    - Returns access/refresh tokens and user data
    """
    # Accept both 'email' and 'username' fields for backward compatibility
    email = request.data.get('email', '') or request.data.get('username', '')
    email = email.strip().lower()
    password = request.data.get('password', '')

    if not email or not password:
        return Response(
            {'error': 'Email and password are required'},
            status=status.HTTP_400_BAD_REQUEST
        )

    # Look up user by email and authenticate
    user = None
    try:
        user_by_email = User.objects.get(email__iexact=email)
        user = authenticate(request, username=user_by_email.username, password=password)
    except User.DoesNotExist:
        pass

    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
        )

    # Check if MFA is required
    if mfa_manager.requires_mfa(user):
        # Check if device is trusted
        if mfa_manager.is_device_trusted(user, request):
            # Device is trusted, skip MFA
            pass
        else:
            # MFA required
            return Response({
                'mfa_required': True,
                'user_id': user.id,
                'mfa_methods': mfa_manager.get_available_methods(user),
                'phone_last_4': user.phone[-4:] if user.phone and len(user.phone) >= 4 else None,
            })

    # No MFA required or device is trusted - complete login
    # Use get_or_create to allow multi-device logins with the same token
    token, created = Token.objects.get_or_create(user=user)

    # Update last login IP
    client_ip = _get_client_ip(request)
    user.last_login_ip = client_ip
    user.save(update_fields=['last_login_ip'])

    return Response({
        'access': token.key,
        'refresh': token.key,  # For API compatibility
        'user': _get_user_data(user),
    })


def _get_client_ip(request):
    """Extract client IP from 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', '')


@api_view(['GET'])
@permission_classes([IsAuthenticated])
def current_user_view(request):
    """
    Get current authenticated user
    GET /api/auth/me/
    """
    user = request.user

    # Get business info if user has a tenant
    business_name = None
    business_subdomain = None
    quota_overages = []

    if user.tenant:
        business_name = user.tenant.name
        # user.tenant.subdomain does not exist. Fetch from domains relation.
        # Assuming 'domains' is the related_name from Domain model to Tenant
        primary_domain = user.tenant.domains.filter(is_primary=True).first()
        if primary_domain:
             business_subdomain = primary_domain.domain.split('.')[0]
        else:
             business_subdomain = user.tenant.schema_name

        # Check for active quota overages (for owners and managers)
        if user.role in [User.Role.TENANT_OWNER, User.Role.TENANT_MANAGER]:
            from smoothschedule.identity.core.quota_service import QuotaService
            try:
                service = QuotaService(user.tenant)
                quota_overages = service.get_active_overages()
            except Exception:
                # Don't fail login if quota check fails
                pass

    # Map database roles to frontend roles
    role_mapping = {
        'superuser': 'superuser',
        'platform_manager': 'platform_manager',
        'platform_sales': 'platform_sales',
        'platform_support': 'platform_support',
        'tenant_owner': 'owner',
        'tenant_manager': 'manager',
        'tenant_staff': 'staff',
        'customer': 'customer',
    }
    frontend_role = role_mapping.get(user.role.lower(), user.role.lower())

    # Get linked resource info for tenant users (staff, managers, owners can all be linked to resources)
    linked_resource_id = None
    can_edit_schedule = False
    if user.tenant and user.role in [User.Role.TENANT_STAFF, User.Role.TENANT_MANAGER, User.Role.TENANT_OWNER]:
        try:
            with schema_context(user.tenant.schema_name):
                linked_resource = Resource.objects.filter(user=user).first()
                if linked_resource:
                    linked_resource_id = linked_resource.id
                    can_edit_schedule = linked_resource.user_can_edit_schedule
        except Exception as e:
            import logging
            logger = logging.getLogger(__name__)
            logger.error(f"Error getting linked resource for user {user.id}: {e}")

    user_data = {
        'id': user.id,
        'username': user.username,
        'email': user.email,
        'name': user.full_name,
        'role': frontend_role,
        'avatar_url': None,  # TODO: Implement avatar
        'email_verified': user.email_verified,
        'is_staff': user.is_staff,
        'is_superuser': user.is_superuser,
        'is_active': user.is_active,
        'business': user.tenant_id,
        'business_name': business_name,
        'business_subdomain': business_subdomain,
        'permissions': user.permissions,
        'can_invite_staff': user.can_invite_staff(),
        'can_access_tickets': user.can_access_tickets(),
        'can_send_messages': user.can_send_messages(),
        'can_edit_schedule': can_edit_schedule,
        'linked_resource_id': linked_resource_id,
        'quota_overages': quota_overages,
    }

    return Response(user_data, status=status.HTTP_200_OK)


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def logout_view(request):
    """
    Logout the current user
    POST /api/auth/logout/
    """
    from django.contrib.auth import logout
    logout(request)
    return Response({"detail": "Successfully logged out."}, status=status.HTTP_200_OK)


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def send_verification_email(request):
    """
    Send email verification link
    POST /api/auth/email/verify/send/
    """
    user = request.user

    if user.email_verified:
        return Response({"detail": "Email already verified."}, status=status.HTTP_400_BAD_REQUEST)

    # Create token
    token = EmailVerificationToken.create_for_user(user)

    # Build verification URL
    # Use the frontend URL for verification
    port = ':5173' if settings.DEBUG else ''
    subdomain = ''
    if user.tenant:
        primary_domain = user.tenant.domains.filter(is_primary=True).first()
        if primary_domain:
            subdomain = primary_domain.domain.split('.')[0] + '.'

    verify_url = f"http://{subdomain}lvh.me{port}/verify-email?token={token.token}"

    # Send email (goes to console in development)
    subject = "Verify your email - Smooth Schedule"
    message = f"""Hi {user.full_name},

Please click the link below to verify your email address:

{verify_url}

This link will expire in 24 hours.

If you did not request this, please ignore this email.

Thanks,
The Smooth Schedule Team
"""

    send_plain_email(
        subject,
        message,
        settings.DEFAULT_FROM_EMAIL if hasattr(settings, 'DEFAULT_FROM_EMAIL') else 'noreply@smoothschedule.com',
        [user.email],
        fail_silently=False,
    )

    return Response({"detail": "Verification email sent."}, status=status.HTTP_200_OK)


@api_view(['POST'])
@permission_classes([AllowAny])
def verify_email(request):
    """
    Verify email with token
    POST /api/auth/email/verify/
    """
    token_str = request.data.get('token')

    if not token_str:
        return Response({"error": "Token is required."}, status=status.HTTP_400_BAD_REQUEST)

    try:
        token = EmailVerificationToken.objects.get(token=token_str)
    except EmailVerificationToken.DoesNotExist:
        return Response({"error": "Invalid token."}, status=status.HTTP_400_BAD_REQUEST)

    if not token.is_valid():
        return Response({"error": "Token has expired or already been used."}, status=status.HTTP_400_BAD_REQUEST)

    # Mark token as used
    token.used = True
    token.save()

    # Mark user email as verified
    token.user.email_verified = True
    token.user.save(update_fields=['email_verified'])

    return Response({"detail": "Email verified successfully."}, status=status.HTTP_200_OK)


def _get_user_data(user):
    """Helper to get user data for API responses."""
    # Get business info if user has a tenant
    business_name = None
    business_subdomain = None
    if user.tenant:
        business_name = user.tenant.name
        primary_domain = user.tenant.domains.filter(is_primary=True).first()
        if primary_domain:
            business_subdomain = primary_domain.domain.split('.')[0]
        else:
            business_subdomain = user.tenant.schema_name

    # Map database roles to frontend roles
    role_mapping = {
        'superuser': 'superuser',
        'platform_manager': 'platform_manager',
        'platform_sales': 'platform_sales',
        'platform_support': 'platform_support',
        'tenant_owner': 'owner',
        'tenant_manager': 'manager',
        'tenant_staff': 'staff',
        'customer': 'customer',
    }
    frontend_role = role_mapping.get(user.role.lower(), user.role.lower())

    # Get linked resource info for tenant users (staff, managers, owners can all be linked to resources)
    linked_resource_id = None
    linked_resource_name = None
    can_edit_schedule = False
    if user.tenant and user.role in [User.Role.TENANT_STAFF, User.Role.TENANT_MANAGER, User.Role.TENANT_OWNER]:
        try:
            with schema_context(user.tenant.schema_name):
                linked_resource = Resource.objects.filter(user=user).first()
                if linked_resource:
                    linked_resource_id = linked_resource.id
                    linked_resource_name = linked_resource.name
                    can_edit_schedule = linked_resource.user_can_edit_schedule
        except Exception as e:
            import logging
            logger = logging.getLogger(__name__)
            logger.error(f"Error getting linked resource for user {user.id} in _get_user_data: {e}")

    return {
        'id': user.id,
        'username': user.username,
        'email': user.email,
        'name': user.full_name,
        'role': frontend_role,
        'avatar_url': None,
        'email_verified': user.email_verified,
        'is_staff': user.is_staff,
        'is_superuser': user.is_superuser,
        'is_active': user.is_active,
        'business': user.tenant_id,
        'business_name': business_name,
        'business_subdomain': business_subdomain,
        'permissions': user.permissions,
        'can_invite_staff': user.can_invite_staff(),
        'can_access_tickets': user.can_access_tickets(),
        'can_send_messages': user.can_send_messages(),
        'can_edit_schedule': can_edit_schedule,
        'linked_resource_id': linked_resource_id,
        'linked_resource_name': linked_resource_name,
    }


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def hijack_acquire_view(request):
    """
    Masquerade as another user (hijack).
    POST /api/auth/hijack/acquire/

    Body: { "user_pk": <user_id>, "hijack_history": [...] }

    Returns new auth token for the hijacked user along with the hijack history.
    Supports multi-level masquerading - permissions are checked against the
    ORIGINAL user (first in the stack), not the currently masquerading user.
    """
    import logging
    logger = logging.getLogger(__name__)
    logger.warning(f"Hijack API called. User authenticated: {request.user.is_authenticated}, User: {request.user}")

    user_pk = request.data.get('user_pk')
    if not user_pk:
        return Response({"error": "user_pk is required"}, status=status.HTTP_400_BAD_REQUEST)

    hijacker = request.user
    hijacked = get_object_or_404(User, pk=user_pk)

    # Get the hijack history from the request
    hijack_history = request.data.get('hijack_history', [])
    logger.warning(f"hijack_history length: {len(hijack_history)}")

    # For multi-level masquerading, check permissions against the ORIGINAL user
    # (the first user in the masquerade chain, or the current user if no chain)
    if hijack_history:
        original_user_id = hijack_history[0].get('user_id')
        original_user = get_object_or_404(User, pk=original_user_id)
        permission_checker = original_user
        logger.warning(f"Multi-level masquerade: checking permissions for original user {original_user.email}")
    else:
        permission_checker = hijacker
        logger.warning(f"First-level masquerade: checking permissions for {hijacker.email}")

    logger.warning(f"Hijack attempt: permission_checker={permission_checker.email} (role={permission_checker.role}), hijacked={hijacked.email} (role={hijacked.role})")

    # Check permission against the original user in the chain
    can_hijack_result = can_hijack(permission_checker, hijacked)
    logger.warning(f"can_hijack result: {can_hijack_result}")
    if not can_hijack_result:
        logger.warning(f"Hijack DENIED: {permission_checker.email} -> {hijacked.email}")
        return Response(
            {"error": f"You do not have permission to masquerade as this user."},
            status=status.HTTP_403_FORBIDDEN
        )

    # Enforce maximum masquerade depth (prevent infinite chains)
    MAX_MASQUERADE_DEPTH = 5
    if len(hijack_history) >= MAX_MASQUERADE_DEPTH:
        logger.warning(f"Hijack denied - max depth ({MAX_MASQUERADE_DEPTH}) reached")
        return Response(
            {"error": f"Maximum masquerade depth ({MAX_MASQUERADE_DEPTH}) reached."},
            status=status.HTTP_403_FORBIDDEN
        )

    logger.warning("Passed all checks, proceeding with hijack...")

    # Add current user (hijacker) to the history stack
    hijacker_business_subdomain = None
    if hijacker.tenant:
        primary_domain = hijacker.tenant.domains.filter(is_primary=True).first()
        if primary_domain:
            hijacker_business_subdomain = primary_domain.domain.split('.')[0]
        else:
            hijacker_business_subdomain = hijacker.tenant.schema_name

    role_mapping = {
        'superuser': 'superuser',
        'platform_manager': 'platform_manager',
        'platform_sales': 'platform_sales',
        'platform_support': 'platform_support',
        'tenant_owner': 'owner',
        'tenant_manager': 'manager',
        'tenant_staff': 'staff',
        'customer': 'customer',
    }

    # Append current user to the history (don't overwrite existing history)
    new_history = hijack_history + [{
        'user_id': hijacker.id,
        'username': hijacker.username,
        'role': role_mapping.get(hijacker.role.lower(), hijacker.role.lower()),
        'business_id': hijacker.tenant_id,
        'business_subdomain': hijacker_business_subdomain,
    }]

    # Create or get token for hijacked user
    Token.objects.filter(user=hijacked).delete()  # Delete old token
    token = Token.objects.create(user=hijacked)

    return Response({
        'access': token.key,
        'refresh': token.key,  # For API compatibility (we don't use refresh tokens with DRF Token auth)
        'user': _get_user_data(hijacked),
        'masquerade_stack': new_history,
    }, status=status.HTTP_200_OK)


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def hijack_release_view(request):
    """
    Stop masquerading and return to previous user.
    POST /api/auth/hijack/release/

    Body: { "masquerade_stack": [...] }

    Returns auth token for the original user.
    """
    masquerade_stack = request.data.get('masquerade_stack', [])

    if not masquerade_stack:
        return Response(
            {"error": "No masquerade session to stop. masquerade_stack is empty."},
            status=status.HTTP_400_BAD_REQUEST
        )

    # Get the original user from the stack
    original_user_entry = masquerade_stack.pop()
    original_user = get_object_or_404(User, pk=original_user_entry['user_id'])

    # Create or get token for original user
    Token.objects.filter(user=original_user).delete()  # Delete old token
    token = Token.objects.create(user=original_user)

    return Response({
        'access': token.key,
        'refresh': token.key,
        'user': _get_user_data(original_user),
        'masquerade_stack': masquerade_stack,  # Return remaining stack (should be empty now)
    }, status=status.HTTP_200_OK)


# ============================================================================
# Staff Invitation Endpoints
# ============================================================================

class StaffInvitationSerializer(serializers.ModelSerializer):
    """Serializer for staff invitations"""
    invited_by_name = serializers.SerializerMethodField()
    role_display = serializers.SerializerMethodField()

    class Meta:
        model = StaffInvitation
        fields = [
            'id', 'email', 'role', 'role_display', 'status',
            'invited_by', 'invited_by_name',
            'created_at', 'expires_at', 'accepted_at',
            'create_bookable_resource', 'resource_name', 'permissions'
        ]
        read_only_fields = ['id', 'status', 'invited_by', 'created_at', 'expires_at', 'accepted_at']

    def get_invited_by_name(self, obj):
        return obj.invited_by.full_name if obj.invited_by else None

    def get_role_display(self, obj):
        role_map = {
            'TENANT_MANAGER': 'Manager',
            'TENANT_STAFF': 'Staff',
        }
        return role_map.get(obj.role, obj.role)


@api_view(['GET', 'POST'])
@permission_classes([IsAuthenticated])
def staff_invitations_view(request):
    """
    List pending invitations or create a new invitation.
    GET /api/staff/invitations/ - List invitations for current tenant
    POST /api/staff/invitations/ - Create new invitation
    """
    user = request.user

    # Check permission - only owners and managers with permission can manage invitations
    if not user.can_invite_staff():
        return Response(
            {"error": "You do not have permission to invite staff members."},
            status=status.HTTP_403_FORBIDDEN
        )

    # Must have a tenant
    if not user.tenant:
        return Response(
            {"error": "No business associated with your account."},
            status=status.HTTP_400_BAD_REQUEST
        )

    if request.method == 'GET':
        # List invitations for this tenant
        invitations = StaffInvitation.objects.filter(
            tenant=user.tenant,
            status=StaffInvitation.Status.PENDING
        )
        serializer = StaffInvitationSerializer(invitations, many=True)
        return Response(serializer.data)

    elif request.method == 'POST':
        email = request.data.get('email', '').strip().lower()
        role = request.data.get('role', User.Role.TENANT_STAFF)
        create_bookable_resource = request.data.get('create_bookable_resource', False)
        resource_name = request.data.get('resource_name', '').strip()
        permissions = request.data.get('permissions', {})

        # Validate email
        if not email:
            return Response(
                {"error": "Email is required."},
                status=status.HTTP_400_BAD_REQUEST
            )

        # Validate role - only allow manager and staff roles
        if role not in [User.Role.TENANT_MANAGER, User.Role.TENANT_STAFF]:
            return Response(
                {"error": "Invalid role. Must be 'TENANT_MANAGER' or 'TENANT_STAFF'."},
                status=status.HTTP_400_BAD_REQUEST
            )

        # Managers can only invite staff, not other managers
        # TODO: Add owner control to allow/disallow managers inviting managers
        if user.role == User.Role.TENANT_MANAGER and role == User.Role.TENANT_MANAGER:
            return Response(
                {"error": "Managers can only invite staff members, not other managers."},
                status=status.HTTP_403_FORBIDDEN
            )

        # Check if user already exists in this tenant
        existing_user = User.objects.filter(
            email=email,
            tenant=user.tenant
        ).first()
        if existing_user:
            return Response(
                {"error": f"A user with email {email} already exists in your business."},
                status=status.HTTP_400_BAD_REQUEST
            )

        # Validate permissions is a dict
        if not isinstance(permissions, dict):
            permissions = {}

        # Create invitation with bookable resource settings
        invitation = StaffInvitation.create_invitation(
            email=email,
            role=role,
            tenant=user.tenant,
            invited_by=user,
            create_bookable_resource=create_bookable_resource,
            resource_name=resource_name,
            permissions=permissions
        )

        # Send invitation email
        _send_invitation_email(invitation)

        serializer = StaffInvitationSerializer(invitation)
        return Response(serializer.data, status=status.HTTP_201_CREATED)


@api_view(['DELETE'])
@permission_classes([IsAuthenticated])
def cancel_invitation_view(request, invitation_id):
    """
    Cancel a pending invitation.
    DELETE /api/staff/invitations/<id>/
    """
    user = request.user

    if not user.can_manage_users():
        return Response(
            {"error": "You do not have permission to manage staff invitations."},
            status=status.HTTP_403_FORBIDDEN
        )

    if not user.tenant:
        return Response(
            {"error": "No business associated with your account."},
            status=status.HTTP_400_BAD_REQUEST
        )

    invitation = get_object_or_404(
        StaffInvitation,
        id=invitation_id,
        tenant=user.tenant
    )

    if invitation.status != StaffInvitation.Status.PENDING:
        return Response(
            {"error": "Only pending invitations can be cancelled."},
            status=status.HTTP_400_BAD_REQUEST
        )

    invitation.cancel()
    return Response({"detail": "Invitation cancelled."}, status=status.HTTP_200_OK)


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def resend_invitation_view(request, invitation_id):
    """
    Resend an invitation email.
    POST /api/staff/invitations/<id>/resend/
    """
    user = request.user

    if not user.can_manage_users():
        return Response(
            {"error": "You do not have permission to manage staff invitations."},
            status=status.HTTP_403_FORBIDDEN
        )

    if not user.tenant:
        return Response(
            {"error": "No business associated with your account."},
            status=status.HTTP_400_BAD_REQUEST
        )

    invitation = get_object_or_404(
        StaffInvitation,
        id=invitation_id,
        tenant=user.tenant,
        status=StaffInvitation.Status.PENDING
    )

    # Resend the email
    _send_invitation_email(invitation)

    return Response({"detail": "Invitation email resent."}, status=status.HTTP_200_OK)


@api_view(['GET'])
@permission_classes([AllowAny])
def invitation_details_view(request, token):
    """
    Get invitation details by token (public endpoint for acceptance page).
    GET /api/staff/invitations/token/<token>/
    """
    invitation = get_object_or_404(StaffInvitation, token=token)

    if not invitation.is_valid():
        return Response(
            {"error": "This invitation has expired or is no longer valid."},
            status=status.HTTP_400_BAD_REQUEST
        )

    # Return limited info for the acceptance page
    role_map = {
        'TENANT_MANAGER': 'Manager',
        'TENANT_STAFF': 'Staff',
    }

    return Response({
        'email': invitation.email,
        'role': invitation.role,
        'role_display': role_map.get(invitation.role, invitation.role),
        'business_name': invitation.tenant.name,
        'invited_by': invitation.invited_by.full_name if invitation.invited_by else None,
        'expires_at': invitation.expires_at,
        'create_bookable_resource': invitation.create_bookable_resource,
        'resource_name': invitation.resource_name,
    })


@api_view(['POST'])
@permission_classes([AllowAny])
def accept_invitation_view(request, token):
    """
    Accept an invitation and create user account.
    POST /api/staff/invitations/token/<token>/accept/

    Body: {
        "first_name": "John",
        "last_name": "Doe",
        "password": "securepassword123"
    }
    """
    invitation = get_object_or_404(StaffInvitation, token=token)

    if not invitation.is_valid():
        return Response(
            {"error": "This invitation has expired or is no longer valid."},
            status=status.HTTP_400_BAD_REQUEST
        )

    first_name = request.data.get('first_name', '').strip()
    last_name = request.data.get('last_name', '').strip()
    password = request.data.get('password', '')

    # Validate required fields
    if not first_name:
        return Response(
            {"error": "First name is required."},
            status=status.HTTP_400_BAD_REQUEST
        )

    if not password or len(password) < 8:
        return Response(
            {"error": "Password must be at least 8 characters."},
            status=status.HTTP_400_BAD_REQUEST
        )

    # Check if email is already taken (in any tenant)
    if User.objects.filter(email=invitation.email).exists():
        return Response(
            {"error": "An account with this email already exists. Please login instead."},
            status=status.HTTP_400_BAD_REQUEST
        )

    # Create the user with email as username
    # Determine sandbox mode from request (set by middleware)
    is_sandbox = getattr(request, 'sandbox_mode', False)

    user = User.objects.create_user(
        username=invitation.email.lower(),  # Use email as username
        email=invitation.email,
        password=password,
        first_name=first_name,
        last_name=last_name,
        role=invitation.role,
        tenant=invitation.tenant,
        email_verified=True,  # Email is verified since they received the invitation
        permissions=invitation.permissions,  # Copy permissions from invitation
        is_sandbox=is_sandbox,  # Isolate staff in sandbox mode
    )

    # Mark invitation as accepted
    invitation.accept(user)

    # Create bookable resource if configured
    resource_created = None
    if invitation.create_bookable_resource:
        # Get the resource name (use invitation setting or user's full name)
        resource_name = invitation.resource_name or user.full_name

        # IMPORTANT: Must use schema_context to create resource in the correct tenant schema
        # Without this, the resource is created in the public schema and won't be found
        # when querying for linked resources later
        with schema_context(invitation.tenant.schema_name):
            # Find or create the default STAFF resource type
            staff_resource_type = ResourceType.objects.filter(
                category=ResourceType.Category.STAFF,
                is_default=True
            ).first()

            # Create the resource
            resource_created = Resource.objects.create(
                name=resource_name,
                type=Resource.Type.STAFF,  # Legacy field
                resource_type=staff_resource_type,  # New field
                user=user,
                max_concurrent_events=1,  # Default to exclusive booking
            )

    # Create auth token for immediate login
    auth_token, _ = Token.objects.get_or_create(user=user)

    response_data = {
        'access': auth_token.key,
        'refresh': auth_token.key,
        'user': _get_user_data(user),
        'detail': 'Account created successfully.',
    }

    if resource_created:
        response_data['resource_created'] = {
            'id': resource_created.id,
            'name': resource_created.name,
        }

    return Response(response_data, status=status.HTTP_201_CREATED)


@api_view(['POST'])
@permission_classes([AllowAny])
def decline_invitation_view(request, token):
    """
    Decline an invitation.
    POST /api/staff/invitations/token/<token>/decline/
    """
    invitation = get_object_or_404(StaffInvitation, token=token)

    if invitation.status != StaffInvitation.Status.PENDING:
        return Response(
            {"error": "This invitation is no longer pending."},
            status=status.HTTP_400_BAD_REQUEST
        )

    invitation.decline()
    return Response({"detail": "Invitation declined."}, status=status.HTTP_200_OK)


def _send_invitation_email(invitation):
    """Send invitation email to the invitee."""
    # Build invitation URL
    port = ':5173' if settings.DEBUG else ''

    # Get subdomain for the tenant
    primary_domain = invitation.tenant.domains.filter(is_primary=True).first()
    if primary_domain:
        subdomain = primary_domain.domain.split('.')[0] + '.'
    else:
        subdomain = invitation.tenant.schema_name + '.'

    invite_url = f"http://{subdomain}lvh.me{port}/accept-invite?token={invitation.token}"

    role_map = {
        'TENANT_MANAGER': 'Manager',
        'TENANT_STAFF': 'Staff Member',
    }
    role_display = role_map.get(invitation.role, 'team member')

    subject = f"You're invited to join {invitation.tenant.name} on Smooth Schedule"
    message = f"""Hi there,

{invitation.invited_by.full_name if invitation.invited_by else 'Someone'} has invited you to join {invitation.tenant.name} as a {role_display} on Smooth Schedule.

Click the link below to accept this invitation and create your account:

{invite_url}

This invitation will expire in 7 days.

If you did not expect this invitation, you can safely ignore this email.

Thanks,
The Smooth Schedule Team
"""

    send_plain_email(
        subject,
        message,
        settings.DEFAULT_FROM_EMAIL if hasattr(settings, 'DEFAULT_FROM_EMAIL') else 'noreply@smoothschedule.com',
        [invitation.email],
        fail_silently=False,
    )


def _send_verification_email_for_user(user, tenant=None):
    """
    Send verification email to a user after signup.

    This is a helper that doesn't require authentication (used during signup).
    """
    import logging
    logger = logging.getLogger(__name__)

    try:
        # Create verification token
        token = EmailVerificationToken.create_for_user(user)

        # Build verification URL
        port = ':5173' if settings.DEBUG else ''
        subdomain = ''
        if tenant:
            primary_domain = tenant.domains.filter(is_primary=True).first()
            if primary_domain:
                subdomain = primary_domain.domain.split('.')[0] + '.'
            else:
                subdomain = tenant.schema_name + '.'

        # Determine root domain
        root_domain = 'lvh.me' if settings.DEBUG else 'smoothschedule.com'
        verify_url = f"http://{subdomain}{root_domain}{port}/verify-email?token={token.token}"

        # Use HTTPS in production
        if not settings.DEBUG:
            verify_url = verify_url.replace('http://', 'https://')

        subject = "Verify your email - Smooth Schedule"
        message = f"""Hi {user.first_name or user.full_name},

Welcome to Smooth Schedule! Please click the link below to verify your email address:

{verify_url}

This link will expire in 24 hours.

If you did not sign up for Smooth Schedule, please ignore this email.

Thanks,
The Smooth Schedule Team
"""

        send_plain_email(
            subject,
            message,
            settings.DEFAULT_FROM_EMAIL if hasattr(settings, 'DEFAULT_FROM_EMAIL') else 'noreply@smoothschedule.com',
            [user.email],
            fail_silently=False,
        )

        logger.info(f"Verification email sent to {user.email}")
    except Exception as e:
        # Log error but don't fail the signup
        logger.error(f"Failed to send verification email to {user.email}: {e}")


@api_view(['POST'])
@permission_classes([AllowAny])
def check_subdomain_view(request):
    """
    Check if a subdomain is available.
    POST /api/auth/signup/check-subdomain/
    Body: { "subdomain": "example" }
    """
    subdomain = request.data.get('subdomain', '').strip().lower()
    if not subdomain:
        return Response({"error": "Subdomain is required"}, status=status.HTTP_400_BAD_REQUEST)

    # Check reserved words
    reserved = ['www', 'api', 'admin', 'mail', 'platform', 'app', 'dashboard', 'status', 'public']
    if subdomain in reserved:
        return Response({"available": False, "reason": "Reserved"}, status=status.HTTP_200_OK)

    # Check Tenant schema_name
    if Tenant.objects.filter(schema_name=subdomain).exists():
        return Response({"available": False}, status=status.HTTP_200_OK)

    # Check Domain
    if Domain.objects.filter(domain__startswith=f"{subdomain}.").exists():
         return Response({"available": False}, status=status.HTTP_200_OK)

    return Response({"available": True}, status=status.HTTP_200_OK)


@api_view(['POST'])
@permission_classes([AllowAny])
def signup_view(request):
    """
    Sign up a new tenant and owner.
    POST /api/auth/signup/
    """
    data = request.data
    
    # 1. Validate Subdomain
    subdomain = data.get('subdomain', '').strip().lower()
    if not subdomain:
        return Response({"detail": "Subdomain is required"}, status=status.HTTP_400_BAD_REQUEST)
    
    if Tenant.objects.filter(schema_name=subdomain).exists():
        return Response({"detail": "Subdomain already taken"}, status=status.HTTP_400_BAD_REQUEST)

    # 2. Validate User
    email = data.get('email', '').strip().lower()
    password = data.get('password', '')
    if User.objects.filter(email=email).exists():
        return Response({"detail": "User with this email already exists"}, status=status.HTTP_400_BAD_REQUEST)

    try:
        with schema_context('public'):
            # 3. Create Tenant
            # Get plan code from frontend (accepts both 'plan' and 'tier' for compatibility)
            # Frontend sends 'tier' (uppercase), we normalize to lowercase
            plan_code = (data.get('plan') or data.get('tier') or 'free').lower()

            # Get Stripe customer ID if provided (from setup-intent flow)
            stripe_customer_id = data.get('stripe_customer_id', '')

            # Create tenant without legacy tier fields (now handled by billing.Subscription)
            tenant = Tenant.objects.create(
                schema_name=subdomain,
                name=data.get('business_name', subdomain),
                primary_color='#2563eb',  # Default
                secondary_color='#0ea5e9',  # Default
                contact_email=email,
                phone=data.get('phone', ''),
                stripe_customer_id=stripe_customer_id,
            )

            # 4. Create Subscription for the tenant
            # Look up the plan and get its latest public version
            from smoothschedule.billing.models import Plan, PlanVersion, Subscription
            from django.utils import timezone as dj_timezone
            from datetime import timedelta

            try:
                plan = Plan.objects.get(code=plan_code, is_active=True)
                # Get the latest public, non-legacy version
                plan_version = plan.versions.filter(
                    is_public=True,
                    is_legacy=False,
                ).order_by('-version').first()

                if plan_version:
                    # Create subscription with 30-day billing period
                    now = dj_timezone.now()
                    Subscription.objects.create(
                        business=tenant,
                        plan_version=plan_version,
                        status='active' if plan_code == 'free' else 'trial',
                        current_period_start=now,
                        current_period_end=now + timedelta(days=30),
                        trial_ends_at=now + timedelta(days=14) if plan_code != 'free' else None,
                    )
            except Plan.DoesNotExist:
                # Fall back to free plan if specified plan not found
                plan = Plan.objects.filter(code='free', is_active=True).first()
                if plan:
                    plan_version = plan.versions.filter(is_public=True, is_legacy=False).first()
                    if plan_version:
                        now = dj_timezone.now()
                        Subscription.objects.create(
                            business=tenant,
                            plan_version=plan_version,
                            status='active',
                            current_period_start=now,
                            current_period_end=now + timedelta(days=30),
                        )

            # 5. Create Domain
            # Determine root domain based on settings or environment
            # For dev, we use lvh.me
            root_domain = "lvh.me"
            # In production, this should be smoothschedule.com
            # We can infer from request host or settings
            if 'smoothschedule.com' in request.get_host():
                root_domain = 'smoothschedule.com'

            domain_url = f"{subdomain}.{root_domain}"
            Domain.objects.create(
                domain=domain_url,
                tenant=tenant,
                is_primary=True
            )

            # 6. Create User (Owner)
            user = User.objects.create_user(
                username=email,  # Use email as username
                email=email,
                password=password,
                first_name=data.get('first_name', ''),
                last_name=data.get('last_name', ''),
                role=User.Role.TENANT_OWNER,
                tenant=tenant,
                email_verified=False,  # Require verification
            )

            # 7. Generate Token
            token, _ = Token.objects.get_or_create(user=user)

            # 8. Send Verification Email
            _send_verification_email_for_user(user, tenant)

            return Response({
                'access': token.key,
                'user': _get_user_data(user),
                'tenant': {
                    'id': tenant.id,
                    'name': tenant.name,
                    'subdomain': subdomain,
                    'domain': domain_url
                }
            }, status=status.HTTP_201_CREATED)

    except Exception as e:
        # Cleanup if failed (transaction atomic would be better but this is simple)
        # In a real app, use atomic transaction
        from smoothschedule.identity.core.mixins import safe_error_message
        return Response(
            {"detail": safe_error_message(e, "Failed to create account. Please try again.")},
            status=status.HTTP_500_INTERNAL_SERVER_ERROR
        )


@api_view(['POST'])
@permission_classes([AllowAny])
def signup_setup_intent(request):
    """
    Create a Stripe SetupIntent for collecting payment method during signup.
    POST /api/auth/signup/setup-intent/

    Body:
        - email: User email address (for creating Stripe customer)
        - name: Business name (optional)
        - plan: Plan code (optional, for metadata)

    Returns:
        - client_secret: For Stripe.js confirmCardSetup
        - customer_id: Stripe customer ID (stored for later use)
        - publishable_key: Platform's Stripe publishable key
    """
    import stripe
    import logging
    logger = logging.getLogger(__name__)

    try:
        email = request.data.get('email', '').strip().lower()
        business_name = request.data.get('name', '').strip()
        plan_code = request.data.get('plan', 'free').strip().lower()

        if not email:
            return Response(
                {'error': 'Email is required'},
                status=status.HTTP_400_BAD_REQUEST
            )

        # Use platform's Stripe API key (not tenant's)
        stripe.api_key = settings.STRIPE_SECRET_KEY

        # Check if customer already exists (by email)
        existing_customers = stripe.Customer.list(email=email, limit=1)
        if existing_customers.data:
            customer = existing_customers.data[0]
            logger.info(f"[signup_setup_intent] Found existing customer: {customer.id}")
        else:
            # Create a new Stripe customer
            customer = stripe.Customer.create(
                email=email,
                name=business_name or None,
                metadata={
                    'signup_plan': plan_code,
                    'created_during': 'signup',
                }
            )
            logger.info(f"[signup_setup_intent] Created new customer: {customer.id}")

        # Create SetupIntent for future payment collection
        setup_intent = stripe.SetupIntent.create(
            customer=customer.id,
            payment_method_types=['card'],
            metadata={
                'email': email,
                'plan': plan_code,
                'created_during': 'signup',
            }
        )

        logger.info(f"[signup_setup_intent] Created SetupIntent: {setup_intent.id}")

        return Response({
            'client_secret': setup_intent.client_secret,
            'setup_intent_id': setup_intent.id,
            'customer_id': customer.id,
            'publishable_key': settings.STRIPE_PUBLISHABLE_KEY,
        })

    except stripe.error.StripeError as e:
        logger.error(f"[signup_setup_intent] StripeError: {e}")
        return Response(
            {'error': 'Unable to initialize payment. Please try again.'},
            status=status.HTTP_500_INTERNAL_SERVER_ERROR
        )
    except Exception as e:
        logger.error(f"[signup_setup_intent] Exception: {e}")
        return Response(
            {'error': 'Unable to initialize payment. Please try again.'},
            status=status.HTTP_500_INTERNAL_SERVER_ERROR
        )


@api_view(['POST'])
@permission_classes([AllowAny])
def send_customer_verification(request):
    """
    Send 6-digit verification code for new customer registration during booking.
    POST /api/auth/send-verification/

    Body:
        - email: Customer email address
        - first_name: Customer first name
        - last_name: Customer last name

    Stores code in cache for 10 minutes.
    """
    from django.core.cache import cache
    import random

    email = request.data.get('email', '').strip().lower()
    first_name = request.data.get('first_name', '').strip()
    last_name = request.data.get('last_name', '').strip()

    if not email or not first_name:
        return Response(
            {'detail': 'Email and first name are required'},
            status=status.HTTP_400_BAD_REQUEST
        )

    # Check if email is already registered
    if User.objects.filter(email__iexact=email).exists():
        return Response(
            {'detail': 'An account with this email already exists. Please sign in instead.'},
            status=status.HTTP_400_BAD_REQUEST
        )

    # Generate 6-digit code
    verification_code = ''.join([str(random.randint(0, 9)) for _ in range(6)])

    # Store in cache with 10-minute expiry
    cache_key = f'customer_verification:{email}'
    cache.set(cache_key, {
        'code': verification_code,
        'first_name': first_name,
        'last_name': last_name,
        'email': email
    }, timeout=600)  # 10 minutes

    # Send email with verification code
    subject = "Your verification code - SmoothSchedule"
    message = f"""Hi {first_name},

Thank you for booking with us! Your verification code is:

{verification_code}

This code will expire in 10 minutes.

If you didn't request this code, please ignore this email.

Thanks,
The SmoothSchedule Team
"""

    try:
        send_plain_email(
            subject,
            message,
            settings.DEFAULT_FROM_EMAIL if hasattr(settings, 'DEFAULT_FROM_EMAIL') else 'noreply@smoothschedule.com',
            [email],
            fail_silently=False,
        )
    except Exception as e:
        from smoothschedule.identity.core.mixins import safe_error_message
        return Response(
            {'detail': safe_error_message(e, 'Failed to send email. Please try again.')},
            status=status.HTTP_500_INTERNAL_SERVER_ERROR
        )

    return Response({
        'detail': 'Verification code sent successfully'
    }, status=status.HTTP_200_OK)


@api_view(['POST'])
@permission_classes([AllowAny])
def verify_and_register_customer(request):
    """
    Verify code and create customer account for booking.
    POST /api/auth/verify-and-register/

    Body:
        - email: Customer email
        - first_name: Customer first name
        - last_name: Customer last name
        - password: Account password
        - verification_code: 6-digit code from email

    Creates a customer user in the current tenant's schema.
    """
    from django.core.cache import cache
    from django_tenants.utils import get_tenant_model

    email = request.data.get('email', '').strip().lower()
    first_name = request.data.get('first_name', '').strip()
    last_name = request.data.get('last_name', '').strip()
    password = request.data.get('password', '')
    verification_code = request.data.get('verification_code', '').strip()

    if not all([email, first_name, password, verification_code]):
        return Response(
            {'detail': 'All fields are required'},
            status=status.HTTP_400_BAD_REQUEST
        )

    # Get tenant from request
    TenantModel = get_tenant_model()
    tenant = getattr(request, 'tenant', None)

    # Handle 'public' schema case (central API accessed via api.lvh.me)
    if not tenant or tenant.schema_name == 'public':
        # Try to find tenant from header
        subdomain = request.headers.get('x-business-subdomain')
        if subdomain:
            try:
                tenant = Tenant.objects.get(schema_name=subdomain)
            except Tenant.DoesNotExist:
                return Response(
                    {'detail': 'Business not found'},
                    status=status.HTTP_404_NOT_FOUND
                )
        else:
            return Response(
                {'detail': 'Invalid tenant context'},
                status=status.HTTP_400_BAD_REQUEST
            )

    # Verify code from cache
    cache_key = f'customer_verification:{email}'
    cached_data = cache.get(cache_key)

    if not cached_data:
        return Response(
            {'detail': 'Verification code expired or not found. Please request a new code.'},
            status=status.HTTP_400_BAD_REQUEST
        )

    if cached_data['code'] != verification_code:
        return Response(
            {'detail': 'Invalid verification code'},
            status=status.HTTP_400_BAD_REQUEST
        )

    # Check if user already exists
    if User.objects.filter(email__iexact=email).exists():
        return Response(
            {'detail': 'An account with this email already exists'},
            status=status.HTTP_400_BAD_REQUEST
        )

    # Create customer user
    try:
        # Generate unique username from email
        username_base = email.split('@')[0]
        username = username_base
        counter = 1
        while User.objects.filter(username=username).exists():
            username = f"{username_base}{counter}"
            counter += 1

        user = User.objects.create_user(
            username=username,
            email=email,
            password=password,
            first_name=first_name,
            last_name=last_name,
            role=User.Role.CUSTOMER,
            tenant=tenant,
            email_verified=True,  # Email is verified via code
        )

        # Clear cache
        cache.delete(cache_key)

        # Generate token
        token, _ = Token.objects.get_or_create(user=user)

        return Response({
            'access': token.key,
            'refresh': token.key,
            'user': _get_user_data(user),
        }, status=status.HTTP_201_CREATED)

    except Exception as e:
        from smoothschedule.identity.core.mixins import safe_error_message
        return Response(
            {'detail': safe_error_message(e, 'Failed to create account. Please try again.')},
            status=status.HTTP_500_INTERNAL_SERVER_ERROR
        )
