"""
Data Export API Views

Provides endpoints for exporting business data in CSV and JSON formats.
Gated by subscription-based can_export_data permission.
"""
import csv
import io
from datetime import datetime
from django.http import HttpResponse
from django.utils import timezone
from django.utils.dateparse import parse_datetime
from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.exceptions import PermissionDenied

from .models import Event, Resource, Service
from smoothschedule.identity.users.models import User
from smoothschedule.identity.core.models import Tenant


class HasExportDataPermission:
    """
    Permission class that checks if tenant has can_export_data permission.

    Checks tenant's subscription plan permissions to ensure they have
    access to data export functionality.
    """

    def has_permission(self, request, view):
        """Check if user's tenant has export permission"""
        # Get tenant from request (set by middleware or user)
        tenant = getattr(request, 'tenant', None)
        if not tenant and request.user.is_authenticated:
            tenant = request.user.tenant

        if not tenant:
            # No tenant - deny access
            raise PermissionDenied(
                "Data export is only available for business accounts."
            )

        # Check if tenant has export permission
        # This can come from subscription plan or direct tenant field
        has_permission = getattr(tenant, 'can_export_data', False)

        if not has_permission:
            raise PermissionDenied(
                "Data export is not available on your current subscription plan. "
                "Please upgrade to access this feature."
            )

        return True


class ExportViewSet(viewsets.ViewSet):
    """
    API ViewSet for exporting business data.

    Supports:
    - Multiple data types (appointments, customers, resources, services)
    - Multiple formats (CSV, JSON)
    - Date range filtering
    - Permission gating via subscription plans

    Endpoints:
    - GET /api/export/appointments/?format=csv&start_date=...&end_date=...
    - GET /api/export/customers/?format=json
    - GET /api/export/resources/?format=csv
    - GET /api/export/services/?format=json
    """

    permission_classes = [IsAuthenticated, HasExportDataPermission]

    def _parse_format(self, request):
        """Parse and validate format parameter"""
        format_param = request.query_params.get('format', 'json').lower()
        if format_param not in ['csv', 'json']:
            return 'json'
        return format_param

    def _parse_date_range(self, request):
        """Parse start_date and end_date query parameters"""
        start_date = request.query_params.get('start_date')
        end_date = request.query_params.get('end_date')

        start_dt = None
        end_dt = None

        if start_date:
            start_dt = parse_datetime(start_date)
            if not start_dt:
                raise ValueError(f"Invalid start_date format: {start_date}")

        if end_date:
            end_dt = parse_datetime(end_date)
            if not end_dt:
                raise ValueError(f"Invalid end_date format: {end_date}")

        return start_dt, end_dt

    def _create_csv_response(self, data, filename, headers):
        """
        Create CSV HttpResponse from data.

        Args:
            data: List of dictionaries containing row data
            filename: Name of the CSV file to download
            headers: List of column headers
        """
        response = HttpResponse(content_type='text/csv')
        response['Content-Disposition'] = f'attachment; filename="{filename}"'

        if not data:
            # Empty CSV with just headers
            writer = csv.writer(response)
            writer.writerow(headers)
            return response

        # Write CSV data
        writer = csv.DictWriter(response, fieldnames=headers)
        writer.writeheader()
        writer.writerows(data)

        return response

    def _create_json_response(self, data, filename):
        """
        Create JSON response with proper headers.

        Args:
            data: Data to serialize as JSON
            filename: Name for Content-Disposition header
        """
        response = Response(data)
        response['Content-Disposition'] = f'attachment; filename="{filename}"'
        return response

    @action(detail=False, methods=['get'])
    def appointments(self, request):
        """
        Export appointments/events.

        Query Parameters:
        - format: 'csv' or 'json' (default: json)
        - start_date: ISO 8601 datetime (optional)
        - end_date: ISO 8601 datetime (optional)
        - status: Filter by status (optional)

        CSV Headers:
        - id, title, start_time, end_time, status, notes,
          customer_name, customer_email, resource_names, created_at
        """
        try:
            export_format = self._parse_format(request)
            start_dt, end_dt = self._parse_date_range(request)
        except ValueError as e:
            return Response(
                {'error': str(e)},
                status=status.HTTP_400_BAD_REQUEST
            )

        # Build queryset
        queryset = Event.objects.select_related('created_by').prefetch_related(
            'participants',
            'participants__content_type'
        ).all()

        # Apply filters
        if start_dt:
            queryset = queryset.filter(start_time__gte=start_dt)
        if end_dt:
            queryset = queryset.filter(start_time__lt=end_dt)

        status_filter = request.query_params.get('status')
        if status_filter:
            queryset = queryset.filter(status=status_filter.upper())

        # Prepare data
        data = []
        for event in queryset:
            # Get customer info
            customer_participant = event.participants.filter(role='CUSTOMER').first()
            customer_name = ''
            customer_email = ''
            if customer_participant and customer_participant.content_object:
                customer = customer_participant.content_object
                if hasattr(customer, 'full_name'):
                    customer_name = customer.full_name or ''
                if hasattr(customer, 'email'):
                    customer_email = customer.email or ''

            # Get resource names
            resource_participants = event.participants.filter(role='RESOURCE')
            resource_names = []
            for rp in resource_participants:
                if rp.content_object:
                    resource_names.append(str(rp.content_object))

            row = {
                'id': event.id,
                'title': event.title,
                'start_time': event.start_time.isoformat(),
                'end_time': event.end_time.isoformat(),
                'status': event.status,
                'notes': event.notes or '',
                'customer_name': customer_name,
                'customer_email': customer_email,
                'resource_names': ', '.join(resource_names) if export_format == 'csv' else resource_names,
                'created_at': event.created_at.isoformat() if event.created_at else '',
                'created_by': event.created_by.email if event.created_by else '',
            }
            data.append(row)

        # Generate filename
        timestamp = timezone.now().strftime('%Y%m%d_%H%M%S')
        filename = f"appointments_{timestamp}.{export_format}"

        # Return appropriate format
        if export_format == 'csv':
            headers = [
                'id', 'title', 'start_time', 'end_time', 'status', 'notes',
                'customer_name', 'customer_email', 'resource_names',
                'created_at', 'created_by'
            ]
            return self._create_csv_response(data, filename, headers)
        else:
            return self._create_json_response({
                'count': len(data),
                'exported_at': timezone.now().isoformat(),
                'filters': {
                    'start_date': start_dt.isoformat() if start_dt else None,
                    'end_date': end_dt.isoformat() if end_dt else None,
                    'status': status_filter,
                },
                'data': data
            }, filename)

    @action(detail=False, methods=['get'])
    def customers(self, request):
        """
        Export customer list.

        Query Parameters:
        - format: 'csv' or 'json' (default: json)
        - status: 'active' or 'inactive' (optional)

        CSV Headers:
        - id, email, first_name, last_name, full_name, phone,
          is_active, created_at, last_login
        """
        export_format = self._parse_format(request)

        # Build queryset
        queryset = User.objects.filter(role=User.Role.CUSTOMER)

        # Apply status filter
        status_filter = request.query_params.get('status')
        if status_filter:
            if status_filter.lower() == 'active':
                queryset = queryset.filter(is_active=True)
            elif status_filter.lower() == 'inactive':
                queryset = queryset.filter(is_active=False)

        # Prepare data
        data = []
        for customer in queryset:
            row = {
                'id': customer.id,
                'email': customer.email,
                'first_name': customer.first_name or '',
                'last_name': customer.last_name or '',
                'full_name': customer.full_name or '',
                'phone': customer.phone or '',
                'is_active': customer.is_active,
                'created_at': customer.date_joined.isoformat() if customer.date_joined else '',
                'last_login': customer.last_login.isoformat() if customer.last_login else '',
            }
            data.append(row)

        # Generate filename
        timestamp = timezone.now().strftime('%Y%m%d_%H%M%S')
        filename = f"customers_{timestamp}.{export_format}"

        # Return appropriate format
        if export_format == 'csv':
            headers = [
                'id', 'email', 'first_name', 'last_name', 'full_name',
                'phone', 'is_active', 'created_at', 'last_login'
            ]
            return self._create_csv_response(data, filename, headers)
        else:
            return self._create_json_response({
                'count': len(data),
                'exported_at': timezone.now().isoformat(),
                'filters': {
                    'status': status_filter,
                },
                'data': data
            }, filename)

    @action(detail=False, methods=['get'])
    def resources(self, request):
        """
        Export resources.

        Query Parameters:
        - format: 'csv' or 'json' (default: json)
        - is_active: 'true' or 'false' (optional)

        CSV Headers:
        - id, name, type, description, max_concurrent_events,
          buffer_duration, is_active, user_email, created_at
        """
        export_format = self._parse_format(request)

        # Build queryset
        queryset = Resource.objects.select_related('user').all()

        # Apply active filter
        active_filter = request.query_params.get('is_active')
        if active_filter:
            queryset = queryset.filter(is_active=active_filter.lower() == 'true')

        # Prepare data
        data = []
        for resource in queryset:
            row = {
                'id': resource.id,
                'name': resource.name,
                'type': resource.type,
                'description': resource.description or '',
                'max_concurrent_events': resource.max_concurrent_events,
                'buffer_duration': str(resource.buffer_duration) if resource.buffer_duration else '0:00:00',
                'is_active': resource.is_active,
                'user_email': resource.user.email if resource.user else '',
                'created_at': resource.created_at.isoformat() if resource.created_at else '',
            }
            data.append(row)

        # Generate filename
        timestamp = timezone.now().strftime('%Y%m%d_%H%M%S')
        filename = f"resources_{timestamp}.{export_format}"

        # Return appropriate format
        if export_format == 'csv':
            headers = [
                'id', 'name', 'type', 'description', 'max_concurrent_events',
                'buffer_duration', 'is_active', 'user_email', 'created_at'
            ]
            return self._create_csv_response(data, filename, headers)
        else:
            return self._create_json_response({
                'count': len(data),
                'exported_at': timezone.now().isoformat(),
                'filters': {
                    'is_active': active_filter,
                },
                'data': data
            }, filename)

    @action(detail=False, methods=['get'])
    def services(self, request):
        """
        Export services.

        Query Parameters:
        - format: 'csv' or 'json' (default: json)
        - is_active: 'true' or 'false' (optional)

        CSV Headers:
        - id, name, description, duration, price, display_order,
          is_active, created_at
        """
        export_format = self._parse_format(request)

        # Build queryset
        queryset = Service.objects.all()

        # Apply active filter
        active_filter = request.query_params.get('is_active')
        if active_filter:
            queryset = queryset.filter(is_active=active_filter.lower() == 'true')

        # Prepare data
        data = []
        for service in queryset:
            row = {
                'id': service.id,
                'name': service.name,
                'description': service.description or '',
                'duration': service.duration,
                'price': str(service.price),
                'display_order': service.display_order,
                'is_active': service.is_active,
                'created_at': service.created_at.isoformat() if service.created_at else '',
            }
            data.append(row)

        # Generate filename
        timestamp = timezone.now().strftime('%Y%m%d_%H%M%S')
        filename = f"services_{timestamp}.{export_format}"

        # Return appropriate format
        if export_format == 'csv':
            headers = [
                'id', 'name', 'description', 'duration', 'price',
                'display_order', 'is_active', 'created_at'
            ]
            return self._create_csv_response(data, filename, headers)
        else:
            return self._create_json_response({
                'count': len(data),
                'exported_at': timezone.now().isoformat(),
                'filters': {
                    'is_active': active_filter,
                },
                'data': data
            }, filename)
