"""
Public quote response pages.

A quote email carries one unguessable link. From it the client can either ask
to speak to an advisor, which simply tells us to call them, or accept the
offer, which creates the order and hands over to the existing agreement flow
at /deal/<token>/ for signature and the first payment.

Nothing here requires a login. The token is the credential.
"""
import logging

from django.conf import settings
from django.shortcuts import get_object_or_404, redirect, render
from django.utils import timezone

from .models import AssessmentQuote

log = logging.getLogger(__name__)

# Share of the project value taken on signature. The rest is invoiced from the
# panel: 40 per cent on delivery of the build, 20 per cent after testing.
DEPOSIT_SHARE = 0.40


def _client_ip(request):
    return (request.META.get('HTTP_X_FORWARDED_FOR') or '').split(',')[0].strip() \
        or request.META.get('REMOTE_ADDR') or None


def _notify_admins(subject, body):
    """Tell every system administrator, by whatever channels are configured."""
    try:
        from apps.ftlink.alerts import _recipients
        from django.core.mail import send_mail
        from apps.ecommerce.email_utils import _get_from_email
        people = _recipients()
    except Exception:
        log.exception('Could not resolve alert recipients')
        return

    for person in people:
        if person.get('email'):
            try:
                send_mail(subject, body, _get_from_email(), [person['email']], fail_silently=True)
            except Exception:
                log.exception('Quote notification email failed for %s', person['email'])
        if person.get('phone'):
            try:
                from apps.pages.sms_utils import send_sms
                send_sms(person['phone'], body[:300])
            except Exception:
                log.exception('Quote notification SMS failed for %s', person['phone'])


def _context(quote):
    a = quote.assessment
    return {
        'quote':       quote,
        'assessment':  a,
        'amount':      quote.quote_amount or a.quote_amount,
        'weeks':       quote.quote_weeks or a.quote_weeks,
        'notes':       quote.quote_notes or a.quote_notes,
        'label':       a.ai_label or a.service_types_display,
        'expired':     quote.is_expired,
        'site_url':    (getattr(settings, 'SITE_URL', '') or '').rstrip('/'),
    }


def quote_offer(request, token):
    """The offer, with the two choices."""
    quote = get_object_or_404(AssessmentQuote, accept_token=token)
    return render(request, 'public/quote/offer.html', _context(quote))


def quote_advisor(request, token):
    """Client would rather talk to a person. Record it and tell the team."""
    quote = get_object_or_404(AssessmentQuote, accept_token=token)
    if request.method != 'POST':
        return redirect('quote_offer', token=token)

    if quote.outcome == AssessmentQuote.OUTCOME_PENDING:
        quote.outcome = AssessmentQuote.OUTCOME_ADVISOR
        quote.responded_at = timezone.now()
        quote.responded_ip = _client_ip(request)
        quote.save(update_fields=['outcome', 'responded_at', 'responded_ip'])

        a = quote.assessment
        _notify_admins(
            f'Call requested: {a.name} about {a.ai_label or a.service_types_display}',
            (
                f'{a.name} has asked to speak to an advisor about quote #{quote.version}.\n\n'
                f'Email: {a.email}\n'
                f'Phone: {a.phone or "not provided"}\n'
                f'Company: {a.company or "not provided"}\n'
                f'Quote: {quote.quote_amount or "not set"}\n\n'
                f'Please contact them from support.'
            ),
        )

    ctx = _context(quote)
    ctx['done'] = 'advisor'
    return render(request, 'public/quote/thanks.html', ctx)


def quote_accept(request, token):
    """
    Client accepts. Create the order and the agreement, then hand over to the
    existing signature and payment flow rather than duplicating it here.
    """
    quote = get_object_or_404(AssessmentQuote, accept_token=token)
    if request.method != 'POST':
        return redirect('quote_offer', token=token)

    # Already accepted: send them back to their agreement rather than making a second one
    if quote.agreement_id:
        return redirect('deal_agreement', token=quote.agreement.token)

    from apps.ecommerce.models import DealAgreement, Order

    a = quote.assessment
    total = quote.quote_amount or a.quote_amount
    if not total:
        ctx = _context(quote)
        ctx['error'] = 'This quote has no amount set. Please contact us and we will confirm it.'
        return render(request, 'public/quote/offer.html', ctx)

    deposit = round(float(total) * DEPOSIT_SHARE, 2)

    try:
        tenant = None
        try:
            from apps.tenants.models import Tenant
            tenant = Tenant.objects.filter(is_master=True).first()
        except Exception:
            pass

        order = Order.objects.create(
            tenant=tenant,
            customer_name=a.name,
            customer_email=a.email,
            customer_phone=a.phone or '',
            customer_company=a.company or '',
            subtotal=deposit,
            total=deposit,
            is_deposit_order=True,
            ip_address=_client_ip(request),
            customer_notes=f'Accepted quote #{quote.version} for {a.ai_label or a.service_types_display}.',
            internal_notes=(
                f'Project value {total}. First payment {deposit} (40 per cent) on signature. '
                f'Remaining 40 per cent on delivery and 20 per cent after testing, to be invoiced.'
            ),
        )

        agreement = DealAgreement.objects.create(
            order=order,
            terms_type=DealAgreement.TERMS_SERVICE,
            sent_to_email=a.email,
            sent_to_name=a.name,
            sent_at=timezone.now(),
        )

        quote.outcome = AssessmentQuote.OUTCOME_ACCEPTED
        quote.responded_at = timezone.now()
        quote.responded_ip = _client_ip(request)
        quote.agreement = agreement
        quote.save(update_fields=['outcome', 'responded_at', 'responded_ip', 'agreement'])

        _notify_admins(
            f'Quote accepted: {a.name}, {a.ai_label or a.service_types_display}',
            (
                f'{a.name} has accepted quote #{quote.version}.\n\n'
                f'Project value: {total}\n'
                f'First payment due: {deposit}\n'
                f'Order: {order.order_number}\n\n'
                f'They are now on the agreement page. You will be notified again when they pay.'
            ),
        )
    except Exception:
        log.exception('Could not create order or agreement for quote %s', quote.pk)
        ctx = _context(quote)
        ctx['error'] = 'Something went wrong setting up your agreement. Please contact us and we will sort it out.'
        return render(request, 'public/quote/offer.html', ctx)

    return redirect('deal_agreement', token=agreement.token)
