from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.pagination import LimitOffsetPagination
from drf_spectacular.utils import extend_schema, OpenApiParameter
from drf_spectacular.types import OpenApiTypes
from django.db.models import Sum, Count, Avg, Q, Case, When, IntegerField, F
from django.db.models.functions import TruncDate, TruncHour, TruncMonth, Cast
from datetime import timedelta
from django.utils import timezone
from django.utils.dateparse import parse_datetime, parse_date
from entry.models import Entry
from car.models import Car
from car_brand.models import CarBrand
from .serializers import (
    OverviewStatsSerializer, RevenueOverTimeSerializer, TopCustomersSerializer,
    CarBrandAnalyticsSerializer, PeakHoursSerializer, DailyTrendsSerializer,
    MonthlyReportSerializer, EnergyConsumptionSerializer, CompletionRateSerializer
)


def _get_date_range(request):
    """Return (start_dt, end_dt) from start_date/end_date query params."""
    start_raw = request.query_params.get('start_date')
    end_raw = request.query_params.get('end_date')

    start_dt = parse_datetime(start_raw) if start_raw else None
    end_dt = parse_datetime(end_raw) if end_raw else None

    if start_dt is None and start_raw:
        start_date = parse_date(start_raw)
        if start_date:
            start_dt = timezone.make_aware(timezone.datetime.combine(start_date, timezone.datetime.min.time()))

    if end_dt is None and end_raw:
        end_date = parse_date(end_raw)
        if end_date:
            end_dt = timezone.make_aware(timezone.datetime.combine(end_date, timezone.datetime.max.time()))

    return start_dt, end_dt


def _apply_date_filter(queryset, request, field_name='date_created'):
    start_dt, end_dt = _get_date_range(request)
    if start_dt:
        queryset = queryset.filter(**{f"{field_name}__gte": start_dt})
    if end_dt:
        queryset = queryset.filter(**{f"{field_name}__lte": end_dt})
    return queryset


def _apply_branch_filter(queryset, request):
    """Apply branch filter from branch_id query parameter."""
    branch_id = request.query_params.get('branch_id')
    if branch_id:
        try:
            queryset = queryset.filter(branch_id=int(branch_id))
        except ValueError:
            pass
    return queryset


def _paginate_results(request, results):
    """Apply limit and offset pagination to results list."""
    limit = int(request.query_params.get('limit', 50))
    offset = int(request.query_params.get('offset', 0))
    
    total = len(results)
    paginated = results[offset:offset + limit]
    
    return {
        'count': total,
        'limit': limit,
        'offset': offset,
        'results': paginated
    }


@extend_schema(
    tags=['Analytics'],
    responses=OverviewStatsSerializer,
    parameters=[
        OpenApiParameter(
            name='start_date',
            type=OpenApiTypes.DATETIME,
            location=OpenApiParameter.QUERY,
            description='ISO 8601 start datetime (or YYYY-MM-DD date)',
            required=False
        ),
        OpenApiParameter(
            name='end_date',
            type=OpenApiTypes.DATETIME,
            location=OpenApiParameter.QUERY,
            description='ISO 8601 end datetime (or YYYY-MM-DD date)',
            required=False
        ),
        OpenApiParameter(
            name='branch_id',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Filter by branch ID',
            required=False
        )
    ],
    description='Get overall statistics including total entries, energy dispensed, customers, and revenue'
)
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def overview_stats(request):
    """Get overall business statistics"""
    entries = _apply_date_filter(Entry.objects.all(), request)
    entries = _apply_branch_filter(entries, request)
    
    total_entries = entries.count()
    completed_entries = entries.filter(completed=True).count()
    pending_entries = entries.filter(completed=False).count()
    
    total_energy = entries.aggregate(total=Sum('energy'))['total'] or 0
    total_revenue = entries.aggregate(total=Sum('total_cost'))['total'] or 0
    
    total_customers = Car.objects.values('customer_phone').distinct().count()
    
    data = {
        'total_entries': total_entries,
        'completed_entries': completed_entries,
        'pending_entries': pending_entries,
        'total_energy_dispensed': round(total_energy, 2),
        'total_customers': total_customers,
        'total_revenue': round(total_revenue, 2)
    }
    
    return Response(data)


@extend_schema(
    tags=['Analytics'],
    responses=RevenueOverTimeSerializer(many=True),
    parameters=[
        OpenApiParameter(
            name='days',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Number of days to look back (default: 30)',
            required=False
        ),
        OpenApiParameter(
            name='start_date',
            type=OpenApiTypes.DATETIME,
            location=OpenApiParameter.QUERY,
            description='ISO 8601 start datetime (or YYYY-MM-DD date)',
            required=False
        ),
        OpenApiParameter(
            name='end_date',
            type=OpenApiTypes.DATETIME,
            location=OpenApiParameter.QUERY,
            description='ISO 8601 end datetime (or YYYY-MM-DD date)',
            required=False
        ),
        OpenApiParameter(
            name='branch_id',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Filter by branch ID',
            required=False
        ),
        OpenApiParameter(
            name='limit',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Number of results per page (default: 50)',
            required=False
        ),
        OpenApiParameter(
            name='offset',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Number of results to skip (default: 0)',
            required=False
        )
    ],
    description='Get revenue and energy data over time for trend analysis'
)
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def revenue_over_time(request):
    """Get revenue trends over time"""
    days = int(request.query_params.get('days', 30))
    start_date = timezone.now() - timedelta(days=days)
    
    data = _apply_date_filter(Entry.objects.filter(
        date_created__gte=start_date,
        completed=True
    ), request)
    data = _apply_branch_filter(data, request).annotate(
        date=TruncDate('date_created')
    ).values('date').annotate(
        total_energy=Sum('energy'),
        total_revenue=Sum('total_cost'),
        entry_count=Count('id')
    ).order_by('date')
    
    result = []
    for item in data:
        result.append({
            'date': item['date'],
            'total_energy': round(item['total_energy'], 2),
            'total_revenue': round(item['total_revenue'] or 0, 2),
            'entry_count': item['entry_count']
        })
    
    paginated = _paginate_results(request, result)
    return Response(paginated)


@extend_schema(
    tags=['Analytics'],
    responses=TopCustomersSerializer(many=True),
    parameters=[
        OpenApiParameter(
            name='start_date',
            type=OpenApiTypes.DATETIME,
            location=OpenApiParameter.QUERY,
            description='ISO 8601 start datetime (or YYYY-MM-DD date)',
            required=False
        ),
        OpenApiParameter(
            name='end_date',
            type=OpenApiTypes.DATETIME,
            location=OpenApiParameter.QUERY,
            description='ISO 8601 end datetime (or YYYY-MM-DD date)',
            required=False
        ),
        OpenApiParameter(
            name='branch_id',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Filter by branch ID',
            required=False
        ),
        OpenApiParameter(
            name='limit',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Number of results per page (default: 50)',
            required=False
        ),
        OpenApiParameter(
            name='offset',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Number of results to skip (default: 0)',
            required=False
        )
    ],
    description='Get top customers by energy consumption and spending'
)
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def top_customers(request):
    """Get top customers by usage and revenue"""
    
    data = _apply_date_filter(Entry.objects.filter(
        completed=True
    ), request)
    data = _apply_branch_filter(data, request).values(
        'car__customer_name',
        'car__customer_phone'
    ).annotate(
        total_entries=Count('id'),
        total_energy=Sum('energy'),
        total_spent=Sum('total_cost')
    ).order_by('-total_energy')
    
    result = []
    for item in data:
        result.append({
            'customer_name': item['car__customer_name'],
            'customer_phone': item['car__customer_phone'],
            'total_entries': item['total_entries'],
            'total_energy': round(item['total_energy'], 2),
            'total_spent': round(item['total_spent'] or 0, 2)
        })
    
    paginated = _paginate_results(request, result)
    return Response(paginated)


@extend_schema(
    tags=['Analytics'],
    responses=CarBrandAnalyticsSerializer(many=True),
    parameters=[
        OpenApiParameter(
            name='start_date',
            type=OpenApiTypes.DATETIME,
            location=OpenApiParameter.QUERY,
            description='ISO 8601 start datetime (or YYYY-MM-DD date)',
            required=False
        ),
        OpenApiParameter(
            name='end_date',
            type=OpenApiTypes.DATETIME,
            location=OpenApiParameter.QUERY,
            description='ISO 8601 end datetime (or YYYY-MM-DD date)',
            required=False
        ),
        OpenApiParameter(
            name='branch_id',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Filter by branch ID',
            required=False
        ),
        OpenApiParameter(
            name='limit',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Number of results per page (default: 50)',
            required=False
        ),
        OpenApiParameter(
            name='offset',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Number of results to skip (default: 0)',
            required=False
        )
    ],
    description='Analyze which car brands are most popular at the charging station'
)
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def car_brand_analytics(request):
    """Get analytics by car brand"""
    data = Car.objects.values(
        'brand__name'
    ).annotate(
        car_count=Count('id'),
        entry_count=Count('entry'),
        total_energy=Sum('entry__energy')
    ).order_by('-entry_count')

    start_dt, end_dt = _get_date_range(request)
    if start_dt or end_dt:
        entry_filters = {}
        if start_dt:
            entry_filters['entry__date_created__gte'] = start_dt
        if end_dt:
            entry_filters['entry__date_created__lte'] = end_dt
        data = data.filter(**entry_filters)
    
    # Apply branch filter
    branch_id = request.query_params.get('branch_id')
    if branch_id:
        try:
            data = data.filter(entry__branch_id=int(branch_id))
        except ValueError:
            pass
    
    result = []
    for item in data:
        result.append({
            'brand_name': item['brand__name'],
            'car_count': item['car_count'],
            'entry_count': item['entry_count'] or 0,
            'total_energy': round(item['total_energy'] or 0, 2)
        })
    
    paginated = _paginate_results(request, result)
    return Response(paginated)


@extend_schema(
    tags=['Analytics'],
    responses=PeakHoursSerializer(many=True),
    parameters=[
        OpenApiParameter(
            name='days',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Number of days to analyze (default: 30)',
            required=False
        ),
        OpenApiParameter(
            name='start_date',
            type=OpenApiTypes.DATETIME,
            location=OpenApiParameter.QUERY,
            description='ISO 8601 start datetime (or YYYY-MM-DD date)',
            required=False
        ),
        OpenApiParameter(
            name='end_date',
            type=OpenApiTypes.DATETIME,
            location=OpenApiParameter.QUERY,
            description='ISO 8601 end datetime (or YYYY-MM-DD date)',
            required=False
        ),
        OpenApiParameter(
            name='branch_id',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Filter by branch ID',
            required=False
        ),
        OpenApiParameter(
            name='limit',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Number of results per page (default: 50)',
            required=False
        ),
        OpenApiParameter(
            name='offset',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Number of results to skip (default: 0)',
            required=False
        )
    ],
    description='Identify peak charging hours for resource planning'
)
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def peak_hours(request):
    """Get peak charging hours"""
    days = int(request.query_params.get('days', 30))
    start_date = timezone.now() - timedelta(days=days)
    
    data = _apply_date_filter(Entry.objects.filter(
        date_created__gte=start_date
    ), request)
    data = _apply_branch_filter(data, request).annotate(
        hour=TruncHour('date_created')
    ).values('hour').annotate(
        entry_count=Count('id'),
        total_energy=Sum('energy')
    ).order_by('hour')
    
    # Group by hour of day
    hourly_stats = {}
    for item in data:
        hour_of_day = item['hour'].hour
        if hour_of_day not in hourly_stats:
            hourly_stats[hour_of_day] = {'entry_count': 0, 'total_energy': 0}
        hourly_stats[hour_of_day]['entry_count'] += item['entry_count']
        hourly_stats[hour_of_day]['total_energy'] += item['total_energy'] or 0
    
    result = []
    for hour in range(24):
        stats = hourly_stats.get(hour, {'entry_count': 0, 'total_energy': 0})
        result.append({
            'hour': hour,
            'entry_count': stats['entry_count'],
            'total_energy': round(stats['total_energy'], 2)
        })
    
    paginated = _paginate_results(request, result)
    return Response(paginated)


@extend_schema(
    tags=['Analytics'],
    responses=DailyTrendsSerializer(many=True),
    parameters=[
        OpenApiParameter(
            name='days',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Number of days to analyze (default: 7)',
            required=False
        ),
        OpenApiParameter(
            name='start_date',
            type=OpenApiTypes.DATETIME,
            location=OpenApiParameter.QUERY,
            description='ISO 8601 start datetime (or YYYY-MM-DD date)',
            required=False
        ),
        OpenApiParameter(
            name='end_date',
            type=OpenApiTypes.DATETIME,
            location=OpenApiParameter.QUERY,
            description='ISO 8601 end datetime (or YYYY-MM-DD date)',
            required=False
        ),
        OpenApiParameter(
            name='branch_id',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Filter by branch ID',
            required=False
        ),
        OpenApiParameter(
            name='limit',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Number of results per page (default: 50)',
            required=False
        ),
        OpenApiParameter(
            name='offset',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Number of results to skip (default: 0)',
            required=False
        )
    ],
    description='Get daily trends for recent performance monitoring'
)
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def daily_trends(request):
    """Get daily performance trends"""
    days = int(request.query_params.get('days', 7))
    start_date = timezone.now() - timedelta(days=days)
    
    data = _apply_date_filter(Entry.objects.filter(
        date_created__gte=start_date
    ), request)
    data = _apply_branch_filter(data, request).annotate(
        date=TruncDate('date_created')
    ).values('date').annotate(
        total_entries=Count('id'),
        completed_entries=Count('id', filter=Q(completed=True)),
        total_energy=Sum('energy'),
        total_revenue=Sum('total_cost')
    ).order_by('date')
    
    result = []
    for item in data:
        energy = item['total_energy'] or 0
        result.append({
            'date': item['date'],
            'total_entries': item['total_entries'],
            'completed_entries': item['completed_entries'],
            'total_energy': round(energy, 2),
            'revenue': round(item['total_revenue'] or 0, 2)
        })
    
    paginated = _paginate_results(request, result)
    return Response(paginated)


@extend_schema(
    tags=['Analytics'],
    responses=MonthlyReportSerializer(many=True),
    parameters=[
        OpenApiParameter(
            name='months',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Number of months to analyze (default: 6)',
            required=False
        ),
        OpenApiParameter(
            name='start_date',
            type=OpenApiTypes.DATETIME,
            location=OpenApiParameter.QUERY,
            description='ISO 8601 start datetime (or YYYY-MM-DD date)',
            required=False
        ),
        OpenApiParameter(
            name='end_date',
            type=OpenApiTypes.DATETIME,
            location=OpenApiParameter.QUERY,
            description='ISO 8601 end datetime (or YYYY-MM-DD date)',
            required=False
        ),
        OpenApiParameter(
            name='branch_id',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Filter by branch ID',
            required=False
        ),
        OpenApiParameter(
            name='limit',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Number of results per page (default: 50)',
            required=False
        ),
        OpenApiParameter(
            name='offset',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Number of results to skip (default: 0)',
            required=False
        )
    ],
    description='Get monthly reports for long-term business planning'
)
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def monthly_report(request):
    """Get monthly business reports"""
    months = int(request.query_params.get('months', 6))
    start_date = timezone.now() - timedelta(days=months*30)
    
    data = _apply_date_filter(Entry.objects.filter(
        date_created__gte=start_date
    ), request)
    data = _apply_branch_filter(data, request).annotate(
        month=TruncMonth('date_created')
    ).values('month').annotate(
        total_entries=Count('id'),
        total_energy=Sum('energy'),
        total_revenue=Sum('total_cost'),
        unique_customers=Count('car__customer_phone', distinct=True),
        avg_energy=Avg('energy')
    ).order_by('month')
    
    result = []
    for item in data:
        energy = item['total_energy'] or 0
        result.append({
            'month': item['month'].strftime('%Y-%m'),
            'total_entries': item['total_entries'],
            'total_energy': round(energy, 2),
            'total_revenue': round(item['total_revenue'] or 0, 2),
            'unique_customers': item['unique_customers'],
            'avg_energy_per_entry': round(item['avg_energy'] or 0, 2)
        })
    
    paginated = _paginate_results(request, result)
    return Response(paginated)


@extend_schema(
    tags=['Analytics'],
    responses=EnergyConsumptionSerializer,
    parameters=[
        OpenApiParameter(
            name='start_date',
            type=OpenApiTypes.DATETIME,
            location=OpenApiParameter.QUERY,
            description='ISO 8601 start datetime (or YYYY-MM-DD date)',
            required=False
        ),
        OpenApiParameter(
            name='end_date',
            type=OpenApiTypes.DATETIME,
            location=OpenApiParameter.QUERY,
            description='ISO 8601 end datetime (or YYYY-MM-DD date)',
            required=False
        ),
        OpenApiParameter(
            name='branch_id',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Filter by branch ID',
            required=False
        )
    ],
    description='Analyze average energy consumption patterns'
)
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def energy_consumption_stats(request):
    """Get energy consumption statistics"""
    stats = _apply_date_filter(Entry.objects.filter(
        completed=True
    ), request)
    stats = _apply_branch_filter(stats, request).aggregate(
        avg_battery_capacity=Avg('battery_capacity'),
        avg_initial_soc=Avg('initial_soc'),
        avg_final_soc=Avg('final_soc'),
        avg_energy=Avg('energy'),
        total_sessions=Count('id')
    )
    
    data = {
        'avg_battery_capacity': round(stats['avg_battery_capacity'] or 0, 2),
        'avg_initial_soc': round(stats['avg_initial_soc'] or 0, 2),
        'avg_final_soc': round(stats['avg_final_soc'] or 0, 2),
        'avg_energy_per_session': round(stats['avg_energy'] or 0, 2),
        'total_sessions': stats['total_sessions']
    }
    
    return Response(data)


@extend_schema(
    tags=['Analytics'],
    responses=CompletionRateSerializer(many=True),
    parameters=[
        OpenApiParameter(
            name='period',
            type=OpenApiTypes.STR,
            location=OpenApiParameter.QUERY,
            description='Period: daily, weekly, monthly (default: daily)',
            required=False,
            enum=['daily', 'weekly', 'monthly']
        ),
        OpenApiParameter(
            name='days',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Number of days/weeks/months to analyze (default: 7)',
            required=False
        ),
        OpenApiParameter(
            name='start_date',
            type=OpenApiTypes.DATETIME,
            location=OpenApiParameter.QUERY,
            description='ISO 8601 start datetime (or YYYY-MM-DD date)',
            required=False
        ),
        OpenApiParameter(
            name='end_date',
            type=OpenApiTypes.DATETIME,
            location=OpenApiParameter.QUERY,
            description='ISO 8601 end datetime (or YYYY-MM-DD date)',
            required=False
        ),
        OpenApiParameter(
            name='branch_id',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Filter by branch ID',
            required=False
        ),
        OpenApiParameter(
            name='limit',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Number of results per page (default: 50)',
            required=False
        ),
        OpenApiParameter(
            name='offset',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description='Number of results to skip (default: 0)',
            required=False
        )
    ],
    description='Track completion rates to identify operational efficiency'
)
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def completion_rate(request):
    """Get completion rate statistics"""
    period = request.query_params.get('period', 'daily')
    days = int(request.query_params.get('days', 7))
    now = timezone.now()
    
    if period == 'monthly':
        start_date = now - timedelta(days=days*30)
        trunc_func = TruncMonth
        date_format = '%Y-%m'
    elif period == 'weekly':
        start_date = now - timedelta(weeks=days)
        trunc_func = TruncDate
        date_format = '%Y-W%W'
    else:  # daily
        start_date = now - timedelta(days=days)
        trunc_func = TruncDate
        date_format = '%Y-%m-%d'
    
    data = _apply_date_filter(Entry.objects.filter(
        date_created__gte=start_date
    ), request)
    data = _apply_branch_filter(data, request).annotate(
        period=trunc_func('date_created')
    ).values('period').annotate(
        total_entries=Count('id'),
        completed=Sum(Cast('completed', IntegerField())),
    ).annotate(
        pending=F('total_entries') - F('completed')
    ).order_by('period')
    
    result = []
    for item in data:
        total = item['total_entries']
        completed = item['completed'] or 0
        rate = (completed / total * 100) if total > 0 else 0
        
        result.append({
            'period': item['period'].strftime(date_format),
            'total_entries': total,
            'completed': completed,
            'pending': item['pending'],
            'completion_rate': round(rate, 2)
        })
    
    paginated = _paginate_results(request, result)
    return Response(paginated)
