from rest_framework import serializers
from apps.companies.models import (
    Company, OfficeHours, SalesTiming, CatchPhrase,
    CompanyHistory, Holiday, CompanyBotSettings
)
from apps.permissions.models import UserCompanyRole, Role
from apps.core.serializers import UserBasicInfoSerializer
from django.db import models

from django.contrib.auth import get_user_model

from apps.companies.utils import normalize_website
from django.db.models import Count

User = get_user_model()


class CompanyBotDetailSerializer(serializers.ModelSerializer):
    class Meta:
        model = CompanyBotSettings
        fields = ['id', 'bot_name', 'phone_number']


class CompanyBotsListSerializer(serializers.ModelSerializer):
    bots = CompanyBotDetailSerializer(source='bot_settings', many=True, read_only=True)

    class Meta:
        model = Company
        fields = ['id', 'name', 'bots']


class CompanyBotSettingsSerializer(serializers.ModelSerializer):
    company_name = serializers.CharField(source='company.name', read_only=True)

    class Meta:
        model = CompanyBotSettings
        fields = [
            'id', 'company', 'company_name', 'bot_name',
            'phone_number', 'is_active',
            'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'company', 'company_name', 'created_at', 'updated_at']

    # def to_representation(self, instance):
    #     """Customize output for bot_name"""
    #     rep = super().to_representation(instance)
    #     if instance.bot_name:
    #         rep["bot_name"] = instance.get_bot_name_display()
    #     return rep


class BotDetailsSerializer(serializers.ModelSerializer):
    class Meta:
        model = CompanyBotSettings
        fields = ['id', 'bot_name']
        read_only_fields = ['id', 'bot_name']
    #
    # def to_representation(self, instance):
    #     """Return display label instead of DB value for bot_name"""
    #     rep = super().to_representation(instance)
    #     if instance.bot_name:
    #         rep['bot_name'] = instance.get_bot_name_display()
    #     return rep


class HolidaySerializer(serializers.ModelSerializer):
    company_name = serializers.CharField(source='company.name', read_only=True)
    duration_days = serializers.SerializerMethodField()
    bots = serializers.PrimaryKeyRelatedField(
        queryset=CompanyBotSettings.objects.all(),
        many=True,
        required=False,
        allow_empty=True
    )
    bots_detail = BotDetailsSerializer(
        source='bots',
        many=True,
        read_only=True
    )

    class Meta:
        model = Holiday
        fields = [
            'id', 'company', 'company_name', 'name', 'message',
            'start_date', 'end_date', 'is_active', 'bots', 'bots_detail', 'duration_days',
            'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'company', 'company_name', 'duration_days', 'created_at', 'updated_at']

    def get_duration_days(self, obj):
        """Get number of days in holiday period"""
        return obj.get_duration_days()

    def validate(self, data):
        """Validate holiday dates"""
        start_date = data.get('start_date')
        end_date = data.get('end_date')

        if start_date and end_date:
            if start_date > end_date:
                raise serializers.ValidationError("End date must be after or equal to start date")

        return data


class OfficeHoursSerializer(serializers.ModelSerializer):
    day_display = serializers.CharField(source='get_day_display', read_only=True)

    class Meta:
        model = OfficeHours
        fields = [
            'id', 'day', 'day_display', 'is_open', 'start_time', 'end_time'
        ]
        read_only_fields = ['id']

    def validate(self, data):

        """Custom validation for office hours"""
        company = self.context['request'].user.active_company
        day = data.get('day')

        # Case 1: prevent duplicates on create
        if self.instance is None and OfficeHours.objects.filter(company=company, day=day).exists():
            raise serializers.ValidationError(
                {"day": f"Office hours for {day.capitalize()} already exist for this company."}
            )

        # Case 2: prevent duplicates on update (ignore self)
        if self.instance and OfficeHours.objects.filter(company=company, day=day).exclude(id=self.instance.id).exists():
            raise serializers.ValidationError(
                {"day": f"Office hours for {day.capitalize()} already exist for this company."}
            )
        if data.get('is_open'):
            if not data.get('start_time') or not data.get('end_time'):
                raise serializers.ValidationError("Start and end times are required when office is open")

            if data['start_time'] >= data['end_time']:
                raise serializers.ValidationError("End time must be after start time")

        return data


class SalesTimingSerializer(serializers.ModelSerializer):
    company_name = serializers.CharField(source='company.name', read_only=True)

    class Meta:
        model = SalesTiming
        fields = [
            'id', 'company', 'company_name', 'start_time', 'end_time',
            'is_active', 'bot', 'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'company', 'company_name', 'created_at', 'updated_at']

    # def to_representation(self, instance):
    #     """Customize output for bot"""
    #     rep = super().to_representation(instance)
    #     if instance.bot:
    #         rep["bot"] = instance.get_bot_display()
    #     return rep

    def validate(self, data):
        """Custom validation for sales timing"""
        # For partial updates (PATCH), only validate fields that are provided
        if self.partial:
            # If start_time is provided, end_time must also be provided
            if 'start_time' in data and 'end_time' not in data:
                raise serializers.ValidationError("If start_time is provided, end_time must also be provided")

            # If end_time is provided, start_time must also be provided
            if 'end_time' in data and 'start_time' not in data:
                raise serializers.ValidationError("If end_time is provided, start_time must also be provided")

            # If both times are provided, validate the relationship
            if 'start_time' in data and 'end_time' in data:
                if data['start_time'] >= data['end_time']:
                    raise serializers.ValidationError("End time must be after start time")
        else:
            # For full updates (POST/PUT), validate all required fields
            if not data.get('start_time') or not data.get('end_time'):
                raise serializers.ValidationError("Start and end times are required")

            if data['start_time'] >= data['end_time']:
                raise serializers.ValidationError("End time must be after start time")

        return data


class CatchPhraseSerializer(serializers.ModelSerializer):
    company_name = serializers.CharField(source='company.name', read_only=True)

    class Meta:
        model = CatchPhrase
        fields = [
            'id', 'company', 'company_name', 'phrase', 'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'company', 'company_name', 'created_at', 'updated_at']

    def validate(self, data):
        """Custom validation for catch phrase"""
        if not data.get('phrase') or not data.get('phrase').strip():
            raise serializers.ValidationError("Catch phrase cannot be empty")

        return data


class CompanyHistorySerializer(serializers.ModelSerializer):
    updated_by_username = serializers.CharField(source='updated_by.username', read_only=True)
    company_name = serializers.CharField(source='company.name', read_only=True)

    class Meta:
        model = CompanyHistory
        fields = [
            'id', 'company', 'company_name', 'updated_by', 'updated_by_username',
            'action', 'model_name', 'object_id', 'details', 'created_at'
        ]
        read_only_fields = ['id', 'company_name', 'updated_by_username', 'created_at']


class MissingUserSerializer(serializers.ModelSerializer):
    """Serializer for users in missing_call_notify_to field"""

    class Meta:
        model = User  # Replace with actual User model
        fields = ['id', 'username']  # Adjust fields as necessary


class RoleSerializer(serializers.ModelSerializer):
    """Serializer for roles"""
    permissions_count = serializers.SerializerMethodField()

    class Meta:
        model = Role
        fields = ['id', 'name', 'permissions_count']

    def get_permissions_count(self, obj):
        """Return number of permissions linked to this role"""
        return obj.permissions.count()


class CurrentUserRoleMixin:
    def get_current_user_role(self, obj):
        request = self.context.get("request")

        if not request or not request.user or request.user.is_anonymous or request.user.is_superuser:
            return None

        user = request.user

        if not hasattr(user, "_company_role_cache"):
            user._company_role_cache = {
                ucr.company_id: ucr.role
                for ucr in UserCompanyRole.objects.filter(
                    user=user, is_active=True
                ).select_related("role")
            }

        role = user._company_role_cache.get(obj.id)
        if not role:
            return None

        return RoleSerializer(role, context=self.context).data


class CompanySerializer(CurrentUserRoleMixin, serializers.ModelSerializer):
    """Single serializer for Company model - handles create, update, and read"""
    user_count = serializers.SerializerMethodField()
    active_users_count = serializers.SerializerMethodField()
    inactive_users_count = serializers.SerializerMethodField()
    available_users_count = serializers.SerializerMethodField()
    default_transfer_staff_name = serializers.SerializerMethodField()
    office_hours = OfficeHoursSerializer(many=True, read_only=True)
    office_hours_summary = serializers.SerializerMethodField()
    sales_timings = SalesTimingSerializer(many=True, read_only=True)
    sales_timings_summary = serializers.SerializerMethodField()
    catch_phrases = CatchPhraseSerializer(many=True, read_only=True)
    catch_phrases_summary = serializers.SerializerMethodField()
    users = UserBasicInfoSerializer(many=True, read_only=True)
    current_user_role = serializers.SerializerMethodField()

    missing_call_notify_to = serializers.PrimaryKeyRelatedField(
        queryset=User.objects.all(),
        many=True,
        required=False,
        allow_empty=True
    )

    missing_call_notify_to_details = MissingUserSerializer(
        source='missing_call_notify_to',
        many=True,
        read_only=True
    )

    class Meta:
        model = Company
        fields = [
            'id', 'name', 'phone', 'office_time', 'bdc_number', 'timezone',
            'missing_call_notify_to', 'missing_call_notify_to_details',
            'default_transfer_staff', 'default_transfer_staff_name', 'is_active',
            'created_at', 'updated_at', 'user_count', 'active_users_count', 'inactive_users_count','available_users_count', 'office_hours',
            'office_hours_summary', 'sales_timings', 'sales_timings_summary',
            'catch_phrases', 'catch_phrases_summary', 'website', 'bio', 'users', 'current_user_role'
        ]
        read_only_fields = ['id', 'created_at', 'updated_at', 'user_count', 'office_hours_summary',
                            'sales_timings_summary', 'catch_phrases_summary']

    def get_user_count(self, obj):
        """Get the number of users in this company"""
        return obj.user_count if hasattr(obj, 'user_count') else obj.users.count()

    def get_active_users_count(self, obj):
        """Get the number of users in this company"""
        return obj.active_users_count if hasattr(obj, 'active_users_count') else obj.users.filter(
            is_active=True).count()

    def get_inactive_users_count(self, obj):
        """Get the number of users in this company"""
        return obj.inactive_users_count if hasattr(obj, 'inactive_users_count') else obj.users.filter(
            is_active=False).count()

    def get_available_users_count(self, obj):
        """Get the number of users in this company"""
        return obj.available_users_count if hasattr(obj, 'available_users_count') else obj.users.filter(
            is_active=True, is_available=True).count()

    def validate_missing_call_notify_to(self, value):
        """Validate that all user IDs exist and are active"""
        if value:
            # Check if all users exist and are active
            user_ids = [user.id for user in value]
            existing_users = User.objects.filter(id__in=user_ids, is_active=True)
            if len(existing_users) != len(value):
                raise serializers.ValidationError("Some user IDs are invalid or inactive")
        return value

    def get_default_transfer_staff_name(self, obj):
        """Get the name of default transfer staff"""
        return obj.get_default_transfer_staff_name()

    def get_office_hours_summary(self, obj):
        """Get office hours summary"""
        return obj.get_office_hours_summary()

    def get_sales_timings_summary(self, obj):
        """Get sales timings summary"""
        return obj.get_sales_timings_summary()

    def get_catch_phrases_summary(self, obj):
        """Get catch phrases summary"""
        return obj.get_catch_phrases_summary()

    def validate_default_transfer_staff(self, value):
        """Validate that default transfer staff belongs to this company"""
        if value and self.instance:
            # Check if user belongs to this company
            if not value.companies.filter(id=self.instance.id).exists():
                raise serializers.ValidationError(
                    "Default transfer staff must belong to this company"
                )
        return value

    def validate_name(self, value):
        """Validate unique name only when creating new company"""
        if self.instance is None:  # Creating new record
            if Company.objects.filter(name=value).exists():
                raise serializers.ValidationError("Company with this name already exists.")
        return value

    def validate_phone(self, value):
        """Validate unique phone only when creating new company"""
        if value and self.instance is None:  # Add 'value and' check
            if Company.objects.filter(phone=value).exists():
                raise serializers.ValidationError("Company with this phone number already exists.")
        return value

    # def validate_website(self, value):
    #     """Validate unique website only when creating new company"""
    #     if value and self.instance is None:  # Add 'value and' check
    #         if Company.objects.filter(website=value).exists():
    #             raise serializers.ValidationError("Company with this website already exists.")
    #     return value

    def validate_website(self, value):
        """Validate unique website only when creating new company"""
        if not value or self.instance is not None:
            return value

        normalized_value = normalize_website(value)

        print("website validation")
        if Company.objects.annotate(
                normalized=models.Func(
                    models.F('website'),
                    function='LOWER'
                )
        ).filter(website__icontains=normalized_value).exists():
            print("website exists")
            raise serializers.ValidationError("Company with this website already exists.")

        return value


class CompanySummarySerializer(CurrentUserRoleMixin, serializers.ModelSerializer):
    """Serializer for company summary in user's company list"""
    role_name = serializers.SerializerMethodField()
    is_active_company = serializers.SerializerMethodField()
    available_users_count = serializers.SerializerMethodField()
    active_users_count = serializers.SerializerMethodField()
    inactive_users_count = serializers.SerializerMethodField()
    user_count = serializers.SerializerMethodField()
    users = UserBasicInfoSerializer(many=True)
    current_user_role = serializers.SerializerMethodField()

    class Meta:
        model = Company
        fields = ['id', 'name', 'phone', 'office_time', 'timezone',
                  'role_name', 'is_active_company', 'is_active', 'active_users_count', 'inactive_users_count','available_users_count', 'bio',
                  'website', 'user_count', 'users', 'current_user_role']

    def get_user_count(self, obj):
        """Get the number of users in this company"""
        return obj.get_user_count()

    def get_active_users_count(self, obj):
        """Get the number of users in this company"""
        return obj.active_users_count if hasattr(obj, 'active_users_count') else obj.users.filter(
            is_active=True).count()

    def get_available_users_count(self, obj):
        """Get the number of users in this company"""
        return obj.available_users_count if hasattr(obj, 'available_users_count') else obj.users.filter(
            is_active=True, is_available=True).count()

    def get_inactive_users_count(self, obj):
        """Get the number of users in this company"""
        return obj.inactive_users_count if hasattr(obj, 'inactive_users_count') else obj.users.filter(
            is_active=False).count()

    def get_role_name(self, obj):
        """Get user's role name in this company"""
        role = self.get_current_user_role(obj)
        return role["name"] if role else "No Role"

    def get_is_active_company(self, obj):
        """Check if this is user's currently active company"""
        request = self.context.get('request')
        if request and request.user:
            return request.user.active_company == obj
        return False


class UserCompaniesSerializer(serializers.Serializer):
    """Serializer for listing user's companies"""
    companies = CompanySummarySerializer(many=True, read_only=True)
    active_company = CompanySummarySerializer(read_only=True)

    def to_representation(self, instance):
        """Custom representation to get user's companies and active company"""
        return {
            'companies': CompanySummarySerializer(
                instance.companies.all(),
                many=True,
                context=self.context
            ).data,
            'active_company': CompanySummarySerializer(
                instance.active_company,
                context=self.context
            ).data if instance.active_company else None
        }


class SwitchCompanySerializer(serializers.Serializer):
    """Serializer for switching user's active company"""
    company_id = serializers.IntegerField(help_text="ID of company to switch to")

    def validate_company_id(self, value):
        """Validate that company exists and user belongs to it"""
        try:
            company = Company.objects.get(id=value, is_active=True)
        except Company.DoesNotExist:
            raise serializers.ValidationError("Company not found or inactive")

        request = self.context.get('request')
        if request and request.user:
            if not request.user.belongs_to_company(company):
                raise serializers.ValidationError("You don't belong to this company")

        return value

    def switch_company(self, user):
        """Switch user's active company"""
        company_id = self.validated_data['company_id']
        company = Company.objects.get(id=company_id)

        if user.switch_company(company):
            return company
        else:
            raise serializers.ValidationError("Failed to switch company")


class SetDefaultCompanySerializer(serializers.Serializer):
    """Serializer for setting user's default company"""
    company_id = serializers.IntegerField(help_text="ID of company to set as default")

    def validate_company_id(self, value):
        """Validate that company exists and user belongs to it"""
        try:
            company = Company.objects.get(id=value, is_active=True)
        except Company.DoesNotExist:
            raise serializers.ValidationError("Company not found or inactive")

        request = self.context.get('request')
        if request and request.user:
            if not request.user.belongs_to_company(company):
                raise serializers.ValidationError("You don't belong to this company")

        return value

    def set_default_company(self, user):
        """Set user's default company"""
        company_id = self.validated_data['company_id']
        company = Company.objects.get(id=company_id)

        if user.set_default_company(company):
            return company
        else:
            raise serializers.ValidationError("Failed to set default company")
