from rest_framework.pagination import LimitOffsetPagination
from rest_framework.viewsets import ModelViewSet
from rest_framework.views import APIView
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from rest_framework.response import Response
from rest_framework import status
from rest_framework.decorators import action
from rest_framework import viewsets
from django.contrib.auth import get_user_model
from apps.companies.models import Company, OfficeHours, SalesTiming, CatchPhrase, CompanyHistory, Holiday, CompanyBotSettings
from apps.companies.serializers import (
    CompanySerializer, UserCompaniesSerializer, SwitchCompanySerializer,
    SetDefaultCompanySerializer, OfficeHoursSerializer, SalesTimingSerializer,
    CatchPhraseSerializer, CompanyHistorySerializer, HolidaySerializer,
    CompanyBotSettingsSerializer, CompanyBotsListSerializer
)
from rest_framework import generics
from apps.permissions.permissions import CompanyPermission, AllowAny
from utils.paginations.pagination import OurLimitOffsetPagination
from apps.companies.utils import log_company_change
from utils.threads.email_thread import send_mail
from datetime import date
from apps.companies.exceptions import NoActiveCompanyError
from apps.companies.utils import apply_to_all_companies_bulk, validate_office_hours, validate_sales_timings, \
    apply_holidays_to_all_companies
from apps.permissions.permissions import SuperAdminOnly
from django.db.models import Count
from rest_framework_simplejwt.tokens import RefreshToken, AccessToken


User = get_user_model()


class CompanyBotsListView(generics.ListAPIView):
    """
    Simple list view that returns company bots
    - No company_id parameter: returns ALL companies' bots
    - With company_id parameter: returns only that company's bots
    """
    serializer_class = CompanyBotsListSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        company_id = self.request.query_params.get('company_id', None)

        if company_id:
            return Company.objects.filter(id=company_id, is_active=True).prefetch_related('bot_settings')
        else:
            return Company.objects.filter(is_active=True).prefetch_related('bot_settings')


class CompanyBotSettingsViewSet(ModelViewSet):
    """Company Bot Settings management ViewSet - handles all CRUD operations"""
    serializer_class = CompanyBotSettingsSerializer
    permission_classes = [CompanyPermission]

    def get_permissions(self):
        """Return different permissions based on action"""
        if self.action in ['list', 'retrieve']:
            return [CompanyPermission('view_company_bots')]
        else:
            return [CompanyPermission('edit_company_bots')]

    def get_queryset(self):
        """Filter to show only bot settings for user's active company"""
        user = self.request.user
        if not user.active_company:
            raise NoActiveCompanyError()
        return CompanyBotSettings.objects.filter(company=user.active_company)

    def perform_create(self, serializer):
        """Set company when creating bot settings and log the change"""
        company = self.request.user.active_company
        if not company:
            raise NoActiveCompanyError()

        bot_settings = serializer.save(company=company)
        # Log the creation
        log_company_change(
            company=company,
            user=self.request.user,
            action='created',
            model_name='CompanyBotSettings',
            object_id=bot_settings.id,
            details=f"Created bot settings: '{bot_settings}'"
        )

    def perform_update(self, serializer):
        """Log changes when updating bot settings"""
        old_instance = self.get_object()
        old_details = f"'{old_instance}'"

        bot_settings = serializer.save()

        # Log the change
        new_details = f"'{bot_settings}'"
        log_company_change(
            company=self.request.user.active_company,
            user=self.request.user,
            action='updated',
            model_name='CompanyBotSettings',
            object_id=bot_settings.id,
            details=f"Updated bot settings from {old_details} to {new_details}"
        )

    def perform_destroy(self, instance):
        """Log changes when deleting bot settings"""
        # Log the change before deletion
        log_company_change(
            company=self.request.user.active_company,
            user=self.request.user,
            action='deleted',
            model_name='CompanyBotSettings',
            object_id=instance.id,
            details=f"Deleted bot settings: '{instance}'"
        )

        instance.delete()


class CompanyViewSet(ModelViewSet):
    """Company management ViewSet - handles all CRUD operations"""
    serializer_class = CompanySerializer
    permission_classes = [CompanyPermission]
    pagination_class = OurLimitOffsetPagination
    filter_backends = [OrderingFilter, SearchFilter]
    search_fields = ['name', 'phone', 'website']
    ordering_fields = ['name', 'created_at', 'is_active', 'user_count']
    ordering = ['-created_at']

    def get_permissions(self):
        """Return different permissions based on action"""
        if self.action == 'create':
            return [SuperAdminOnly()]
        elif self.action in ['update', 'partial_update']:
            return [CompanyPermission('edit_company')]
        elif self.action == 'destroy':
            return [CompanyPermission('delete_company')]
        else:
            return [CompanyPermission('view_company')]

    def get_queryset(self):
        """Filter to show only companies the user belongs to"""
        user = self.request.user

        # Superusers can see all companies
        if user.is_superuser:
            return Company.objects.prefetch_related(
                'missing_call_notify_to',
                'office_hours',
                'sales_timings',
                'catch_phrases'
            ).select_related('default_transfer_staff').annotate(
                user_count=Count('users', distinct=True),
                active_users_count=Count('users', distinct=True, is_active=True),
                inactive_users_count=Count('users', distinct=True, is_active=False),
                available_users_count=Count('users', distinct=True, is_active=True, is_available=True)
            )

        return user.companies.prefetch_related(
            'missing_call_notify_to',
            'office_hours',
            'sales_timings',
            'catch_phrases'
        ).select_related('default_transfer_staff').annotate(
            user_count=Count('users', distinct=True),
            active_users_count=Count('users', distinct=True, is_active=True),
            inactive_users_count=Count('users', distinct=True, is_active=False),
            available_users_count=Count('users', distinct=True, is_active=True, is_available=True)
        )

    def partial_update(self, request, *args, **kwargs):
        """Handle PATCH requests and log changes."""
        instance = self.get_object()
        user = request.user
        company = instance

        old_status = instance.is_active
        new_status = request.data.get('is_active')

        response = super().partial_update(request, *args, **kwargs)

        if response.status_code in [200, 202]:
            CompanyHistory.objects.create(
                company=company,
                updated_by=user,
                action='updated',
                model_name='Call Settings',
                object_id=company.id,
                details=f"Updated call settings"
            )

        if new_status is not None:
            try:
                new_status = bool(int(new_status)) if isinstance(new_status, str) else bool(new_status)
            except:
                new_status = instance.is_active

            if old_status != new_status:
                response.data['company_status_changed'] = True
                response.data['is_now_active'] = new_status

            if new_status is False and user.active_company == company:
                response.data['force_session_refresh'] = True

            if new_status is False:
                handle_users_after_company_deactivation(company)

            return response

def handle_users_after_company_deactivation(company):
    User = get_user_model()

    users = User.objects.filter(active_company=company)

    for user in users:
        other_active_companies = user.companies.filter(is_active=True).exclude(id=company.id)

        if other_active_companies.exists():
            user.active_company = other_active_companies.first()
            # user.must_logout = False
            user.save()
        else:
            user.active_company = None
            # user.must_logout = True
            user.save()

class ActiveCompaniesView(ModelViewSet):
    """Return only active companies"""
    serializer_class = CompanySerializer
    permission_classes = [CompanyPermission]
    pagination_class = OurLimitOffsetPagination

    def get_permissions(self):
        """Return different permissions based on action"""
        if self.action == 'create':
            return [SuperAdminOnly()]
        elif self.action in ['update', 'partial_update']:
            return [CompanyPermission('edit_company')]
        elif self.action == 'destroy':
            return [CompanyPermission('delete_company')]
        else:
            return [AllowAny()]

    def get_queryset(self):
        user = self.request.user
        permission_codename = self.request.query_params.get('permission', None)

        # Get base queryset
        if user.is_superuser:
            queryset = Company.objects.prefetch_related(
                'missing_call_notify_to',
                'office_hours',
                'sales_timings',
                'catch_phrases'
            ).select_related('default_transfer_staff').filter(
                is_active=True
            ).order_by('updated_at')
        else:
            queryset = user.companies.prefetch_related(
                'missing_call_notify_to',
                'office_hours',
                'sales_timings',
                'catch_phrases'
            ).select_related('default_transfer_staff').filter(
                is_active=True
            ).order_by('updated_at')

        if permission_codename and not user.is_superuser:
            filtered_companies = []
            for company in queryset:
                if user.has_company_permission(permission_codename, company=company):
                    filtered_companies.append(company.id)

            return queryset.filter(id__in=filtered_companies)

        return queryset

    def perform_create(self, serializer):
        """Custom logic when creating a company"""
        serializer.save()

    def perform_update(self, serializer):
        """Custom logic when updating a company"""
        serializer.save()

    def perform_destroy(self, instance):
        """Soft delete - set is_active to False instead of deleting"""
        instance.is_active = False
        instance.save()

    @action(detail=True, methods=['post'])
    def add_user(self, request, pk=None):
        """Add a user to this company"""
        # Check if user has permission to manage users
        if not request.user.is_superuser and not request.user.has_company_permission('manage_users'):
            return Response(
                {'error': 'You do not have permission to manage users in companies'},
                status=status.HTTP_403_FORBIDDEN
            )

        try:
            company_id = pk
            print(f"DEBUG: Looking for company with ID: {company_id}")

            try:
                company = Company.objects.get(id=company_id, is_active=True)
                print(f"DEBUG: Found company: {company.name}")
            except Company.DoesNotExist:
                print(f"DEBUG: Company with ID {company_id} not found")
                return Response(
                    {'error': f'Company with ID {company_id} not found or inactive'},
                    status=status.HTTP_404_NOT_FOUND
                )

            user_id = request.data.get('user_id')
            print(f"DEBUG: Adding user ID: {user_id}")

            if not user_id:
                return Response(
                    {'error': 'user_id is required'},
                    status=status.HTTP_400_BAD_REQUEST
                )

            try:
                user = User.objects.get(id=user_id)
                print(f"DEBUG: Found user: {user.username}")
            except User.DoesNotExist:
                return Response(
                    {'error': f'User with ID {user_id} not found'},
                    status=status.HTTP_404_NOT_FOUND
                )

            # Add user to company
            user.companies.add(company)

            # Set as active company if user doesn't have one
            if not user.active_company:
                user.active_company = company
                user.save()

            # Send email notification to the user
            if user.email:
                key = {
                    'username': user.username,
                    'name': company.name,
                    'year': date.today().year,
                }
                send_mail(
                    subject=f"You are added to {company.name}",
                    html_content="auth/user_added_to_company.html",  # template you already have
                    recipient_list=[user.email],
                    key=key
                )

            return Response({
                'message': f'User "{user.username}" added to company "{company.name}"',
                'user_id': user.id,
                'company_id': company.id
            })

        except Exception as e:
            print(f"DEBUG: Exception occurred: {str(e)}")
            return Response(
                {'error': str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )


class UserCompaniesView(APIView):
    """List all companies that the user belongs to"""
    permission_classes = [IsAuthenticated]

    def get(self, request):
        """Get user's companies and active company"""
        serializer = UserCompaniesSerializer(request.user, context={'request': request})
        return Response(serializer.data)


class SwitchCompanyView(APIView):
    """Switch user's active company"""
    permission_classes = [IsAuthenticated]

    def post(self, request):
        """Switch to a different company"""
        serializer = SwitchCompanySerializer(data=request.data, context={'request': request})
        serializer.is_valid(raise_exception=True)

        try:
            company = serializer.switch_company(request.user)
            return Response({
                'message': f'Successfully switched to company: {company.name}',
                'company': {
                    'id': company.id,
                    'name': company.name
                }
            }, status=status.HTTP_200_OK)
        except Exception as e:
            return Response({
                'error': str(e)
            }, status=status.HTTP_400_BAD_REQUEST)


class SetDefaultCompanyView(APIView):
    """Set user's default company"""
    permission_classes = [IsAuthenticated]

    def post(self, request):
        """Set default company"""
        serializer = SetDefaultCompanySerializer(data=request.data, context={'request': request})
        serializer.is_valid(raise_exception=True)

        try:
            company = serializer.set_default_company(request.user)
            return Response({
                'message': f'Successfully set {company.name} as default company',
                'company': {
                    'id': company.id,
                    'name': company.name
                }
            }, status=status.HTTP_200_OK)
        except Exception as e:
            return Response({
                'error': str(e)
            }, status=status.HTTP_400_BAD_REQUEST)


class OfficeHoursViewSet(ModelViewSet):
    """Office hours management - full CRUD operations"""
    serializer_class = OfficeHoursSerializer
    permission_classes = [CompanyPermission]

    def get_permissions(self):
        """Return different permissions based on action"""
        if self.action in ['list', 'retrieve']:
            return [CompanyPermission('view_officehours')]
        else:
            return [CompanyPermission('edit_officehours')]

    def get_queryset(self):
        """Filter to show only office hours for user's active company"""
        user = self.request.user
        if not user.active_company:
            raise NoActiveCompanyError()
        return OfficeHours.objects.filter(company=user.active_company).order_by('day', 'start_time')

    def perform_create(self, serializer):
        """Set company when creating office hours and log the change"""
        office_hour = serializer.save(company=self.request.user.active_company)

        # Log the creation
        log_company_change(
            company=self.request.user.active_company,
            user=self.request.user,
            action='created',
            model_name='OfficeHours',
            object_id=office_hour.id,
            details=f"Created {office_hour.day} office hours: {office_hour.start_time} - {office_hour.end_time}"
        )

    def perform_update(self, serializer):
        """Log changes when updating office hours"""
        old_instance = self.get_object()
        old_details = f"{old_instance.day}: {old_instance.start_time} - {old_instance.end_time}"

        office_hour = serializer.save()

        # Log the change
        new_details = f"{office_hour.day}: {office_hour.start_time} - {office_hour.end_time}"
        log_company_change(
            company=self.request.user.active_company,
            user=self.request.user,
            action='updated',
            model_name='OfficeHours',
            object_id=office_hour.id,
            details=f"Updated office hours from '{old_details}' to '{new_details}'"
        )

    def perform_destroy(self, instance):
        """Log changes when deleting office hours"""
        # Log the change before deletion
        log_company_change(
            company=self.request.user.active_company,
            user=self.request.user,
            action='deleted',
            model_name='OfficeHours',
            object_id=instance.id,
            details=f"Deleted {instance.day} office hours: {instance.start_time} - {instance.end_time}"
        )

        instance.delete()

    @action(detail=False, methods=['post'])
    def apply_to_all_companies(self, request):
        """Apply current company's office hours to all user's companies"""
        return apply_to_all_companies_bulk(
            request=request,
            model_class=OfficeHours,
            model_name='OfficeHours',
            validation_func=validate_office_hours
        )


class SalesTimingViewSet(ModelViewSet):
    """Sales timing management - full CRUD operations"""
    serializer_class = SalesTimingSerializer
    permission_classes = [CompanyPermission]

    def get_permissions(self):
        """Return different permissions based on action"""
        if self.action in ['list', 'retrieve']:
            return [CompanyPermission('view_salestime')]
        else:
            return [CompanyPermission('edit_salestime')]

    def get_queryset(self):
        """Filter to show only sales timings for user's active company"""
        user = self.request.user
        if not user.active_company:
            raise NoActiveCompanyError()
        return SalesTiming.objects.filter(company=user.active_company).order_by('bot', 'start_time')

    def perform_create(self, serializer):
        """Set company when creating sales timing and log the change"""
        sales_timing = serializer.save(company=self.request.user.active_company)

        # Log the creation
        log_company_change(
            company=self.request.user.active_company,
            user=self.request.user,
            action='created',
            model_name='SalesTiming',
            object_id=sales_timing.id,
            details=f"Created sales timing for bot '{sales_timing.bot}': {sales_timing.start_time} - {sales_timing.end_time}"
        )

    def perform_update(self, serializer):
        """Log changes when updating sales timing"""
        old_instance = self.get_object()
        old_details = f"Bot '{old_instance.bot}': {old_instance.start_time} - {old_instance.end_time}"

        sales_timing = serializer.save()

        # Log the change
        new_details = f"Bot '{sales_timing.bot}': {sales_timing.start_time} - {sales_timing.end_time}"
        log_company_change(
            company=self.request.user.active_company,
            user=self.request.user,
            action='updated',
            model_name='SalesTiming',
            object_id=sales_timing.id,
            details=f"Updated sales timing from '{old_details}' to '{new_details}'"
        )

    def perform_destroy(self, instance):
        """Log changes when deleting sales timing"""
        # Log the change before deletion
        log_company_change(
            company=self.request.user.active_company,
            user=self.request.user,
            action='deleted',
            model_name='SalesTiming',
            object_id=instance.id,
            details=f"Deleted sales timing for bot '{instance.bot}': {instance.start_time} - {instance.end_time}"
        )

        instance.delete()

    @action(detail=False, methods=['post'])
    def apply_to_all_companies(self, request):
        """Apply current company's sales timings to all user's companies"""
        return apply_to_all_companies_bulk(
            request=request,
            model_class=SalesTiming,
            model_name='SalesTiming',
            validation_func=validate_sales_timings
        )


class CatchPhraseViewSet(ModelViewSet):
    """Catch phrases management - full CRUD operations"""
    serializer_class = CatchPhraseSerializer
    permission_classes = [CompanyPermission]

    def get_permissions(self):
        """Return different permissions based on action"""
        if self.action in ['list', 'retrieve']:
            return [CompanyPermission('view_catchphrase')]
        else:
            return [CompanyPermission('edit_catchphrase')]

    def get_queryset(self):
        """Filter to show only catch phrases for user's active company"""
        user = self.request.user
        if not user.active_company:
            raise NoActiveCompanyError()
        return CatchPhrase.objects.filter(company=user.active_company).order_by('phrase')

    def perform_create(self, serializer):
        """Set company when creating catch phrase and log the change"""
        catch_phrase = serializer.save(company=self.request.user.active_company)

        # Log the creation
        log_company_change(
            company=self.request.user.active_company,
            user=self.request.user,
            action='created',
            model_name='CatchPhrase',
            object_id=catch_phrase.id,
            details=f"Created catch phrase: '{catch_phrase.phrase}'"
        )

    def perform_update(self, serializer):
        """Log changes when updating catch phrase"""
        old_instance = self.get_object()
        old_details = f"'{old_instance.phrase}'"

        catch_phrase = serializer.save()

        # Log the change
        new_details = f"'{catch_phrase.phrase}'"
        log_company_change(
            company=self.request.user.active_company,
            user=self.request.user,
            action='updated',
            model_name='CatchPhrase',
            object_id=catch_phrase.id,
            details=f"Updated catch phrase from {old_details} to {new_details}"
        )

    def perform_destroy(self, instance):
        """Log changes when deleting catch phrase"""
        # Log the change before deletion
        log_company_change(
            company=self.request.user.active_company,
            user=self.request.user,
            action='deleted',
            model_name='CatchPhrase',
            object_id=instance.id,
            details=f"Deleted catch phrase: '{instance.phrase}'"
        )

        instance.delete()


class CompanyHistoryViewSet(viewsets.ReadOnlyModelViewSet):
    """Company history viewset - read-only access to company history"""
    serializer_class = CompanyHistorySerializer
    permission_classes = [CompanyPermission]
    pagination_class = OurLimitOffsetPagination

    filter_backends = [SearchFilter, OrderingFilter]
    search_fields = [
        'company__name',
        'updated_by__username',
        'model_name',
        'action',
        'details',
    ]

    def get_queryset(self):
        """Filter to show only history for user's active company"""
        user = self.request.user
        if not user.active_company:
            return CompanyHistory.objects.none()
        return user.active_company.history.all()

    def get_permissions(self):
        """Explicitly check view_company permission"""
        return [CompanyPermission('view_company')]


class HolidayViewSet(ModelViewSet):
    """Holiday management - full CRUD operations"""
    serializer_class = HolidaySerializer
    permission_classes = [CompanyPermission]

    def get_permissions(self):
        """Return different permissions based on action"""
        if self.action in ['list', 'retrieve']:
            return [CompanyPermission('view_holidays')]
        else:
            return [CompanyPermission('edit_holidays')]

    def get_queryset(self):
        """Filter to show only holidays for user's active company"""
        user = self.request.user
        if not user.active_company:
            raise NoActiveCompanyError()
        return Holiday.objects.filter(company=user.active_company).prefetch_related('bots').order_by('start_date')

    def perform_create(self, serializer):
        """Set company when creating holiday and log the change"""
        holiday = serializer.save(company=self.request.user.active_company)

        # Log the creation
        log_company_change(
            company=self.request.user.active_company,
            user=self.request.user,
            action='created',
            model_name='Holiday',
            object_id=holiday.id,
            details=f"Created holiday '{holiday.name}' from {holiday.start_date} to {holiday.end_date}"
        )

    def perform_update(self, serializer):
        """Log changes when updating holiday"""
        old_instance = self.get_object()
        old_details = f"'{old_instance.name}' from {old_instance.start_date} to {old_instance.end_date}"

        holiday = serializer.save()

        # Log the change
        new_details = f"'{holiday.name}' from {holiday.start_date} to {holiday.end_date}"
        log_company_change(
            company=self.request.user.active_company,
            user=self.request.user,
            action='updated',
            model_name='Holiday',
            object_id=holiday.id,
            details=f"Updated holiday from {old_details} to {new_details}"
        )

    def perform_destroy(self, instance):
        """Log changes when deleting holiday"""
        # Log the change before deletion
        log_company_change(
            company=self.request.user.active_company,
            user=self.request.user,
            action='deleted',
            model_name='Holiday',
            object_id=instance.id,
            details=f"Deleted holiday '{instance.name}' from {instance.start_date} to {instance.end_date}"
        )

        instance.delete()

    @action(detail=False, methods=['post'])
    def apply_to_all_companies(self, request):
        """Apply current company's holidays to all user's companies"""
        return apply_holidays_to_all_companies(request)
