from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.utils import timezone
from django.db.models import Sum, Count, Q, Avg, F
from datetime import datetime, date, timedelta
from decimal import Decimal
import json

# Import models from different apps
from customers.models import Customer, Service
from billing.models import Invoice
from hr.models import Employee
from tickets.models import Ticket
from payments.models import Payment
from expenditure.models import Expense
from accounts.models import CustomUser, GroupPermissionManager
from accounts.permissions import has_financial_access, is_admin, has_permission, get_user_permissions

def home(request):
    """Home page view that redirects to appropriate dashboard"""
    if request.user.is_authenticated:
        return redirect('customers:dashboard')
    else:
        return redirect('login')

def permission_denied_view(request, exception):
    """Custom 403 permission denied view"""
    context = {
        'error_message': str(exception) if exception else "You don't have permission to access this resource.",
        'user': request.user
    }
    return render(request, '403.html', context, status=403)

@login_required
def dashboard(request):
    """Enhanced Management Dashboard with comprehensive analytics"""

    # Handle case where request might be None (called from get_dashboard_context)
    if request is None:
        from django.http import HttpRequest
        request = HttpRequest()
        request.user = None

    # Ensure request.user exists
    if not hasattr(request, 'user') or request.user is None:
        from django.contrib.auth.models import AnonymousUser
        request.user = AnonymousUser()

    # Date ranges for calculations
    today = timezone.now().date()
    current_month_start = today.replace(day=1)
    last_month_start = (current_month_start - timedelta(days=1)).replace(day=1)
    current_year_start = today.replace(month=1, day=1)
    week_start = today - timedelta(days=today.weekday())

    # === FINANCIAL METRICS ===

    # Monthly Revenue
    monthly_revenue = Payment.objects.filter(
        status='completed',
        completed_at__gte=current_month_start,
        completed_at__lt=current_month_start + timedelta(days=32)
    ).aggregate(total=Sum('amount'))['total'] or Decimal('0.00')

    # Last month revenue for comparison
    last_month_revenue = Payment.objects.filter(
        status='completed',
        completed_at__gte=last_month_start,
        completed_at__lt=current_month_start
    ).aggregate(total=Sum('amount'))['total'] or Decimal('0.00')

    # Revenue growth calculation
    revenue_growth = 0
    if last_month_revenue > 0:
        revenue_growth = ((monthly_revenue - last_month_revenue) / last_month_revenue) * 100

    # Monthly Expenses
    monthly_expenses = Expense.objects.filter(
        status__in=['approved', 'paid'],
        expense_date__gte=current_month_start
    ).aggregate(total=Sum('amount'))['total'] or Decimal('0.00')

    # Last month expenses for comparison
    last_month_expenses = Expense.objects.filter(
        status__in=['approved', 'paid'],
        expense_date__gte=last_month_start,
        expense_date__lt=current_month_start
    ).aggregate(total=Sum('amount'))['total'] or Decimal('0.00')

    # Expense change calculation
    expense_change = 0
    if last_month_expenses > 0:
        expense_change = ((monthly_expenses - last_month_expenses) / last_month_expenses) * 100

    # Net Profit
    net_profit = monthly_revenue - monthly_expenses
    profit_margin = 0
    if monthly_revenue > 0:
        profit_margin = (net_profit / monthly_revenue) * 100

    # Payment tracking (daily, weekly, monthly)
    daily_payments = Payment.objects.filter(
        status='completed',
        completed_at__date=today
    ).aggregate(total=Sum('amount'))['total'] or Decimal('0.00')

    weekly_payments = Payment.objects.filter(
        status='completed',
        completed_at__date__gte=week_start
    ).aggregate(total=Sum('amount'))['total'] or Decimal('0.00')

    monthly_payments = monthly_revenue

    # Collection rate (percentage of invoiced amount collected)
    total_invoiced = Invoice.objects.filter(
        created_at__gte=current_month_start
    ).aggregate(total=Sum('total_amount'))['total'] or Decimal('0.00')

    collection_rate = 0
    if total_invoiced > 0:
        collection_rate = (monthly_revenue / total_invoiced) * 100

    # === CUSTOMER METRICS ===

    total_customers = Customer.objects.count()
    active_customers = Customer.objects.filter(is_active=True).count()
    new_customers_this_month = Customer.objects.filter(
        created_at__gte=current_month_start
    ).count()

    # Customer service status
    expired_customers = 0
    overdue_customers_count = 0

    # Calculate expired and overdue customers
    overdue_customer_ids = Invoice.objects.filter(
        status='unpaid',
        due_date__lt=today
    ).values_list('customer_id', flat=True).distinct()
    overdue_customers_count = len(overdue_customer_ids)

    # Service status percentages
    active_percentage = (active_customers / total_customers * 100) if total_customers > 0 else 0
    expired_percentage = (expired_customers / total_customers * 100) if total_customers > 0 else 0
    overdue_percentage = (overdue_customers_count / total_customers * 100) if total_customers > 0 else 0

    # === TICKET METRICS ===

    # Ticket counts
    open_tickets = Ticket.objects.filter(status__in=['open', 'in_progress']).count()
    resolved_tickets = Ticket.objects.filter(
        status='resolved',
        updated_at__gte=current_month_start
    ).count()

    # Tickets overdue for more than 24 hours (either past scheduled time or open for 24+ hours)
    overdue_tickets_24h = Ticket.objects.filter(
        Q(status__in=['open', 'in_progress']) & (
            Q(scheduled_date__lt=timezone.now() - timedelta(hours=24), scheduled_date__isnull=False) |
            Q(created_at__lt=timezone.now() - timedelta(hours=24), scheduled_date__isnull=True)
        )
    ).count()

    # Ticket resolution metrics
    total_tickets_this_month = Ticket.objects.filter(
        created_at__gte=current_month_start
    ).count()

    ticket_resolution_rate = 0
    if total_tickets_this_month > 0:
        ticket_resolution_rate = (resolved_tickets / total_tickets_this_month) * 100
    elif resolved_tickets > 0:
        # If we have resolved tickets but no new ones this month, show 100%
        ticket_resolution_rate = 100

    # Average resolution time
    resolved_tickets_with_time = Ticket.objects.filter(
        status='resolved',
        completed_at__isnull=False,
        updated_at__gte=current_month_start
    )

    avg_resolution_time = 0
    if resolved_tickets_with_time.exists():
        total_hours = 0
        ticket_count = 0
        for ticket in resolved_tickets_with_time:
            if ticket.completed_at and ticket.created_at:
                total_hours += (ticket.completed_at - ticket.created_at).total_seconds() / 3600
                ticket_count += 1

        if ticket_count > 0:
            avg_resolution_time = total_hours / ticket_count

    # === CRITICAL ALERTS ===

    critical_alerts = []

    # Overdue tickets alert
    if overdue_tickets_24h > 0:
        critical_alerts.append({
            'title': 'Overdue Support Tickets',
            'description': f'{overdue_tickets_24h} tickets pending for over 24 hours',
            'count': overdue_tickets_24h
        })

    # Overdue payments alert
    if overdue_customers_count > 0:
        critical_alerts.append({
            'title': 'Overdue Payments',
            'description': f'{overdue_customers_count} customers have overdue payments',
            'count': overdue_customers_count
        })

    # Low collection rate alert
    if collection_rate < 70:
        critical_alerts.append({
            'title': 'Low Collection Rate',
            'description': f'Only {collection_rate:.1f}% of invoices collected this month',
            'count': int(collection_rate)
        })

    # === RECENT ACTIVITY ===

    # Recent activity
    recent_customers = Customer.objects.filter(is_active=True).order_by('-created_at')[:10]
    recent_tickets = Ticket.objects.select_related('customer').order_by('-created_at')[:10]

    # Marketing reports for management notifications
    from customers.models import MarketingWeeklyReport
    pending_marketing_reports = MarketingWeeklyReport.objects.filter(status='submitted').count()

    # Recent payments (last 10)
    recent_payments = Payment.objects.filter(
        status='completed'
    ).select_related('customer').order_by('-completed_at')[:10]

    # Urgent tickets (high priority and overdue)
    urgent_tickets = Ticket.objects.filter(
        Q(priority__in=['high', 'urgent']) | Q(created_at__lt=timezone.now() - timedelta(hours=24)),
        status__in=['open', 'in_progress']
    ).select_related('customer').order_by('-priority', 'created_at')[:10]

    # Create a list with additional data for template
    urgent_tickets_data = []
    for ticket in urgent_tickets:
        urgent_tickets_data.append({
            'ticket': ticket,
            'customer_name': ticket.customer.full_name if ticket.customer else "Company/Infrastructure",
            'is_past_due': ticket.created_at < (timezone.now() - timedelta(hours=24))
        })
    urgent_tickets = urgent_tickets_data

    # === PERFORMANCE CHARTS DATA ===

    # Last 6 months data for charts
    chart_labels = []
    customer_growth_data = []
    revenue_growth_data = []

    for i in range(5, -1, -1):
        month_date = current_month_start - timedelta(days=i*30)
        month_start = month_date.replace(day=1)
        month_end = (month_start.replace(day=28) + timedelta(days=4)).replace(day=1)

        chart_labels.append(month_start.strftime('%b %Y'))

        # New customers for this month
        new_customers = Customer.objects.filter(
            created_at__gte=month_start,
            created_at__lt=month_end
        ).count()
        customer_growth_data.append(new_customers)

        # Revenue for this month
        month_revenue = Payment.objects.filter(
            status='completed',
            completed_at__gte=month_start,
            completed_at__lt=month_end
        ).aggregate(total=Sum('amount'))['total'] or 0
        revenue_growth_data.append(float(month_revenue))

    context = {
        # Financial metrics
        'monthly_revenue': monthly_revenue,
        'revenue_growth': revenue_growth,
        'monthly_expenses': monthly_expenses,
        'expense_change': expense_change,
        'net_profit': net_profit,
        'profit_margin': profit_margin,

        # Payment tracking
        'daily_payments': daily_payments,
        'weekly_payments': weekly_payments,
        'monthly_payments': monthly_payments,
        'collection_rate': collection_rate,

        # Customer metrics
        'total_customers': total_customers,
        'active_customers': active_customers,
        'expired_customers': expired_customers,
        'new_customers_this_month': new_customers_this_month,
        'overdue_customers_count': overdue_customers_count,
        'active_percentage': active_percentage,
        'expired_percentage': expired_percentage,
        'overdue_percentage': overdue_percentage,

        # Ticket metrics
        'open_tickets': open_tickets,
        'resolved_tickets': resolved_tickets,
        'overdue_tickets_24h': overdue_tickets_24h,
        'ticket_resolution_rate': ticket_resolution_rate,
        'avg_resolution_time': avg_resolution_time,

        # Alerts and activity
        'critical_alerts': critical_alerts,
        'recent_payments': recent_payments,
        'urgent_tickets': urgent_tickets,
        'recent_customers': recent_customers,
        'recent_tickets': recent_tickets,
        'pending_marketing_reports': pending_marketing_reports,

        # Chart data
        'chart_labels': json.dumps(chart_labels),
        'customer_growth_data': json.dumps(customer_growth_data),
        'revenue_growth_data': json.dumps(revenue_growth_data),
    }

    return context

def get_dashboard_context(user):
    """Get dashboard context based on user role"""
    if user.is_staff:
        # Create a mock request object for the dashboard function
        from django.http import HttpRequest
        mock_request = HttpRequest()
        mock_request.user = user
        return dashboard(mock_request)
    else:
        # Customer dashboard - simplified view
        try:
            customer = user.customer_profile
            recent_invoices = customer.invoices.order_by('-created_at')[:5]
            recent_tickets = customer.tickets.order_by('-created_at')[:5]

            return {
                'customer': customer,
                'recent_invoices': recent_invoices,
                'recent_tickets': recent_tickets,
                'account_balance': customer.account_balance,
                'outstanding_amount': customer.outstanding_amount,
            }
        except AttributeError: # Handle cases where user might not have customer_profile
            return {'error': 'Customer profile not found.'}
        except Exception as e: # Catch other potential errors
            return {'error': f'An error occurred: {e}'}


def dashboard_view(request):
    """Route to appropriate dashboard based on user type"""
    if not request.user.is_authenticated:
        return redirect('accounts:login')

    if request.user.is_superuser:
        # Comprehensive management dashboard for superusers
        context = dashboard(request)
        template = 'dashboard/dashboard.html'
    elif request.user.is_staff:
        # Staff dashboard for regular staff
        context = get_dashboard_context(request.user)
        template = 'dashboard/staff_dashboard.html'
    else:
        # Customer dashboard
        context = get_dashboard_context(request.user)
        template = 'dashboard/customer_dashboard.html'

    # Ensure context is not None
    if context is None:
        context = {
            'error': 'Unable to load dashboard data',
            'user': request.user
        }

    return render(request, template, context)

def global_search(request):
    """Global search functionality"""
    query = request.GET.get('q', '').strip()

    if not query:
        return JsonResponse({'error': 'No search query provided'}, status=400)

    results = {}

    # Search customers
    from customers.models import Customer
    customers = Customer.objects.filter(
        Q(full_name__icontains=query) |
        Q(customer_id__icontains=query) |
        Q(email__icontains=query) |
        Q(phone__icontains=query)
    )[:10]

    results['customers'] = [
        {
            'id': customer.customer_id,
            'name': customer.full_name,
            'email': customer.email,
            'url': f'/customers/{customer.customer_id}/'
        }
        for customer in customers
    ]

    # Search tickets
    from tickets.models import Ticket
    tickets = Ticket.objects.filter(
        Q(title__icontains=query) |
        Q(ticket_id__icontains=query) |
        Q(description__icontains=query)
    ).select_related('customer')[:10]

    results['tickets'] = [
        {
            'id': ticket.ticket_id,
            'title': ticket.title,
            'customer': ticket.customer.full_name if ticket.customer else 'System',
            'status': ticket.status,
            'url': f'/tickets/{ticket.ticket_id}/'
        }
        for ticket in tickets
    ]

    # Search employees
    from hr.models import Employee
    employees = Employee.objects.filter(
        Q(first_name__icontains=query) |
        Q(last_name__icontains=query) |
        Q(employee_id__icontains=query) |
        Q(email__icontains=query)
    )[:10]

    results['employees'] = [
        {
            'id': employee.employee_id,
            'name': f'{employee.first_name} {employee.last_name}',
            'email': employee.email,
            'department': employee.department.name if employee.department else 'N/A',
            'url': f'/hr/employees/{employee.employee_id}/'
        }
        for employee in employees
    ]

    return JsonResponse(results)

def staff_dashboard(request):
    """Staff dashboard with role-specific information"""
    if not request.user.is_authenticated:
        return redirect('accounts:login')

    context = {
        'user': request.user,
    }

    # Get employee profile if available
    employee_profile = None
    if hasattr(request.user, 'employee_profile') and request.user.employee_profile:
        employee_profile = request.user.employee_profile
        context['employee_profile'] = employee_profile

    # If the user is staff but does not have an employee profile,
    # we should still render a staff dashboard, possibly with a message.
    # The get_dashboard_context function handles the data fetching logic.
    # For now, we'll just ensure the template is rendered.
    staff_data = get_dashboard_context(request.user)
    context.update(staff_data) # Merge the fetched data into the main context

    return render(request, 'dashboard/staff_dashboard.html', context)