from rest_framework import serializers
from django.contrib.auth import authenticate
from .models import User, UserPrescription, ExerciseLog, RegistrationCode


class RegisterSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True, min_length=8)
    invite_code = serializers.CharField(write_only=True)

    class Meta:
        model = User
        fields = ('email', 'password', 'display_name', 'invite_code')

    def validate_invite_code(self, value):
        try:
            code = RegistrationCode.objects.get(code=value.upper())
        except RegistrationCode.DoesNotExist:
            raise serializers.ValidationError('Invalid invite code.')
        if not code.is_valid():
            raise serializers.ValidationError('This invite code has expired or already been used.')
        return value

    def create(self, validated_data):
        invite_code = validated_data.pop('invite_code')
        user = User.objects.create_user(**validated_data)
        code = RegistrationCode.objects.get(code=invite_code.upper())
        code.used_by = user
        code.save()
        return user


class LoginSerializer(serializers.Serializer):
    email = serializers.EmailField()
    password = serializers.CharField(write_only=True)

    def validate(self, data):
        user = authenticate(username=data['email'], password=data['password'])
        if not user:
            raise serializers.ValidationError('Invalid email or password.')
        if not user.is_active:
            raise serializers.ValidationError('Account is disabled.')
        data['user'] = user
        return data


class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'email', 'display_name', 'is_therapist', 'created_at')
        read_only_fields = ('id', 'is_therapist', 'created_at')


class ExerciseLogSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExerciseLog
        fields = ('id', 'breathing_mode', 'visualization_type', 'duration_seconds', 'prescribed_duration_seconds', 'breath_count', 'completed_at')
        read_only_fields = ('id', 'completed_at')


class PatientSummarySerializer(serializers.ModelSerializer):
    """Minimal user info returned in therapist's patient list."""
    prescription = serializers.SerializerMethodField()
    total_sessions = serializers.SerializerMethodField()
    last_session_at = serializers.SerializerMethodField()

    class Meta:
        model = User
        fields = ('id', 'email', 'display_name', 'prescription', 'total_sessions', 'last_session_at')

    def get_prescription(self, obj):
        try:
            p = obj.prescription
            return {
                'breathing_mode': p.breathing_mode,
                'visualization_type': p.visualization_type,
                'bpm': p.bpm,
                'duration_seconds': p.duration_seconds,
                'locked': p.locked,
                'updated_at': p.updated_at,
            }
        except UserPrescription.DoesNotExist:
            return None

    def get_total_sessions(self, obj):
        return obj.exercise_logs.count()

    def get_last_session_at(self, obj):
        log = obj.exercise_logs.first()  # ordered by -completed_at
        return log.completed_at if log else None


class PrescriptionSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserPrescription
        fields = ('breathing_mode', 'visualization_type', 'bpm', 'duration_seconds', 'locked', 'updated_at')
        read_only_fields = ('updated_at',)


class RegistrationCodeSerializer(serializers.ModelSerializer):
    used_by_email = serializers.SerializerMethodField()
    status = serializers.SerializerMethodField()
    expires_at = serializers.SerializerMethodField()

    class Meta:
        model = RegistrationCode
        fields = ('id', 'code', 'created_at', 'expires_at', 'status', 'used_by_email')
        read_only_fields = fields

    def get_used_by_email(self, obj):
        return obj.used_by.email if obj.used_by else None

    def get_status(self, obj):
        if obj.used_by_id is not None:
            return 'used'
        if obj.is_valid():
            return 'pending'
        return 'expired'

    def get_expires_at(self, obj):
        from datetime import timedelta
        return obj.created_at + timedelta(hours=28)
