from datetime import timedelta

from django.core.management import call_command
from django.utils import timezone
from rest_framework import status
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from rest_framework.response import Response
from rest_framework.views import APIView

from apps.telemetry.models import (
    TelemetryAlert,
    TelemetryCohortSnapshot,
    TelemetryFunnelSnapshot,
    TelemetryKPIAggregate,
    TelemetryRetentionSnapshot,
)
from apps.telemetry.serializers import (
    TelemetryAlertResolveSerializer,
    TelemetryBulkIngestSerializer,
    TelemetryEventIngestSerializer,
)
from apps.telemetry.services import ingest_events


class TelemetryIngestView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        if isinstance(request.data, dict) and 'events' in request.data:
            serializer = TelemetryBulkIngestSerializer(data=request.data)
            serializer.is_valid(raise_exception=True)
            payload = serializer.validated_data
            result = ingest_events(
                request.user,
                payload['events'],
                source=payload.get('source') or 'frontend',
            )
        else:
            serializer = TelemetryEventIngestSerializer(data=request.data)
            serializer.is_valid(raise_exception=True)
            result = ingest_events(
                request.user,
                [serializer.validated_data],
                source='frontend',
            )

        return Response({'success': True, 'data': result}, status=status.HTTP_202_ACCEPTED)


class AdminTelemetryOverviewView(APIView):
    permission_classes = [IsAuthenticated, IsAdminUser]

    def get(self, request):
        period = request.query_params.get('period', '7d')
        map_period = {'7d': 7, '30d': 30, '90d': 90, '365d': 365}
        days = map_period.get(period, 7)
        since = timezone.localdate() - timedelta(days=days)

        rows = (
            TelemetryKPIAggregate.objects
            .filter(period_type=TelemetryKPIAggregate.PeriodType.DAY, period_start__gte=since)
            .order_by('-period_start')
        )
        return Response(
            {
                'period': period,
                'rows': [
                    {
                        'period_start': row.period_start,
                        'period_end': row.period_end,
                        'event_domain': row.event_domain,
                        'metrics': row.metrics,
                    }
                    for row in rows
                ],
            }
        )


class AdminTelemetryCohortsView(APIView):
    permission_classes = [IsAuthenticated, IsAdminUser]

    def get(self, request):
        snapshot_date = request.query_params.get('snapshot_date')
        qs = TelemetryCohortSnapshot.objects.all().order_by('-snapshot_date', 'cohort_name')
        if snapshot_date:
            qs = qs.filter(snapshot_date=snapshot_date)
        return Response(
            {
                'rows': [
                    {
                        'snapshot_date': row.snapshot_date,
                        'cohort_name': row.cohort_name,
                        'users_count': row.users_count,
                        'metrics': row.metrics,
                    }
                    for row in qs[:300]
                ]
            }
        )


class AdminTelemetryRetentionView(APIView):
    permission_classes = [IsAuthenticated, IsAdminUser]

    def get(self, request):
        qs = TelemetryRetentionSnapshot.objects.order_by('-cohort_date', 'retention_day')
        return Response(
            {
                'rows': [
                    {
                        'cohort_date': row.cohort_date,
                        'retention_day': row.retention_day,
                        'event_domain': row.event_domain,
                        'cohort_size': row.cohort_size,
                        'active_users': row.active_users,
                        'retention_rate': float(row.retention_rate),
                    }
                    for row in qs[:1000]
                ]
            }
        )


class AdminTelemetryFunnelsView(APIView):
    permission_classes = [IsAuthenticated, IsAdminUser]

    def get(self, request):
        funnel_name = request.query_params.get('funnel_name')
        qs = TelemetryFunnelSnapshot.objects.order_by('-snapshot_date', 'funnel_name', 'stage_order')
        if funnel_name:
            qs = qs.filter(funnel_name=funnel_name)
        return Response(
            {
                'rows': [
                    {
                        'snapshot_date': row.snapshot_date,
                        'funnel_name': row.funnel_name,
                        'stage_name': row.stage_name,
                        'stage_order': row.stage_order,
                        'event_domain': row.event_domain,
                        'users_count': row.users_count,
                        'conversion_rate': float(row.conversion_rate),
                    }
                    for row in qs[:1000]
                ]
            }
        )


class AdminTelemetryAlertsView(APIView):
    permission_classes = [IsAuthenticated, IsAdminUser]

    def get(self, request):
        status_param = request.query_params.get('status', '').upper()
        qs = TelemetryAlert.objects.order_by('-detected_at')
        if status_param in {TelemetryAlert.Status.OPEN, TelemetryAlert.Status.RESOLVED}:
            qs = qs.filter(status=status_param)
        return Response(
            {
                'rows': [
                    {
                        'id': row.id,
                        'alert_type': row.alert_type,
                        'severity': row.severity,
                        'status': row.status,
                        'event_domain': row.event_domain,
                        'detected_at': row.detected_at,
                        'resolved_at': row.resolved_at,
                        'metric_value': float(row.metric_value),
                        'threshold_value': float(row.threshold_value),
                        'context': row.context,
                    }
                    for row in qs[:500]
                ]
            }
        )

    def post(self, request):
        serializer = TelemetryAlertResolveSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        alert_ids = serializer.validated_data.get('alert_ids') or []
        if not alert_ids:
            return Response({'success': True, 'updated': 0})

        updated = TelemetryAlert.objects.filter(id__in=alert_ids, status=TelemetryAlert.Status.OPEN).update(
            status=TelemetryAlert.Status.RESOLVED,
            resolved_at=timezone.now(),
        )
        return Response({'success': True, 'updated': updated})


class AdminTelemetrySeedJobsView(APIView):
    permission_classes = [IsAuthenticated, IsAdminUser]

    CATALOG_PRESETS = {
        'small': {'products': 50, 'vendor_count': 5},
        'medium': {'products': 500, 'vendor_count': 12},
        'large': {'products': 2000, 'vendor_count': 20},
    }
    TELEMETRY_PRESETS = {
        'small': {'customer_count': 6, 'days': 35},
        'medium': {'customer_count': 20, 'days': 60},
        'large': {'customer_count': 50, 'days': 120},
    }

    def post(self, request):
        job_type = str(request.data.get('job_type') or '').strip().lower()
        preset = str(request.data.get('preset') or 'small').strip().lower()
        admin_mobile = str(request.data.get('admin_mobile') or '8668192080').strip()

        if job_type not in {'catalog', 'telemetry_e2e'}:
            return Response(
                {
                    'success': False,
                    'error': "job_type must be one of: catalog, telemetry_e2e",
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        if job_type == 'catalog':
            cfg = self.CATALOG_PRESETS.get(preset)
            if not cfg:
                return Response({'success': False, 'error': 'invalid preset for catalog'}, status=status.HTTP_400_BAD_REQUEST)
            call_command(
                'seed_marketplace_catalog_load',
                products=cfg['products'],
                vendor_count=cfg['vendor_count'],
                admin_mobile=admin_mobile,
            )
            return Response(
                {
                    'success': True,
                    'job_type': 'catalog',
                    'preset': preset,
                    'config': cfg,
                    'message': 'Catalog load seed finished.',
                }
            )

        cfg = self.TELEMETRY_PRESETS.get(preset)
        if not cfg:
            return Response({'success': False, 'error': 'invalid preset for telemetry_e2e'}, status=status.HTTP_400_BAD_REQUEST)
        call_command(
            'seed_telemetry_e2e',
            admin_mobile=admin_mobile,
            customer_count=cfg['customer_count'],
            days=cfg['days'],
        )
        return Response(
            {
                'success': True,
                'job_type': 'telemetry_e2e',
                'preset': preset,
                'config': cfg,
                'message': 'Telemetry E2E seed finished.',
            }
        )
