
from django.utils import timezone
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError
from rest_framework.response import Response
from rest_framework.views import APIView

from accounts.permissions import HasPermission

from .models import EmailSettings, ScheduledReportRecipient
from .serializers import (
    BulkRecipientsSerializer,
    EmailSettingsWriteSerializer,
    ScheduledReportRecipientSerializer,
    is_valid_email,
    split_emails,
)
from .services import EmailSendError, get_email_config, get_zone, send_test_email

PERMISSION = 'settings.manage_email_reports'


class ScheduledReportRecipientViewSet(viewsets.ModelViewSet):
    date_field = 'created_at'
    query_filters = {'frequency': 'frequency'}
    queryset = ScheduledReportRecipient.objects.all()
    serializer_class = ScheduledReportRecipientSerializer
    permission_classes = [HasPermission(PERMISSION)]
    ordering_fields = ('email', 'frequency', 'created_at')
    search_fields = ('email', 'name')

    @action(detail=True, methods=['post'], url_path='send-test')
    def send_test(self, request, pk=None):
        """Send a test email to this recipient so a manager can confirm Resend is set up correctly."""
        recipient = self.get_object()
        try:
            message_id = send_test_email(recipient.email)
        except EmailSendError as exc:
            raise ValidationError({'detail': f'Could not send: {exc}'})
        return Response({'detail': f'Test email sent to {recipient.email}.', 'id': message_id})

    @action(detail=False, methods=['post'])
    def bulk(self, request):
        """Add several addresses with one schedule. Existing (email, frequency) pairs are skipped, not duplicated."""
        data = BulkRecipientsSerializer(data=request.data)
        data.is_valid(raise_exception=True)
        values = data.validated_data
        emails = values.pop('emails')
        created, skipped, invalid = [], [], []
        for email in emails:
            if not is_valid_email(email):
                invalid.append(email)
                continue
            recipient, was_created = ScheduledReportRecipient.objects.get_or_create(
                email=email, frequency=values['frequency'], defaults=values,
            )
            (created if was_created else skipped).append(recipient)
        return Response({
            'created': ScheduledReportRecipientSerializer(created, many=True).data,
            'skipped': [r.email for r in skipped],
            'invalid': invalid,
        }, status=201 if created else 200)


def _settings_payload():
    config = get_email_config()
    key = config['api_key']
    zone = get_zone(config['time_zone'])
    return {
        'api_key_set': bool(key),
        'api_key_hint': f'{key[:3]}…{key[-4:]}' if len(key) > 8 else ('set' if key else ''),
        'api_key_source': config['api_key_source'],
        'from_email': config['from_email'],
        'from_email_source': config['from_email_source'],
        'time_zone': zone.key,
        'current_time': timezone.now().astimezone(zone).isoformat(timespec='minutes'),
        'updated_at': EmailSettings.load().updated_at,
    }


class EmailSettingsView(APIView):
    """Manager-editable Resend configuration. The API key is write-only: responses only say whether one is set."""

    permission_classes = [HasPermission(PERMISSION)]

    def get(self, request):
        return Response(_settings_payload())

    def put(self, request):
        data = EmailSettingsWriteSerializer(data=request.data)
        data.is_valid(raise_exception=True)
        values = data.validated_data
        saved = EmailSettings.load()
        if values.get('clear_api_key'):
            saved.resend_api_key = ''
        elif values.get('resend_api_key'):
            saved.resend_api_key = values['resend_api_key']
        if 'from_email' in values:
            saved.from_email = values['from_email']
        if 'time_zone' in values:
            saved.time_zone = values['time_zone']
        saved.updated_by = request.user
        saved.save()
        return Response(_settings_payload())


class EmailTestView(APIView):
    """Send a test email to one or more addresses using the configuration currently in effect."""

    permission_classes = [HasPermission(PERMISSION)]

    def post(self, request):
        emails = split_emails(request.data.get('emails'))
        if not emails:
            raise ValidationError({'emails': 'Enter at least one email address.'})
        if len(emails) > 10:
            raise ValidationError({'emails': 'Send tests to at most 10 addresses at a time.'})
        bad = [e for e in emails if not is_valid_email(e)]
        if bad:
            raise ValidationError({'emails': f'Not a valid email address: {", ".join(bad)}'})
        sent, failed = [], []
        for email in emails:
            try:
                send_test_email(email)
                sent.append(email)
            except EmailSendError as exc:
                failed.append({'email': email, 'error': str(exc)})
        if not sent:
            raise ValidationError({'detail': f'Could not send: {failed[0]["error"]}'})
        return Response({'sent': sent, 'failed': failed})
