import logging
from datetime import datetime
from django.utils import timezone
from django.template import Template, Context
from .models import Notification, NotificationTemplate
from .models import EmailConfig

logger = logging.getLogger(__name__)


class BaseProvider:
    def send(self, recipient: str, subject: str, body: str) -> dict:
        raise NotImplementedError()


class DummyProvider(BaseProvider):
    def send(self, recipient: str, subject: str, body: str, **kwargs) -> dict:
        logger.info('Dummy provider accepted notification to %s', recipient)
        return {'success': True, 'provider': 'dummy'}



import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
from django.conf import settings

class SMTPProvider(BaseProvider):
    def send(self, recipient: str, subject: str, body: str, email_config: EmailConfig = None) -> dict:
        try:
            host = email_config.host if email_config else settings.EMAIL_HOST
            port = email_config.port if email_config else settings.EMAIL_PORT
            username = email_config.username if email_config else settings.EMAIL_HOST_USER
            password = email_config.password if email_config else settings.EMAIL_HOST_PASSWORD
            use_tls = email_config.use_tls if email_config else getattr(settings, 'EMAIL_USE_TLS', False)
            use_ssl = email_config.use_ssl if email_config else getattr(settings, 'EMAIL_USE_SSL', False)
            from_email = email_config.from_email if email_config else settings.DEFAULT_FROM_EMAIL
            from_name = getattr(settings, 'EMAIL_FROM_NAME', 'True Wave Marketing')

            msg = MIMEText(body, 'plain', 'utf-8')
            msg['Subject'] = subject
            msg['From'] = formataddr((from_name, from_email))
            msg['To'] = recipient

            if use_ssl:
                server = smtplib.SMTP_SSL(host, port)
            else:
                server = smtplib.SMTP(host, port)

            with server:
                if use_tls and not use_ssl:
                    server.starttls()
                if username and password:
                    server.login(username, password)
                server.sendmail(from_email, [recipient], msg.as_string())
            logger.info('SMTP sent to %s: %s', recipient, subject)
            return {'success': True, 'provider': 'smtp'}
        except Exception as e:
            logger.error('SMTP send failed: %s', e)
            return {'success': False, 'provider': 'smtp', 'error': str(e)}


PROVIDERS = {
    'email': SMTPProvider(),
    'dummy': DummyProvider(),
}


def render_template(template_str: str, context: dict) -> str:
    try:
        tmpl = Template(template_str or '')
        return tmpl.render(Context(context or {}))
    except Exception:
        return template_str


def send_notification(channel: str, recipient: str, template_code: str = None, context: dict = None, subject: str = None, body: str = None, user=None):
    # load template if provided
    template = None
    if template_code:
        try:
            template = NotificationTemplate.objects.filter(code=template_code, is_active=True).first()
        except Exception:
            template = None

    subject_template = subject or (template.subject_template if template else '')
    body_template = body or (template.body_template if template else '')

    rendered_subject = render_template(subject_template, context or {})
    rendered_body = render_template(body_template, context or {})

    provider = PROVIDERS.get(channel, PROVIDERS['dummy'])
    email_config = None
    if channel == 'email':
        email_config = EmailConfig.objects.filter(is_active=True, is_enabled=True, is_primary=True).first()
        if not email_config:
            email_config = EmailConfig.objects.filter(is_active=True, is_enabled=True).order_by('-updated_at').first()

        if email_config:
            is_otp = bool(template_code and 'otp' in template_code.lower())
            if is_otp and not email_config.allow_otps:
                return {'ok': False, 'detail': 'Active email config blocks OTP sending.'}
            if (not is_otp) and not email_config.allow_notifications:
                return {'ok': False, 'detail': 'Active email config blocks notification emails.'}

    notif = Notification.objects.create(
        user=user,
        channel=channel,
        recipient=recipient,
        subject=rendered_subject,
        message=rendered_body,
        status='pending',
        provider=channel if channel in PROVIDERS else 'dummy',
    )

    try:
        if channel == 'email':
            res = provider.send(recipient, rendered_subject, rendered_body, email_config=email_config)
        else:
            res = provider.send(recipient, rendered_subject, rendered_body)
        notif.status = 'sent' if res.get('success') else 'failed'
        notif.sent_at = timezone.now()
        notif.save(update_fields=['status', 'sent_at'])
        return {'ok': True, 'detail': res}
    except Exception as exc:
        logger.exception('Notification send failed')
        notif.status = 'failed'
        notif.save(update_fields=['status'])
        return {'ok': False, 'detail': str(exc)}
