import os
import platform

from django import get_version as django_version
from django.shortcuts import render
from django.utils import timezone
from django.views.generic import ListView
from .models import Customer


def home(request):
    """Render the landing screen with loader and environment details."""
    host_name = request.get_host().lower()
    agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic"
    now = timezone.now()

    context = {
        "project_name": "New Style",
        "agent_brand": agent_brand,
        "django_version": django_version(),
        "python_version": platform.python_version(),
        "current_time": now,
        "host_name": host_name,
        "project_description": os.getenv("PROJECT_DESCRIPTION", ""),
        "project_image_url": os.getenv("PROJECT_IMAGE_URL", ""),
    }
    return render(request, "core/index.html", context)


def article_detail(request):
    """Render the article detail screen."""
    host_name = request.get_host().lower()
    agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic"
    now = timezone.now()

    context = {
        "project_name": "New Style",
        "agent_brand": agent_brand,
        "django_version": django_version(),
        "python_version": platform.python_version(),
        "current_time": now,
        "host_name": host_name,
        "project_description": os.getenv("PROJECT_DESCRIPTION", ""),
        "project_image__url": os.getenv("PROJECT_IMAGE_URL", ""),
    }
    return render(request, "core/article_detail.html", context)

from django.conf import settings
from django.core.paginator import Paginator
from django.db.models import Q, Count, Subquery, OuterRef
from .models import User, ContactHistory, Opportunity, ActivityLog
from django.shortcuts import get_object_or_404
from django.views import View

class CustomerListView(ListView):
    model = Customer
    template_name = 'core/customer_list.html'
    context_object_name = 'customers'
    paginate_by = 25  # Default page size

    def get_queryset(self):
        queryset = super().get_queryset().select_related('owner')

        # Filter persistence
        if self.request.GET.get('clear_filters'):
            for key in list(self.request.session.keys()):
                if key.startswith('customer_list_filter_'):
                    del self.request.session[key]

        filter_params = {
            'show_deleted': self.request.GET.get('show_deleted'),
            'q': self.request.GET.get('q'),
            'status': self.request.GET.get('status'),
            'owner': self.request.GET.get('owner'),
        }

        for key, value in filter_params.items():
            if value is not None:
                self.request.session[f'customer_list_filter_{key}'] = value
            else:
                filter_params[key] = self.request.session.get(f'customer_list_filter_{key}')

        # Filter by deletion status
        if not filter_params['show_deleted']:
            queryset = queryset.filter(is_deleted=False)

        # Search
        if filter_params['q']:
            queryset = queryset.filter(
                Q(name__icontains=filter_params['q']) |
                Q(email__icontains=filter_params['q']) |
                Q(id__icontains=filter_params['q'])
            )

        # Filter
        if filter_params['status']:
            queryset = queryset.filter(status=filter_params['status'])

        if filter_params['owner']:
            queryset = queryset.filter(owner_id=filter_params['owner'])

        # Annotate with last contact and opportunity count
        last_contact_subquery = ContactHistory.objects.filter(
            customer=OuterRef('pk')
        ).order_by('-created_at').values('created_at')[:1]

        queryset = queryset.annotate(
            last_contact=Subquery(last_contact_subquery),
            opportunity_count=Count('opportunities', distinct=True)
        ).order_by('name')

        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        page_size = self.request.GET.get('page_size', self.paginate_by)
        
        paginator = Paginator(self.get_queryset(), page_size)
        page_number = self.request.GET.get('page')
        page_obj = paginator.get_page(page_number)
        
        context['page_obj'] = page_obj
        context['page_size'] = int(page_size)
        context['paginator'] = paginator
        context['customer_count'] = paginator.count
        context['statuses'] = Customer.STATUS_CHOICES
        context['owners'] = User.objects.filter(is_staff=True) # Assuming staff are owners
        
        # Persist query params
        context['query'] = self.request.session.get('customer_list_filter_q', '')
        context['selected_status'] = self.request.session.get('customer_list_filter_status', '')
        context['selected_owner'] = self.request.session.get('customer_list_filter_owner', '')
        context['show_deleted'] = self.request.session.get('customer_list_filter_show_deleted', False)

        is_filter_active = any([
            self.request.session.get('customer_list_filter_q'),
            self.request.session.get('customer_list_filter_status'),
            self.request.session.get('customer_list_filter_owner'),
            self.request.session.get('customer_list_filter_show_deleted'),
            self.request.session.get('activity_feed_filter_activity_user'),
            self.request.session.get('activity_feed_filter_activity_action'),
            self.request.session.get('activity_feed_filter_activity_date_range'),
        ])
        context['is_filter_active'] = is_filter_active

        highlighted_customer_ids = []
        updated_customer_id = self.request.session.pop('updated_customer_id', None)
        if updated_customer_id:
            highlighted_customer_ids.append(updated_customer_id)

        deleted_customer_id = self.request.session.pop('deleted_customer_id', None)
        if deleted_customer_id:
            highlighted_customer_ids.append(deleted_customer_id)

        restored_customer_id = self.request.session.pop('restored_customer_id', None)
        if restored_customer_id:
            highlighted_customer_ids.append(restored_customer_id)

        restored_customer_ids = self.request.session.pop('restored_customer_ids', None)
        if restored_customer_ids:
            highlighted_customer_ids.extend([int(cid) for cid in restored_customer_ids])

        context['highlighted_customer_ids'] = highlighted_customer_ids

        context['undo_timeout'] = settings.UNDO_TIMEOUT
        context['toast_position'] = settings.TOAST_POSITION

        # Activity feed filtering
        if self.request.GET.get('clear_filters'):
            for key in list(self.request.session.keys()):
                if key.startswith('activity_feed_filter_'):
                    del self.request.session[key]

        activity_sort = self.request.GET.get('activity_sort', '-timestamp')
        activity_page_size = self.request.GET.get('activity_page_size', 5)

        activity_filter_params = {
            'activity_user': self.request.GET.get('activity_user'),
            'activity_action': self.request.GET.get('activity_action'),
            'activity_date_range': self.request.GET.get('activity_date_range'),
            'activity_sort': activity_sort,
            'activity_page_size': activity_page_size,
        }

        for key, value in activity_filter_params.items():
            if value is not None:
                self.request.session[f'activity_feed_filter_{key}'] = value
            else:
                activity_filter_params[key] = self.request.session.get(f'activity_feed_filter_{key}')

        activity_logs = ActivityLog.objects.select_related('actor').prefetch_related('content_object').all()
        
        if activity_filter_params['activity_user']:
            activity_logs = activity_logs.filter(actor_id=activity_filter_params['activity_user'])

        if activity_filter_params['activity_action']:
            activity_logs = activity_logs.filter(action=activity_filter_params['activity_action'])

        if activity_filter_params['activity_date_range']:
            try:
                start_date, end_date = activity_filter_params['activity_date_range'].split(' to ')
                activity_logs = activity_logs.filter(timestamp__date__gte=start_date, timestamp__date__lte=end_date)
            except ValueError:
                # Handle cases where the date range is not in the expected format
                pass

        if activity_filter_params['activity_sort']:
            sort_param = activity_filter_params['activity_sort']
            if sort_param == 'actor':
                activity_logs = activity_logs.order_by('actor__email')
            elif sort_param == '-actor':
                activity_logs = activity_logs.order_by('-actor__email')
            else:
                activity_logs = activity_logs.order_by(sort_param)

        # Activity summary
        activity_summary = activity_logs.values('action').annotate(count=Count('action'))
        context['activity_summary'] = {item['action']: item['count'] for item in activity_summary}

        # Paginate activity logs
        activity_page_size = activity_filter_params.get('activity_page_size', 5)
        activity_paginator = Paginator(activity_logs, activity_page_size)
        activity_page_number = self.request.GET.get('activity_page')
        activity_page_obj = activity_paginator.get_page(activity_page_number)

        context['activity_logs'] = activity_page_obj
        context['activity_paginator'] = activity_paginator
        context['activity_log_count'] = activity_paginator.count
        context['activity_page_size'] = int(activity_page_size)
        
        # Get users and actions for filter dropdowns
        user_ids = ActivityLog.objects.values_list('actor_id', flat=True).distinct()
        context['activity_users'] = User.objects.filter(id__in=user_ids)
        context['activity_actions'] = ActivityLog.objects.values_list('action', flat=True).distinct()

        context['selected_activity_user'] = self.request.session.get('activity_feed_filter_activity_user', '')
        context['selected_activity_action'] = self.request.session.get('activity_feed_filter_activity_action', '')
        context['selected_activity_date_range'] = self.request.session.get('activity_feed_filter_activity_date_range', '')
        context['selected_activity_sort'] = self.request.session.get('activity_feed_filter_activity_sort', '-timestamp')

        from datetime import timedelta
        twenty_four_hours_ago = timezone.now() - timedelta(hours=24)
        context['recent_activity_count'] = ActivityLog.objects.filter(timestamp__gte=twenty_four_hours_ago).count()

        return context

class CustomerDetailView(View):
    template_name = "core/customer_detail.html"

    def get(self, request, pk):
        customer = get_object_or_404(
            Customer.objects.select_related('owner', 'tenant')
            .prefetch_related('opportunities', 'leads', 'contacthistory_set', 'notes'),
            pk=pk
        )
        context = {
            "customer": customer,
            "opportunities": customer.opportunities.all(),
            "leads": customer.leads.all(),
            "contact_history": customer.contacthistory_set.all(),
            "notes": customer.notes.all(),
            "opportunity_count": customer.opportunities.count(),
            "lead_count": customer.leads.count(),
            "note_count": customer.notes.count(),
        }
        return render(request, self.template_name, context)

from django.urls import reverse_lazy
from django.http import HttpResponseRedirect
from django.contrib import messages
from django.views.generic import DetailView
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from .forms import CustomerForm, OpportunityForm
from django.forms.models import model_to_dict

class CustomerUpdateView(UpdateView):
    model = Customer
    form_class = CustomerForm
    template_name = 'core/customer_form.html'

    def get_success_url(self):
        return reverse_lazy('customer_list')

    def form_valid(self, form):
        # Capture previous state for changed fields only
        previous_state = {key: str(getattr(self.object, key)) for key in form.changed_data}

        response = super().form_valid(form)

        # Capture new state for changed fields
        changed_data = {key: {'old': previous_state[key], 'new': str(form.cleaned_data[key])} for key in form.changed_data}

        if form.changed_data:
            undo_data = {
                'customer_id': self.object.pk,
                'previous_state': previous_state,
                'timestamp': timezone.now().isoformat(),
                'session_key': self.request.session.session_key,
                'action': 'update'
            }
            self.request.session['undo_data'] = undo_data
            undo_url = reverse_lazy('customer_undo')
            message = f'{{"message": "Customer updated successfully.", "undo_url": "{undo_url}"}}'
            messages.success(self.request, message)

        ActivityLog.objects.create(
            actor=self.request.user,
            action=f'updated a {self.object.__class__.__name__}',
            content_object=self.object,
            details=changed_data
        )
        return response

    def form_invalid(self, form):
        messages.error(self.request, 'Please correct the errors below.')
        return super().form_invalid(form)


class CustomerDeleteView(DeleteView):
    model = Customer
    template_name = 'core/customer_confirm_delete.html'
    success_url = reverse_lazy('customer_list')

    def form_valid(self, form):
        self.object = self.get_object()
        success_url = self.get_success_url()

        # Store data required for restoration
        previous_state = model_to_dict(self.object, fields=['name', 'email', 'phone', 'address', 'status', 'owner'])
        # model_to_dict gives owner id, which is what we want.

        undo_data = {
            'customer_id': self.object.pk,
            'previous_state': previous_state,
            'timestamp': timezone.now().isoformat(),
            'session_key': self.request.session.session_key,
            'action': 'delete'
        }
        self.request.session['undo_data'] = undo_data

        self.object.delete(user=self.request.user)

        undo_url = reverse_lazy('customer_undo')
        message = f'{{"message": "Customer deleted successfully.", "undo_url": "{undo_url}"}}'
        messages.success(self.request, message)

        return HttpResponseRedirect(success_url)


class CustomerUndoView(View):
    def get(self, request):
        undo_data = request.session.get('undo_data')

        if not undo_data or undo_data.get('session_key') != request.session.session_key:
            messages.error(request, 'Invalid undo request.')
            return HttpResponseRedirect(reverse_lazy('customer_list'))

        try:
            undo_timestamp = timezone.datetime.fromisoformat(undo_data['timestamp'])
            if (timezone.now() - undo_timestamp).total_seconds() > settings.UNDO_TIMEOUT:
                messages.error(request, 'The undo link has expired.')
                request.session.pop('undo_data', None)
                return HttpResponseRedirect(reverse_lazy('customer_list'))
        except (ValueError, TypeError):
            messages.error(request, 'Invalid undo timestamp.')
            request.session.pop('undo_data', None)
            return HttpResponseRedirect(reverse_lazy('customer_list'))


        action = undo_data.get('action')
        customer_id = undo_data.get('customer_id')
        previous_state = undo_data.get('previous_state')

        try:
            if action == 'update':
                customer = get_object_or_404(Customer, pk=customer_id)
                for key, value in previous_state.items():
                    # Handle foreign keys
                    if key == 'owner' and value:
                        value = get_object_or_404(User, pk=value)
                    setattr(customer, key, value)
                customer.save()
                ActivityLog.objects.create(actor=request.user, action='undid update for', content_object=customer)
                messages.success(request, '{"message": "Update undone successfully.", "icon": "success"}')
                request.session['restored_customer_id'] = customer.pk

            elif action == 'delete':
                # Check if customer is already restored (e.g., from bulk restore)
                if Customer.objects.filter(pk=customer_id, is_deleted=False).exists():
                     messages.warning(request, 'Customer already restored.')
                else:
                    # If soft-deleted, restore it
                    if Customer.objects.filter(pk=customer_id).exists():
                        customer = Customer.objects.get(pk=customer_id)
                        customer.restore(user=request.user)
                    # If hard-deleted, recreate it
                    else:
                        owner_id = previous_state.pop('owner', None)
                        if owner_id:
                            previous_state['owner'] = get_object_or_404(User, pk=owner_id)
                        customer = Customer.objects.create(pk=customer_id, **previous_state)

                    ActivityLog.objects.create(actor=request.user, action='undid delete for', content_object=customer)
                    messages.success(request, '{"message": "1 customer restored successfully.", "icon": "success"}')
                    request.session['restored_customer_id'] = customer_id
        
        except Exception as e:
            messages.error(request, f"An error occurred during undo: {e}")


        request.session.pop('undo_data', None)
        return HttpResponseRedirect(reverse_lazy('customer_list'))


class CustomerRestoreView(View):
    def get(self, request, pk):
        customer = get_object_or_404(Customer, pk=pk)
        customer.restore(user=request.user)
        messages.success(request, '{"message": "1 customer restored successfully.", "icon": "success"}')
        request.session['restored_customer_id'] = pk
        return HttpResponseRedirect(reverse_lazy('customer_list'))

class CustomerBulkActionView(View):
    def post(self, request):
        selected_customers = request.POST.getlist('selected_customers')
        action = request.POST.get('action')

        if action == 'restore':
            restored_count = 0
            restored_ids = []
            for customer_id in selected_customers:
                customer = get_object_or_404(Customer, pk=customer_id)
                customer.restore(user=request.user)
                restored_count += 1
                restored_ids.append(customer_id)
            if restored_count > 0:
                messages.success(request, f'{{"message": "{{restored_count}} customers restored successfully.", "icon": "success"}}')
                request.session['restored_customer_ids'] = restored_ids
        
        elif action == 'delete':
            deleted_count = 0
            deleted_ids = []
            for customer_id in selected_customers:
                customer = get_object_or_404(Customer, pk=customer_id)
                customer.delete(user=request.user)
                deleted_count += 1
                deleted_ids.append(customer_id)
            
            if deleted_count > 0:
                request.session['bulk_deleted_customer_ids'] = deleted_ids
                undo_url = reverse_lazy('customer_bulk_undo')
                message = f'{{"message": "{deleted_count} customers deleted successfully.", "undo_url": "{undo_url}"}}'
                messages.success(self.request, message)

        return HttpResponseRedirect(reverse_lazy('customer_list'))


class CustomerBulkUndoView(View):
    def get(self, request):
        customer_ids = request.session.pop('bulk_deleted_customer_ids', [])
        if customer_ids:
            restored_count = 0
            restored_ids = []
            for customer_id in customer_ids:
                customer = get_object_or_404(Customer, pk=customer_id)
                customer.restore(user=request.user)
                restored_count += 1
                restored_ids.append(customer_id)
            
            if restored_count > 0:
                messages.success(request, f'{{"message": "{{restored_count}} customers restored successfully.", "icon": "success"}}')
                request.session['restored_customer_ids'] = restored_ids

        return HttpResponseRedirect(reverse_lazy('customer_list'))




class OpportunityListView(ListView):
    model = Opportunity
    template_name = 'core/opportunity_list.html'
    context_object_name = 'opportunities'
    paginate_by = 25

    def get_queryset(self):
        queryset = super().get_queryset().select_related('lead__customer', 'created_by').filter(is_deleted=False)
        return queryset


class OpportunityDetailView(DetailView):
    model = Opportunity
    template_name = 'core/opportunity_detail.html'
    context_object_name = 'opportunity'


class OpportunityCreateView(CreateView):
    model = Opportunity
    form_class = OpportunityForm
    template_name = 'core/opportunity_form.html'

    def get_success_url(self):
        return reverse_lazy('opportunity_detail', kwargs={'pk': self.object.pk})

    def form_valid(self, form):
        form.instance.created_by = self.request.user
        messages.success(self.request, 'Opportunity created successfully.')
        return super().form_valid(form)


class OpportunityUpdateView(UpdateView):
    model = Opportunity
    form_class = OpportunityForm
    template_name = 'core/opportunity_form.html'

    def get_success_url(self):
        return reverse_lazy('opportunity_detail', kwargs={'pk': self.object.pk})

    def form_valid(self, form):
        form.instance.updated_by = self.request.user
        messages.success(self.request, 'Opportunity updated successfully.')
        return super().form_valid(form)


class OpportunityDeleteView(DeleteView):
    model = Opportunity
    template_name = 'core/opportunity_confirm_delete.html'
    success_url = reverse_lazy('opportunity_list')

    def delete(self, request, *args, **kwargs):
        self.object = self.get_object()
        success_url = self.get_success_url()
        self.object.delete(user=request.user)
        messages.success(request, 'Opportunity deleted successfully.')
        return HttpResponseRedirect(success_url)