"""
Public API Serializers

This module contains serializers for the public API v1.
These serializers expose limited fields appropriate for external integrations,
with proper documentation for OpenAPI schema generation.
"""

from rest_framework import serializers
from drf_spectacular.utils import extend_schema_field
from drf_spectacular.types import OpenApiTypes

from .models import APIToken, APIScope, WebhookSubscription, WebhookDelivery, WebhookEvent


# =============================================================================
# API Token Serializers
# =============================================================================

class APIScopeSerializer(serializers.Serializer):
    """Serializer for listing available scopes."""
    scope = serializers.CharField(help_text="Scope identifier (e.g., 'services:read')")
    description = serializers.CharField(help_text="Human-readable description")


class APITokenCreateSerializer(serializers.Serializer):
    """
    Serializer for creating a new API token.

    The response will include the full token key only once - store it securely!
    """
    name = serializers.CharField(
        max_length=100,
        help_text="Human-readable name for the token (e.g., 'Website Integration')"
    )
    scopes = serializers.ListField(
        child=serializers.ChoiceField(choices=[s[0] for s in APIScope.CHOICES]),
        help_text="List of permission scopes for this token"
    )
    expires_at = serializers.DateTimeField(
        required=False,
        allow_null=True,
        help_text="Optional expiration date (ISO 8601 format)"
    )
    is_sandbox = serializers.BooleanField(
        required=False,
        allow_null=True,
        default=None,
        help_text="If true, creates a test/sandbox token (ss_test_*) instead of live (ss_live_*). If not provided, inherits from current sandbox mode."
    )

    def validate_scopes(self, value):
        """Validate that at least one scope is provided."""
        if not value:
            raise serializers.ValidationError("At least one scope is required.")
        return value


class APITokenResponseSerializer(serializers.ModelSerializer):
    """
    Serializer for API token responses.

    Note: The full 'key' is only included in the creation response.
    """
    key = serializers.CharField(
        read_only=True,
        help_text="The full API token key (only shown once on creation)"
    )

    class Meta:
        model = APIToken
        fields = [
            'id',
            'name',
            'key',
            'key_prefix',
            'scopes',
            'is_active',
            'is_sandbox',
            'created_at',
            'last_used_at',
            'expires_at',
        ]
        read_only_fields = fields


class APITokenListSerializer(serializers.ModelSerializer):
    """Serializer for listing API tokens (without the full key)."""

    class Meta:
        model = APIToken
        fields = [
            'id',
            'name',
            'key_prefix',
            'scopes',
            'is_active',
            'is_sandbox',
            'created_at',
            'last_used_at',
            'expires_at',
        ]
        read_only_fields = fields


# =============================================================================
# Business Serializers
# =============================================================================

class PublicBusinessSerializer(serializers.Serializer):
    """
    Serializer for public business information.

    Exposes only the information appropriate for external integrations.
    """
    id = serializers.UUIDField(
        read_only=True,
        help_text="Unique business identifier"
    )
    name = serializers.CharField(
        read_only=True,
        help_text="Business name"
    )
    subdomain = serializers.CharField(
        read_only=True,
        help_text="Business subdomain (e.g., 'mycompany' for mycompany.smoothschedule.com)"
    )
    logo_url = serializers.URLField(
        read_only=True,
        allow_null=True,
        help_text="URL to the business logo image"
    )
    primary_color = serializers.CharField(
        read_only=True,
        help_text="Primary brand color (hex format, e.g., '#3B82F6')"
    )
    secondary_color = serializers.CharField(
        read_only=True,
        allow_null=True,
        help_text="Secondary brand color (hex format)"
    )
    timezone = serializers.CharField(
        read_only=True,
        help_text="Business timezone (e.g., 'America/New_York')"
    )
    cancellation_window_hours = serializers.IntegerField(
        read_only=True,
        help_text="Minimum hours before appointment start to allow cancellation"
    )


# =============================================================================
# Service Serializers
# =============================================================================

class PublicServiceSerializer(serializers.Serializer):
    """
    Serializer for public service information.

    Represents a bookable service offered by the business.
    """
    id = serializers.UUIDField(
        read_only=True,
        help_text="Unique service identifier"
    )
    name = serializers.CharField(
        read_only=True,
        help_text="Service name"
    )
    description = serializers.CharField(
        read_only=True,
        allow_null=True,
        help_text="Service description"
    )
    duration = serializers.IntegerField(
        read_only=True,
        help_text="Service duration in minutes"
    )
    price = serializers.DecimalField(
        max_digits=10,
        decimal_places=2,
        read_only=True,
        allow_null=True,
        help_text="Service price (null if free or price varies)"
    )
    photos = serializers.ListField(
        child=serializers.URLField(),
        read_only=True,
        help_text="List of photo URLs for the service"
    )
    is_active = serializers.BooleanField(
        read_only=True,
        help_text="Whether the service is currently available for booking"
    )


# =============================================================================
# Resource Serializers
# =============================================================================

class PublicResourceTypeSerializer(serializers.Serializer):
    """Serializer for resource type information."""
    id = serializers.UUIDField(read_only=True)
    name = serializers.CharField(read_only=True)
    category = serializers.CharField(
        read_only=True,
        help_text="Category: 'staff' or 'other'"
    )


class PublicResourceSerializer(serializers.Serializer):
    """
    Serializer for public resource information.

    Represents a bookable resource (staff member, room, equipment, etc.)
    """
    id = serializers.UUIDField(
        read_only=True,
        help_text="Unique resource identifier"
    )
    name = serializers.CharField(
        read_only=True,
        help_text="Resource name"
    )
    description = serializers.CharField(
        read_only=True,
        allow_null=True,
        help_text="Resource description"
    )
    resource_type = PublicResourceTypeSerializer(
        read_only=True,
        help_text="Resource type information"
    )
    photo_url = serializers.URLField(
        read_only=True,
        allow_null=True,
        help_text="URL to the resource photo"
    )
    is_active = serializers.BooleanField(
        read_only=True,
        help_text="Whether the resource is currently available"
    )


# =============================================================================
# Availability Serializers
# =============================================================================

class TimeSlotSerializer(serializers.Serializer):
    """Serializer for an available time slot."""
    start_time = serializers.DateTimeField(
        help_text="Start time of the slot (ISO 8601)"
    )
    end_time = serializers.DateTimeField(
        help_text="End time of the slot (ISO 8601)"
    )
    resource_id = serializers.UUIDField(
        allow_null=True,
        help_text="Resource ID if the slot is tied to a specific resource"
    )
    resource_name = serializers.CharField(
        allow_null=True,
        help_text="Resource name if applicable"
    )


class AvailabilityRequestSerializer(serializers.Serializer):
    """Serializer for availability query parameters."""
    service_id = serializers.UUIDField(
        required=True,
        help_text="Service ID to check availability for"
    )
    resource_id = serializers.UUIDField(
        required=False,
        allow_null=True,
        help_text="Optional: specific resource to check"
    )
    date = serializers.DateField(
        required=True,
        help_text="Start date for availability check (YYYY-MM-DD)"
    )
    days = serializers.IntegerField(
        required=False,
        default=7,
        min_value=1,
        max_value=30,
        help_text="Number of days to check (1-30, default: 7)"
    )


class AvailabilityResponseSerializer(serializers.Serializer):
    """Serializer for availability response."""
    service = PublicServiceSerializer(help_text="Service information")
    date_range = serializers.DictField(
        help_text="Date range checked",
        child=serializers.DateField()
    )
    slots = TimeSlotSerializer(
        many=True,
        help_text="Available time slots"
    )


# =============================================================================
# Appointment/Booking Serializers
# =============================================================================

class PublicCustomerSerializer(serializers.Serializer):
    """Serializer for customer information in appointments."""
    id = serializers.UUIDField(read_only=True)
    name = serializers.CharField(read_only=True)
    email = serializers.EmailField(read_only=True)
    phone = serializers.CharField(read_only=True, allow_null=True)


class PublicAppointmentSerializer(serializers.Serializer):
    """
    Serializer for appointment information.

    Represents a scheduled appointment/booking.
    """
    id = serializers.UUIDField(
        read_only=True,
        help_text="Unique appointment identifier"
    )
    service = PublicServiceSerializer(
        read_only=True,
        help_text="Service being booked"
    )
    resource = PublicResourceSerializer(
        read_only=True,
        allow_null=True,
        help_text="Resource assigned (if applicable)"
    )
    customer = PublicCustomerSerializer(
        read_only=True,
        help_text="Customer information"
    )
    start_time = serializers.DateTimeField(
        read_only=True,
        help_text="Appointment start time (ISO 8601)"
    )
    end_time = serializers.DateTimeField(
        read_only=True,
        help_text="Appointment end time (ISO 8601)"
    )
    status = serializers.ChoiceField(
        choices=['scheduled', 'confirmed', 'cancelled', 'completed', 'no_show'],
        read_only=True,
        help_text="Appointment status"
    )
    notes = serializers.CharField(
        read_only=True,
        allow_null=True,
        help_text="Notes for the appointment"
    )
    created_at = serializers.DateTimeField(
        read_only=True,
        help_text="When the appointment was created"
    )


class AppointmentCreateSerializer(serializers.Serializer):
    """
    Serializer for creating a new appointment.

    You must provide either customer_id (for existing customer)
    or customer details (email required, name and phone optional).
    """
    service_id = serializers.UUIDField(
        required=True,
        help_text="ID of the service to book"
    )
    resource_id = serializers.UUIDField(
        required=False,
        allow_null=True,
        help_text="Optional: specific resource to book with"
    )
    start_time = serializers.DateTimeField(
        required=True,
        help_text="Requested start time (ISO 8601)"
    )
    notes = serializers.CharField(
        required=False,
        allow_blank=True,
        max_length=1000,
        help_text="Optional notes for the appointment"
    )

    # Customer identification - either ID or details
    customer_id = serializers.UUIDField(
        required=False,
        allow_null=True,
        help_text="ID of an existing customer"
    )
    customer_email = serializers.EmailField(
        required=False,
        help_text="Customer email (required if customer_id not provided)"
    )
    customer_name = serializers.CharField(
        required=False,
        max_length=200,
        help_text="Customer name"
    )
    customer_phone = serializers.CharField(
        required=False,
        max_length=20,
        help_text="Customer phone number"
    )

    def validate(self, data):
        """Validate that either customer_id or customer_email is provided."""
        customer_id = data.get('customer_id')
        customer_email = data.get('customer_email')

        if not customer_id and not customer_email:
            raise serializers.ValidationError({
                'customer_id': 'Either customer_id or customer_email is required.',
                'customer_email': 'Either customer_id or customer_email is required.',
            })

        return data


class AppointmentUpdateSerializer(serializers.Serializer):
    """Serializer for updating/rescheduling an appointment."""
    start_time = serializers.DateTimeField(
        required=False,
        help_text="New start time (ISO 8601)"
    )
    resource_id = serializers.UUIDField(
        required=False,
        allow_null=True,
        help_text="New resource assignment"
    )
    notes = serializers.CharField(
        required=False,
        allow_blank=True,
        max_length=1000,
        help_text="Updated notes"
    )
    status = serializers.ChoiceField(
        choices=['confirmed', 'completed'],
        required=False,
        help_text="Update status (limited options via API)"
    )


class AppointmentCancelSerializer(serializers.Serializer):
    """Serializer for cancelling an appointment."""
    reason = serializers.CharField(
        required=False,
        allow_blank=True,
        max_length=500,
        help_text="Optional cancellation reason"
    )


# =============================================================================
# Customer Serializers
# =============================================================================

class CustomerCreateSerializer(serializers.Serializer):
    """Serializer for creating a new customer."""
    email = serializers.EmailField(
        required=True,
        help_text="Customer email address"
    )
    name = serializers.CharField(
        required=True,
        max_length=200,
        help_text="Customer full name"
    )
    phone = serializers.CharField(
        required=False,
        max_length=20,
        allow_blank=True,
        help_text="Customer phone number"
    )
    notes = serializers.CharField(
        required=False,
        allow_blank=True,
        help_text="Notes about the customer"
    )


class CustomerUpdateSerializer(serializers.Serializer):
    """Serializer for updating customer information."""
    name = serializers.CharField(
        required=False,
        max_length=200,
        help_text="Customer full name"
    )
    phone = serializers.CharField(
        required=False,
        max_length=20,
        allow_blank=True,
        help_text="Customer phone number"
    )
    notes = serializers.CharField(
        required=False,
        allow_blank=True,
        help_text="Notes about the customer"
    )


class CustomerDetailSerializer(serializers.Serializer):
    """Detailed customer information including appointment history."""
    id = serializers.UUIDField(read_only=True)
    email = serializers.EmailField(read_only=True)
    name = serializers.CharField(read_only=True)
    phone = serializers.CharField(read_only=True, allow_null=True)
    created_at = serializers.DateTimeField(read_only=True)
    total_appointments = serializers.IntegerField(
        read_only=True,
        help_text="Total number of appointments"
    )
    last_appointment_at = serializers.DateTimeField(
        read_only=True,
        allow_null=True,
        help_text="Date of last appointment"
    )


# =============================================================================
# Webhook Serializers
# =============================================================================

class WebhookEventSerializer(serializers.Serializer):
    """Serializer for listing available webhook events."""
    event = serializers.CharField(help_text="Event type identifier")
    description = serializers.CharField(help_text="Human-readable description")


class WebhookSubscriptionCreateSerializer(serializers.Serializer):
    """Serializer for creating a webhook subscription."""
    url = serializers.URLField(
        required=True,
        help_text="HTTPS URL to receive webhook payloads"
    )
    events = serializers.ListField(
        child=serializers.ChoiceField(choices=[e[0] for e in WebhookEvent.CHOICES]),
        required=True,
        help_text="List of event types to subscribe to"
    )
    description = serializers.CharField(
        required=False,
        allow_blank=True,
        help_text="Optional description for this webhook"
    )

    def validate_url(self, value):
        """Validate that the URL uses HTTPS."""
        if not value.startswith('https://'):
            raise serializers.ValidationError("Webhook URL must use HTTPS.")
        return value

    def validate_events(self, value):
        """Validate that at least one event is specified."""
        if not value:
            raise serializers.ValidationError("At least one event is required.")
        return value


class WebhookSubscriptionSerializer(serializers.ModelSerializer):
    """Serializer for webhook subscription responses."""

    class Meta:
        model = WebhookSubscription
        fields = [
            'id',
            'url',
            'events',
            'description',
            'is_active',
            'created_at',
            'failure_count',
            'last_triggered_at',
            'last_success_at',
            'last_failure_at',
        ]
        read_only_fields = fields


class WebhookSubscriptionWithSecretSerializer(WebhookSubscriptionSerializer):
    """Serializer that includes the secret (only on creation)."""
    secret = serializers.CharField(
        read_only=True,
        help_text="Secret for verifying webhook signatures (shown only once)"
    )

    class Meta(WebhookSubscriptionSerializer.Meta):
        fields = WebhookSubscriptionSerializer.Meta.fields + ['secret']


class WebhookSubscriptionUpdateSerializer(serializers.Serializer):
    """Serializer for updating a webhook subscription."""
    url = serializers.URLField(
        required=False,
        help_text="New URL (must be HTTPS)"
    )
    events = serializers.ListField(
        child=serializers.ChoiceField(choices=[e[0] for e in WebhookEvent.CHOICES]),
        required=False,
        help_text="New list of events"
    )
    is_active = serializers.BooleanField(
        required=False,
        help_text="Enable or disable the subscription"
    )
    description = serializers.CharField(
        required=False,
        allow_blank=True,
        help_text="Updated description"
    )

    def validate_url(self, value):
        """Validate that the URL uses HTTPS."""
        if value and not value.startswith('https://'):
            raise serializers.ValidationError("Webhook URL must use HTTPS.")
        return value


class WebhookDeliverySerializer(serializers.ModelSerializer):
    """Serializer for webhook delivery history."""

    class Meta:
        model = WebhookDelivery
        fields = [
            'id',
            'event_type',
            'event_id',
            'response_status',
            'created_at',
            'delivered_at',
            'success',
            'retry_count',
            'error_message',
        ]
        read_only_fields = fields


class WebhookDeliveryDetailSerializer(WebhookDeliverySerializer):
    """Detailed webhook delivery including payload."""
    payload = serializers.JSONField(
        read_only=True,
        help_text="The payload that was sent"
    )
    response_body = serializers.CharField(
        read_only=True,
        help_text="Response body received (truncated)"
    )

    class Meta(WebhookDeliverySerializer.Meta):
        fields = WebhookDeliverySerializer.Meta.fields + ['payload', 'response_body']


# =============================================================================
# Error Serializers
# =============================================================================

class ErrorSerializer(serializers.Serializer):
    """Standard error response format."""
    error = serializers.CharField(
        help_text="Error code (e.g., 'validation_error', 'not_found')"
    )
    message = serializers.CharField(
        help_text="Human-readable error message"
    )
    details = serializers.DictField(
        required=False,
        help_text="Field-specific error details (for validation errors)"
    )


class RateLimitErrorSerializer(ErrorSerializer):
    """Rate limit exceeded error response."""
    retry_after = serializers.IntegerField(
        help_text="Seconds to wait before retrying"
    )
