"""
Centralised email sending. The company name comes from Settings at send
time, never from a literal, so a copy of this file cannot sign a client's
emails with somebody else's name.
All outgoing emails use branded HTML templates in templates/public/emails/.
"""
import random
from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string
from django.conf import settings

# Department signatures — one is picked at random per email sent
_SIGNATURES = {
    'client_services': [
        ('Emily Carter',    'Client Services'),
        ('James Harrington','Client Services'),
        ('Sophie Bennett',  'Client Services'),
    ],
    'projects': [
        ('Daniel Walsh',  'Projects'),
        ('Rachel Owens',  'Projects'),
        ('Marcus Reid',   'Projects'),
    ],
    'accounts': [
        ('Natalie Brooks', 'Account Management'),
        ('Oliver Kent',    'Account Management'),
        ('Priya Sharma',   'Account Management'),
    ],
}


def _pick(department):
    name, dept = random.choice(_SIGNATURES[department])
    return {'sig_name': name, 'sig_dept': dept}


def _get_from_email(display_name=''):
    """Return the configured from address with display name."""
    try:
        from apps.pages.models import SiteSettings
        from apps.tenants.models import Tenant
        tenant = Tenant.objects.filter(is_master=True).first()
        site = SiteSettings.load(tenant)
        if site and site.smtp_from_email:
            addr = site.smtp_from_email
            return f'{display_name} <{addr}>'
    except Exception:
        pass
    addr = _outgoing()
    return f'{display_name} <{addr}>'


from apps.pages.branding import company_name


def _send(subject, to, template, context, from_email=None, reply_to=None, email_type='other'):
    """Render an HTML email template and send it, with a plain-text fallback."""
    from_email = from_email or _get_from_email()
    # render_to_string does not run context processors, so an email template
    # sees none of what a page sees. Merge the brand in here rather than in
    # every caller, and let a caller override it if it ever needs to.
    from apps.pages.branding import brand
    context = {**brand(), **(context or {})}
    html_body  = render_to_string(template, context)

    # Build a minimal plain-text fallback by stripping tags
    import re
    plain = re.sub(r'<[^>]+>', ' ', html_body)
    plain = re.sub(r'[ \t]+', ' ', plain)
    plain = re.sub(r'\n{3,}', '\n\n', plain).strip()

    error_msg = ''
    ok = True
    try:
        msg = EmailMultiAlternatives(subject, plain, from_email, [to],
                                     reply_to=reply_to or [])
        msg.attach_alternative(html_body, 'text/html')
        msg.send()
    except Exception as exc:
        ok = False
        error_msg = str(exc)
        raise
    finally:
        try:
            from apps.ecommerce.models import EmailLog
            EmailLog.objects.create(
                email_type=email_type,
                subject=subject,
                to_email=to,
                from_email=from_email,
                html_body=html_body,
                ok=ok,
                error=error_msg,
            )
        except Exception:
            pass  # Never let logging break email sending


# ── Order emails ──────────────────────────────────────────────────────────────

def send_order_confirmation(order):
    """Send a payment confirmation to the customer."""
    try:
        order_url = f'{settings.SITE_URL}/products/order/{order.order_number}/'
        _send(
            subject=f'Order Confirmed — #{order.order_number} | {company_name()}',
            to=order.customer_email,
            template='public/emails/order_confirmation.html',
            email_type='order_confirmation',
            context={
                'customer_name': order.customer_name,
                'order_number':  order.order_number,
                'items':         order.items.all(),
                'amount_paid':   order.amount_paid,
                'order_url':     order_url,
                **_pick('client_services'),
            },
        )
    except Exception:
        pass  # Never let email failure break the payment flow


def send_order_cancellation(order):
    """Send a refund/cancellation notice to the customer."""
    try:
        _send(
            subject=f'Order {order.display_number} Cancelled | {company_name()}',
            to=order.customer_email,
            template='public/emails/order_cancellation.html',
            email_type='order_cancellation',
            context={
                'customer_name': order.customer_name,
                'order_number':  order.display_number,
                'items':         order.items.all(),
                **_pick('accounts'),
            },
        )
    except Exception:
        pass


def send_order_admin_notification(order, request=None):
    """Notify the admin that a new order has been paid."""
    admin_email = getattr(settings, 'ADMIN_EMAIL', '') or _outgoing()
    if not admin_email:
        return
    try:
        if request:
            cms_url = request.build_absolute_uri(f'/cms/orders/{order.pk}/')
        else:
            cms_url = f'https://example.com/cms/orders/{order.pk}/'

        _send(
            subject=f'New Order — #{order.order_number} £{order.amount_paid} | {company_name()} CMS',
            to=admin_email,
            template='public/emails/order_admin_notification.html',
            email_type='admin_notification',
            context={
                'order_number':    order.order_number,
                'customer_name':   order.customer_name,
                'customer_email':  order.customer_email,
                'customer_phone':  order.customer_phone,
                'customer_company': order.customer_company,
                'customer_address': order.customer_address,
                'customer_postcode': order.customer_postcode,
                'customer_country': order.customer_country,
                'customer_notes':  order.customer_notes,
                'items':           order.items.all(),
                'amount_paid':     order.amount_paid,
                'cms_order_url':   cms_url,
            },
        )
    except Exception:
        pass


# ── Quote email ───────────────────────────────────────────────────────────────

def send_tenant_invoice(invoice):
    """
    Email a tenant invoice to the client. Returns the address it went to, or
    raises so the caller can report the failure.
    """
    tenant = invoice.tenant
    to = (
        (tenant.billing_email or '').strip()
        or (getattr(tenant.owner, 'email', '') or '').strip()
    )
    if not to:
        raise ValueError('No billing email or owner email set for this tenant.')

    _send(
        subject=f'Invoice {invoice.invoice_number} from {company_name()}',
        to=to,
        template='public/emails/tenant_invoice.html',
        context={'invoice': invoice, 'tenant': tenant},
        email_type='other',
    )
    return to


def send_quote_email(assessment, sender, quote=None):
    """
    Send a project quotation to a client.

    `quote` is the AssessmentQuote record. When given, the email carries the
    accept and advisor links and states the validity date.
    """
    first_name = getattr(assessment, 'first_name', None) or assessment.name.split()[0]

    quote_url = quote_expires = None
    if quote is not None:
        site = (getattr(settings, 'SITE_URL', '') or '').rstrip('/')
        quote_url = f'{site}/quote/{quote.accept_token}/'
        quote_expires = quote.expires_at

    sender_parts = []
    if hasattr(sender, 'position') and sender.position:
        sender_parts.append(sender.position)
    if hasattr(sender, 'company') and sender.company:
        sender_parts.append(sender.company)
    sender_title = ' at '.join(sender_parts) if sender_parts else ''

    from apps.pages.email_backend import support_credentials
    support_email = support_credentials()[0]
    _send(
        subject=f'Your Project Quotation from {company_name()} — {assessment.ai_label or assessment.service_types_display}',
        to=assessment.email,
        template='public/emails/quote_email.html',
        email_type='quote',
        from_email=_get_from_email(f'{company_name()} Sales Team'),
        reply_to=[support_email],
        context={
            'first_name':    first_name,
            'project_label': assessment.ai_label or assessment.service_types_display,
            'quote_amount':  assessment.quote_amount,
            'quote_weeks':   assessment.quote_weeks,
            'quote_notes':   assessment.quote_notes,
            'service_types': assessment.service_types_display,
            'budget':        assessment.get_budget_display(),
            'timeline':      assessment.get_timeline_display(),
            'quote_url':     quote_url,
            'quote_expires': quote_expires,
            **_pick('projects'),
        },
    )


# ── Deal email ────────────────────────────────────────────────────────────────

def send_deal_email(order, deal_url):
    """Send a deal agreement link to the client."""
    _send(
        subject=f'Your Agreement is Ready — Order #{order.order_number} | {company_name()}',
        to=order.customer_email,
        template='public/emails/deal_email.html',
        email_type='deal',
        context={
            'customer_name': order.customer_name,
            'order_number':  order.order_number,
            'items':         order.items.all(),
            'total':         order.total,
            'deal_url':      deal_url,
            **_pick('accounts'),
        },
    )


def _outgoing():
    """The sending address, from Settings. Never .env."""
    from apps.pages.email_backend import outgoing_address
    return outgoing_address()
