from rest_framework import serializers
from .models import User
from django.contrib.auth.hashers import make_password
from userSettings.models import UserSettings
from employeetypes.models import EmployeeType

class UserReadSerializer(serializers.ModelSerializer):
    firstname = serializers.CharField()
    middlename = serializers.CharField(required=False, allow_blank=True)
    lastname = serializers.CharField()
    supervisor_code = serializers.CharField(source='settings.supervisor_code', read_only=True)
    is_access = serializers.BooleanField(source='settings.is_access', read_only=True)
    user_type = serializers.CharField(source='settings.user_type.code', read_only=True)

    working_time_policy = serializers.SerializerMethodField()
    
    class Meta:
        model = User
        fields = ['id', 'employee_no', 'firstname', 'middlename', 'lastname', 'email', 'user_type', 'supervisor_code', 'is_access', 
                 'hire_start_date', 'hire_end_date', 'lang', 'must_change_password', 'working_time_policy']
        read_only_fields = ['id']
    
    def get_working_time_policy(self, obj):
        """Return policy name and ID if assigned"""
        if obj.working_time_policy:
            return {
                'id': str(obj.working_time_policy.id),
                'name': obj.working_time_policy.name
            }
        return None

class UserSerializer(serializers.ModelSerializer):
    name = serializers.SerializerMethodField()
    firstname = serializers.CharField(required=False)
    middlename = serializers.CharField(required=False, allow_blank=True)
    lastname = serializers.CharField(required=False)
    employee_no = serializers.CharField(required=False)
    supervisor_code = serializers.CharField(source='settings.supervisor_code', required=False)
    is_access = serializers.BooleanField(source='settings.is_access', required=False)
    user_type = serializers.CharField(source='settings.user_type.code', required=False)
    password = serializers.CharField(write_only=True, required=False)

    working_time_policy = serializers.UUIDField(required=False, allow_null=True, write_only=True)
    working_time_policy_name = serializers.SerializerMethodField(read_only=True)
    
    class Meta:
        model = User
        fields = ['id', 'employee_no', 'name', 'firstname', 'middlename', 'lastname', 'email', 'password', 'user_type', 'supervisor_code', 
                 'is_access', 'hire_start_date', 'hire_end_date', 'lang', 'working_time_policy', 'working_time_policy_name']
        read_only_fields = ['id', 'working_time_policy_name']

    def get_name(self, obj):
        name_parts = [obj.firstname]
        if obj.middlename:
            name_parts.append(obj.middlename)
        name_parts.append(obj.lastname)
        return ' '.join(name_parts)
    
    def get_working_time_policy_name(self, obj):
        """Return policy name if assigned"""
        if obj.working_time_policy:
            return obj.working_time_policy.name
        return None

    def validate_email(self, value):
        # Get the current instance if this is an update
        instance = getattr(self, 'instance', None)
        
        # Check if email exists, excluding the current user if this is an update
        if instance:
            if User.objects.filter(email=value).exclude(id=instance.id).exists():
                raise serializers.ValidationError("A user with this email already exists.")
        else:
            if User.objects.filter(email=value).exists():
                raise serializers.ValidationError("A user with this email already exists.")
        return value

    def validate_employee_no(self, value):
        # Only check for uniqueness if this is a new user (no instance) or if employee_no is being changed
        if not self.instance or (self.instance and self.instance.employee_no != value):
            if User.objects.filter(employee_no=value).exists():
                raise serializers.ValidationError("A user with this employee number already exists.")
        return value

    def validate(self, data):
        # Convert string boolean to actual boolean if needed
        if 'settings' in data and 'is_access' in data['settings']:
            is_access = data['settings']['is_access']
            if isinstance(is_access, str):
                data['settings']['is_access'] = is_access.lower() == 'true'
        return data

    def create(self, validated_data):
        settings_data = {}
        
        # Extract settings data from validated_data
        if 'settings' in validated_data:
            settings = validated_data.pop('settings')
            # Handle user_type code correctly
            user_type_code = settings.get('user_type', {}).get('code') if isinstance(settings.get('user_type'), dict) else settings.get('user_type')
            settings_data = {
                'supervisor_code': settings.get('supervisor_code'),
                'is_access': settings.get('is_access', False),
                'user_type': user_type_code
            }
        else:
            # Handle direct fields if settings is not provided
            settings_data = {
                'supervisor_code': validated_data.pop('supervisor_code', None),
                'is_access': validated_data.pop('is_access', False),
                'user_type': validated_data.pop('user_type', None)
            }
        
        if 'password' in validated_data:
            validated_data['password'] = make_password(validated_data['password'])
        
        # Handle name fields
        if 'name' in validated_data:
            name_parts = validated_data.pop('name').split()
            if len(name_parts) >= 3:
                validated_data['firstname'] = name_parts[0]
                validated_data['middlename'] = name_parts[1]
                validated_data['lastname'] = ' '.join(name_parts[2:])
            elif len(name_parts) == 2:
                validated_data['firstname'] = name_parts[0]
                validated_data['middlename'] = ''
                validated_data['lastname'] = name_parts[1]
            else:
                validated_data['firstname'] = name_parts[0] if name_parts else ''
                validated_data['middlename'] = ''
                validated_data['lastname'] = ''

        # Remove user_type from validated_data if it exists
        validated_data.pop('user_type', None)

        # Handle working_time_policy
        working_time_policy_id = validated_data.pop('working_time_policy', None)
        
        # Set must_change_password if password was provided (temporary password scenario)
        if 'must_change_password' in validated_data:
            must_change = validated_data.pop('must_change_password')
            user = User.objects.create(**validated_data)
            user.must_change_password = must_change
            user.save()
        else:
            user = User.objects.create(**validated_data)
        
        # Assign working time policy if provided
        if working_time_policy_id:
            from company.models import WorkingTimePolicy
            try:
                policy = WorkingTimePolicy.objects.get(id=working_time_policy_id, company_id=user.company_id if hasattr(user, 'company_id') else None)
                user.working_time_policy = policy
                user.save()
            except WorkingTimePolicy.DoesNotExist:
                pass  # Silently ignore if policy doesn't exist
        
        # Handle user_type - get EmployeeType by code
        if settings_data.get('user_type'):
            try:
                employee_type = EmployeeType.objects.get(code=settings_data['user_type'])
                settings_data['user_type'] = employee_type
            except EmployeeType.DoesNotExist:
                raise serializers.ValidationError({"user_type": f"Invalid employee type code: {settings_data['user_type']}"})
        
        UserSettings.objects.create(user=user, **settings_data)
        return user

    def update(self, instance, validated_data):
        settings_data = {}
        
        # Extract settings data
        if 'settings' in validated_data:
            settings = validated_data.pop('settings')
            # Handle user_type code correctly
            user_type_code = settings.get('user_type', {}).get('code') if isinstance(settings.get('user_type'), dict) else settings.get('user_type')
            settings_data = {
                'supervisor_code': settings.get('supervisor_code'),
                'is_access': settings.get('is_access'),
                'user_type': user_type_code
            }
        else:
            # Handle direct fields if settings is not provided
            settings_data = {
                'supervisor_code': validated_data.pop('supervisor_code', None),
                'is_access': validated_data.pop('is_access', None),
                'user_type': validated_data.pop('user_type', None)
            }
        
        if 'password' in validated_data:
            validated_data['password'] = make_password(validated_data['password'])
        
        # Update name if provided
        if 'name' in validated_data:
            name_parts = validated_data.pop('name').split()
            if len(name_parts) >= 3:
                validated_data['firstname'] = name_parts[0]
                validated_data['middlename'] = name_parts[1]
                validated_data['lastname'] = ' '.join(name_parts[2:])
            elif len(name_parts) == 2:
                validated_data['firstname'] = name_parts[0]
                validated_data['middlename'] = ''
                validated_data['lastname'] = name_parts[1]
            else:
                validated_data['firstname'] = name_parts[0] if name_parts else instance.firstname
                validated_data['middlename'] = instance.middlename
                validated_data['lastname'] = instance.lastname

        # Remove user_type from validated_data if it exists
        validated_data.pop('user_type', None)
        
        # Handle working_time_policy
        working_time_policy_id = validated_data.pop('working_time_policy', None)
        if working_time_policy_id is not None:
            from company.models import WorkingTimePolicy
            if working_time_policy_id:
                try:
                    # Get company_id from user if available, or from request context
                    company_id = getattr(instance, 'company_id', None)
                    if not company_id and hasattr(self.context.get('request'), 'user'):
                        company_id = getattr(self.context['request'].user, 'company_id', None)
                    
                    policy = WorkingTimePolicy.objects.get(id=working_time_policy_id, company_id=company_id)
                    instance.working_time_policy = policy
                except WorkingTimePolicy.DoesNotExist:
                    pass  # Silently ignore if policy doesn't exist
            else:
                instance.working_time_policy = None

        # Update user fields
        for attr, value in validated_data.items():
            setattr(instance, attr, value)
        instance.save()

        # Update settings
        if settings_data:
            settings = instance.settings
            # Handle user_type - get EmployeeType by code
            if 'user_type' in settings_data:
                try:
                    employee_type = EmployeeType.objects.get(code=settings_data['user_type'])
                    settings_data['user_type'] = employee_type
                except EmployeeType.DoesNotExist:
                    raise serializers.ValidationError({"user_type": f"Invalid employee type code: {settings_data['user_type']}"})
            
            for attr, value in settings_data.items():
                setattr(settings, attr, value)
            settings.save()

        return instance 