"""
Field Mobile Serializers

Serializers for the field employee mobile app API.
"""
from rest_framework import serializers
from django.utils import timezone

from smoothschedule.scheduling.schedule.models import Event, Service, Participant
from smoothschedule.communication.mobile.models import (
    EventStatusHistory,
    EmployeeLocationUpdate,
    FieldCallLog,
)
from smoothschedule.identity.core.mixins import TimezoneSerializerMixin


class ServiceSummarySerializer(serializers.ModelSerializer):
    """Minimal service info for job cards."""

    class Meta:
        model = Service
        fields = ['id', 'name', 'duration', 'price']


class CustomerInfoSerializer(serializers.Serializer):
    """
    Customer information for a job.

    Phone number is masked for privacy - actual calls go through proxy.
    """
    id = serializers.IntegerField()
    name = serializers.SerializerMethodField()
    phone_masked = serializers.SerializerMethodField()
    email = serializers.CharField(allow_null=True)

    def get_name(self, obj):
        """Return customer's full name."""
        if hasattr(obj, 'full_name') and obj.full_name:
            return obj.full_name
        if hasattr(obj, 'get_full_name'):
            return obj.get_full_name() or getattr(obj, 'username', 'Customer')
        return getattr(obj, 'username', 'Customer')

    def get_phone_masked(self, obj):
        """Return masked phone number (last 4 digits only)."""
        phone = getattr(obj, 'phone', None)
        if phone and len(phone) >= 4:
            return f"***-***-{phone[-4:]}"
        return None


class JobListSerializer(TimezoneSerializerMixin, serializers.ModelSerializer):
    """
    Serializer for job list (today's and upcoming jobs).

    Optimized for quick loading on mobile.
    Includes business_timezone for proper time display.
    """
    service_name = serializers.SerializerMethodField()
    customer_name = serializers.SerializerMethodField()
    address = serializers.SerializerMethodField()
    status_display = serializers.CharField(source='get_status_display', read_only=True)
    duration_minutes = serializers.SerializerMethodField()
    allowed_transitions = serializers.SerializerMethodField()
    # Explicitly declare mixin field for DRF's metaclass
    business_timezone = serializers.SerializerMethodField()

    class Meta:
        model = Event
        fields = [
            'id',
            'title',
            'start_time',
            'end_time',
            'status',
            'status_display',
            'service_name',
            'customer_name',
            'address',
            'duration_minutes',
            'allowed_transitions',
            'business_timezone',
        ]

    def get_service_name(self, obj):
        return obj.service.name if obj.service else None

    def get_customer_name(self, obj):
        """Get the customer's name from participants."""
        customer = self._get_customer_participant(obj)
        if customer:
            return getattr(customer, 'full_name', None) or getattr(customer, 'username', 'Customer')
        return None

    def get_address(self, obj):
        """Get customer's address if available."""
        # First check event notes for address
        if obj.notes and 'address' in obj.notes.lower():
            return obj.notes

        # Try to get from customer
        customer = self._get_customer_participant(obj)
        if customer and hasattr(customer, 'address'):
            return customer.address

        return None

    def get_duration_minutes(self, obj):
        """Calculate event duration in minutes."""
        if obj.start_time and obj.end_time:
            delta = obj.end_time - obj.start_time
            return int(delta.total_seconds() / 60)
        return None

    def get_allowed_transitions(self, obj):
        """Get list of statuses this job can transition to."""
        from smoothschedule.communication.mobile.services import StatusMachine

        # Get the valid transitions without needing user context
        return StatusMachine.VALID_TRANSITIONS.get(obj.status, [])

    def _get_customer_participant(self, obj):
        """Get the customer User from participants."""
        from django.contrib.contenttypes.models import ContentType
        from smoothschedule.identity.users.models import User

        if not hasattr(self, '_customer_cache'):
            self._customer_cache = {}

        if obj.id in self._customer_cache:
            return self._customer_cache[obj.id]

        try:
            user_ct = ContentType.objects.get_for_model(User)
            participant = obj.participants.filter(
                role=Participant.Role.CUSTOMER,
                content_type=user_ct
            ).first()

            if participant:
                self._customer_cache[obj.id] = participant.content_object
                return participant.content_object
        except Exception:
            pass

        return None


class JobDetailSerializer(TimezoneSerializerMixin, serializers.ModelSerializer):
    """
    Full job details for the job detail screen.

    Includes all information needed to work on the job.
    Includes business_timezone for proper time display.
    """
    service = ServiceSummarySerializer(read_only=True)
    customer = serializers.SerializerMethodField()
    assigned_staff = serializers.SerializerMethodField()
    status_display = serializers.CharField(source='get_status_display', read_only=True)
    duration_minutes = serializers.SerializerMethodField()
    allowed_transitions = serializers.SerializerMethodField()
    can_track_location = serializers.SerializerMethodField()
    has_active_call_session = serializers.SerializerMethodField()
    status_history = serializers.SerializerMethodField()
    latest_location = serializers.SerializerMethodField()
    can_edit_schedule = serializers.SerializerMethodField()
    # Explicitly declare mixin field for DRF's metaclass
    business_timezone = serializers.SerializerMethodField()

    class Meta:
        model = Event
        fields = [
            'id',
            'title',
            'start_time',
            'end_time',
            'status',
            'status_display',
            'notes',
            'service',
            'customer',
            'assigned_staff',
            'duration_minutes',
            'allowed_transitions',
            'can_track_location',
            'has_active_call_session',
            'status_history',
            'latest_location',
            'deposit_amount',
            'final_price',
            'created_at',
            'updated_at',
            'can_edit_schedule',
            'business_timezone',
        ]

    def get_customer(self, obj):
        """Get customer info with masked phone."""
        customer = self._get_customer_participant(obj)
        if customer:
            return CustomerInfoSerializer(customer).data
        return None

    def get_assigned_staff(self, obj):
        """Get list of assigned staff members."""
        from django.contrib.contenttypes.models import ContentType
        from smoothschedule.identity.users.models import User
        from smoothschedule.scheduling.schedule.models import Resource

        staff = []

        # Get staff from User participants
        user_ct = ContentType.objects.get_for_model(User)
        for participant in obj.participants.filter(
            role__in=[Participant.Role.STAFF, Participant.Role.RESOURCE],
            content_type=user_ct
        ):
            user = participant.content_object
            if user:
                staff.append({
                    'id': user.id,
                    'name': user.full_name or user.username,
                    'type': 'user',
                })

        # Get staff from Resource participants
        resource_ct = ContentType.objects.get_for_model(Resource)
        for participant in obj.participants.filter(
            role__in=[Participant.Role.STAFF, Participant.Role.RESOURCE],
            content_type=resource_ct
        ):
            resource = participant.content_object
            if resource:
                staff.append({
                    'id': resource.id,
                    'name': resource.name,
                    'type': 'resource',
                    'user_id': resource.user_id,
                })

        return staff

    def get_duration_minutes(self, obj):
        if obj.start_time and obj.end_time:
            delta = obj.end_time - obj.start_time
            return int(delta.total_seconds() / 60)
        return None

    def get_allowed_transitions(self, obj):
        from smoothschedule.communication.mobile.services import StatusMachine
        return StatusMachine.VALID_TRANSITIONS.get(obj.status, [])

    def get_can_track_location(self, obj):
        """Check if location tracking is allowed for current status."""
        from smoothschedule.communication.mobile.services import StatusMachine
        return obj.status in StatusMachine.TRACKING_STATUSES

    def get_has_active_call_session(self, obj):
        """Check if there's an active masked call session."""
        tenant = self.context.get('tenant')
        if not tenant:
            return False

        from smoothschedule.communication.credits.models import MaskedSession
        return MaskedSession.objects.filter(
            tenant=tenant,
            event_id=obj.id,
            status=MaskedSession.Status.ACTIVE,
            expires_at__gt=timezone.now()
        ).exists()

    def get_status_history(self, obj):
        """Get recent status change history."""
        tenant = self.context.get('tenant')
        if not tenant:
            return []

        history = EventStatusHistory.objects.filter(
            tenant=tenant,
            event_id=obj.id
        ).select_related('changed_by')[:10]

        return [
            {
                'old_status': h.old_status,
                'new_status': h.new_status,
                'changed_by': h.changed_by.full_name if h.changed_by else 'System',
                'changed_at': h.changed_at,
                'notes': h.notes,
            }
            for h in history
        ]

    def get_latest_location(self, obj):
        """Get the most recent location update for this job."""
        tenant = self.context.get('tenant')
        if not tenant:
            return None

        location = EmployeeLocationUpdate.get_latest_for_event(
            tenant_id=tenant.id,
            event_id=obj.id
        )

        if location:
            return {
                'latitude': float(location.latitude),
                'longitude': float(location.longitude),
                'timestamp': location.timestamp,
                'accuracy': location.accuracy,
            }
        return None

    def _get_customer_participant(self, obj):
        from django.contrib.contenttypes.models import ContentType
        from smoothschedule.identity.users.models import User

        try:
            user_ct = ContentType.objects.get_for_model(User)
            participant = obj.participants.filter(
                role=Participant.Role.CUSTOMER,
                content_type=user_ct
            ).first()
            return participant.content_object if participant else None
        except Exception:
            return None

    def get_can_edit_schedule(self, obj):
        """
        Check if the current user can edit this job's schedule.

        Returns True if the user's linked resource has user_can_edit_schedule=True.
        """
        from django.contrib.contenttypes.models import ContentType
        from smoothschedule.scheduling.schedule.models import Resource

        # Get the current user from context
        request = self.context.get('request')
        if not request or not request.user.is_authenticated:
            return False

        user = request.user

        # Get resources linked to this user
        user_resources = Resource.objects.filter(user=user)

        # Check if any of the user's resources has edit permission
        for resource in user_resources:
            if resource.user_can_edit_schedule:
                return True

        return False


class SetStatusSerializer(serializers.Serializer):
    """Request to change a job's status."""
    status = serializers.ChoiceField(choices=Event.Status.choices)
    notes = serializers.CharField(required=False, allow_blank=True, default='')
    latitude = serializers.DecimalField(
        max_digits=10, decimal_places=7,
        required=False, allow_null=True
    )
    longitude = serializers.DecimalField(
        max_digits=10, decimal_places=7,
        required=False, allow_null=True
    )


class RescheduleJobSerializer(serializers.Serializer):
    """Request to reschedule a job (change start time and/or duration)."""
    start_time = serializers.DateTimeField(required=False, allow_null=True)
    end_time = serializers.DateTimeField(required=False, allow_null=True)
    duration_minutes = serializers.IntegerField(required=False, allow_null=True, min_value=5, max_value=1440)

    def validate(self, attrs):
        """Validate that we have either start/end times or duration."""
        start_time = attrs.get('start_time')
        end_time = attrs.get('end_time')
        duration_minutes = attrs.get('duration_minutes')

        # Must have at least one field to update
        if not start_time and not end_time and not duration_minutes:
            raise serializers.ValidationError(
                "Must provide start_time, end_time, or duration_minutes"
            )

        # If both start_time and end_time are provided, validate end > start
        if start_time and end_time and end_time <= start_time:
            raise serializers.ValidationError(
                "end_time must be after start_time"
            )

        return attrs


class StartEnRouteSerializer(serializers.Serializer):
    """Request to start en-route to a job (includes location)."""
    latitude = serializers.DecimalField(
        max_digits=10, decimal_places=7,
        required=False, allow_null=True
    )
    longitude = serializers.DecimalField(
        max_digits=10, decimal_places=7,
        required=False, allow_null=True
    )
    send_customer_notification = serializers.BooleanField(default=True)


class LocationUpdateSerializer(serializers.Serializer):
    """Employee location update while en-route or in-progress."""
    latitude = serializers.DecimalField(max_digits=10, decimal_places=7)
    longitude = serializers.DecimalField(max_digits=10, decimal_places=7)
    accuracy = serializers.FloatField(required=False, allow_null=True)
    altitude = serializers.FloatField(required=False, allow_null=True)
    heading = serializers.FloatField(required=False, allow_null=True)
    speed = serializers.FloatField(required=False, allow_null=True)
    timestamp = serializers.DateTimeField()
    battery_level = serializers.FloatField(required=False, allow_null=True)


class LocationUpdateResponseSerializer(serializers.Serializer):
    """Response after recording a location update."""
    success = serializers.BooleanField()
    should_continue_tracking = serializers.BooleanField()
    message = serializers.CharField(required=False)


class InitiateCallSerializer(serializers.Serializer):
    """Request to initiate a masked call to customer."""
    # No required fields - customer phone comes from the job
    pass


class InitiateCallResponseSerializer(serializers.Serializer):
    """Response after initiating a call."""
    call_sid = serializers.CharField()
    call_log_id = serializers.IntegerField()
    proxy_number = serializers.CharField()
    status = serializers.CharField()
    message = serializers.CharField()


class SendSMSSerializer(serializers.Serializer):
    """Request to send SMS to customer."""
    message = serializers.CharField(max_length=1600)


class SendSMSResponseSerializer(serializers.Serializer):
    """Response after sending SMS."""
    message_sid = serializers.CharField()
    call_log_id = serializers.IntegerField()
    status = serializers.CharField()


class CallHistorySerializer(serializers.ModelSerializer):
    """Call/SMS history for a job."""
    employee_name = serializers.SerializerMethodField()
    type_display = serializers.CharField(source='get_call_type_display')
    direction_display = serializers.CharField(source='get_direction_display')
    status_display = serializers.CharField(source='get_status_display')

    class Meta:
        model = FieldCallLog
        fields = [
            'id',
            'call_type',
            'type_display',
            'direction',
            'direction_display',
            'status',
            'status_display',
            'duration_seconds',
            'initiated_at',
            'answered_at',
            'ended_at',
            'employee_name',
        ]

    def get_employee_name(self, obj):
        return obj.employee.full_name if obj.employee else None


class EmployeeProfileSerializer(serializers.Serializer):
    """
    Employee profile for the mobile app.

    Includes tenant context and permissions.
    """
    id = serializers.IntegerField()
    email = serializers.EmailField()
    name = serializers.CharField()
    phone = serializers.CharField(allow_null=True)
    role = serializers.CharField()

    # Business context
    business_id = serializers.IntegerField(source='tenant_id')
    business_name = serializers.SerializerMethodField()
    business_subdomain = serializers.SerializerMethodField()

    # Feature flags
    can_use_masked_calls = serializers.SerializerMethodField()
    can_track_location = serializers.SerializerMethodField()

    def get_business_name(self, obj):
        return obj.tenant.name if obj.tenant else None

    def get_business_subdomain(self, obj):
        if obj.tenant:
            domain = obj.tenant.domains.filter(is_primary=True).first()
            if domain:
                return domain.domain.split('.')[0]
        return None

    def get_can_use_masked_calls(self, obj):
        if obj.tenant:
            return obj.tenant.has_feature('can_use_masked_phone_numbers')
        return False

    def get_can_track_location(self, obj):
        if obj.tenant:
            return obj.tenant.has_feature('can_use_mobile_app')
        return False
