"""
Public deal agreement views.
Flow: /deal/<token>/ → client reads T&C, types name, accepts → Stripe payment → done.
"""
from django.shortcuts import render, get_object_or_404, redirect
from django.utils import timezone
from django.conf import settings

from .models import DealAgreement, Order
from apps.pages.branding import company_name


# T&C content by terms type
_TERMS = {
    'service': {
        'title': 'Service Agreement',
        'icon': 'fa-solid fa-handshake',
        'sections': [
            ('Scope of Work', (
                '{company} will deliver the agreed services as specified in your order. '
                'Any changes to scope must be agreed in writing before work begins on the revised scope.'
            )),
            ('Payment Terms', (
                'Payment is due as specified in this agreement. Late payments may attract a 5% monthly '
                'surcharge. Final deliverables will be released upon receipt of full cleared payment.'
            )),
            ('Revisions', (
                'The agreed number of revisions is included in your project. Additional revision '
                'rounds beyond what is specified will be quoted separately.'
            )),
            ('Intellectual Property', (
                'Upon receipt of full payment, all intellectual property rights for custom work '
                'produced specifically for you transfer to you. Third-party assets (fonts, stock images, '
                'plugins) remain subject to their respective licences.'
            )),
            ('Confidentiality', (
                'Both parties agree to keep confidential any proprietary information shared during '
                'the project. {company} may reference your project in its portfolio unless you '
                'request otherwise in writing.'
            )),
            ('Cancellation', (
                'You may cancel this agreement with 14 days written notice. Work completed and '
                'costs incurred up to the cancellation date remain payable.'
            )),
            ('Governing Law', (
                'This agreement is governed by the laws of England and Wales. Any disputes will '
                'be resolved in the courts of England and Wales.'
            )),
        ],
    },
    'subscription': {
        'title': 'Subscription Agreement',
        'icon': 'fa-solid fa-rotate',
        'sections': [
            ('Recurring Billing', (
                'Your subscription will be billed on the same date each month (or year, as agreed). '
                'Payments are processed automatically via Stripe. You will receive a receipt by email '
                'after each successful payment.'
            )),
            ('Services Included', (
                'The services covered by this subscription are as specified in your order. '
                'Any additional services outside the subscription scope will be quoted separately.'
            )),
            ('Cancellation Notice', (
                'You may cancel your subscription at any time by giving 30 days written notice to '
                'support@example.com. No refunds will be issued for the current billing period. '
                'Service continues until the end of the paid period.'
            )),
            ('Service Continuity', (
                '{company} will use reasonable endeavours to maintain uninterrupted service. '
                'Planned maintenance will be notified in advance. Emergency maintenance may occur '
                'without prior notice.'
            )),
            ('Price Changes', (
                'We may adjust subscription pricing with 30 days written notice. You may cancel '
                'without penalty within the notice period if you do not accept the new pricing.'
            )),
            ('Governing Law', (
                'This agreement is governed by the laws of England and Wales.'
            )),
        ],
    },
    'instalment': {
        'title': 'Instalment Plan Agreement',
        'icon': 'fa-solid fa-calendar-days',
        'sections': [
            ('Payment Schedule', (
                'You agree to pay the total amount due in instalments as specified in your order. '
                'The first payment is due immediately upon acceptance. Subsequent payments follow '
                'the agreed schedule.'
            )),
            ('Late Payments', (
                'Instalments must be paid on or before the agreed due date. Payments more than '
                '7 days late will incur a 5% late fee. {company} reserves the right to pause '
                'work or services until overdue amounts are cleared.'
            )),
            ('Default', (
                'If two consecutive instalments are missed without prior agreement, the full '
                'outstanding balance becomes immediately payable. {company} may pursue the '
                'outstanding amount through legal channels if necessary.'
            )),
            ('Work Delivery', (
                'Deliverables and services are released in line with the payment schedule. '
                'Full handover occurs upon receipt of the final instalment and all amounts cleared.'
            )),
            ('Cancellation', (
                'You may cancel this agreement with 14 days written notice. All instalments paid '
                'to date are non-refundable. Work completed remains payable.'
            )),
            ('Governing Law', (
                'This agreement is governed by the laws of England and Wales.'
            )),
        ],
    },
    'domain': {
        'title': 'Domain Registration Agreement',
        'icon': 'fa-solid fa-globe',
        'sections': [
            ('Registration', (
                '{company} will register the domain name(s) specified in your order for the '
                'period agreed. Registration is subject to availability and registrar approval.'
            )),
            ('Ownership', (
                'You are the registrant and owner of the domain. {company} acts as your '
                'registration agent. You are responsible for ensuring your contact details remain '
                'accurate with the registrar.'
            )),
            ('Renewal', (
                'Domain registrations do not renew automatically unless otherwise agreed. '
                '{company} will notify you 60 days before expiry. Failure to renew may result '
                'in the domain becoming available to third parties.'
            )),
            ('Transfer', (
                'You may transfer your domain to another registrar at any time after 60 days '
                'from registration. Transfer codes will be provided upon request.'
            )),
            ('Prohibited Use', (
                'You agree not to use the domain for spam, phishing, or any activity that '
                'violates applicable law or registrar policies. Violation may result in '
                'suspension or deletion of the domain.'
            )),
            ('Governing Law', (
                'This agreement is governed by the laws of England and Wales and applicable '
                'ICANN and registry policies.'
            )),
        ],
    },
    'general': {
        'title': 'Terms and Conditions',
        'icon': 'fa-solid fa-file-contract',
        'sections': [
            ('Agreement', (
                'By accepting these terms you enter into a binding agreement with {company} '
                'Web / App Design and Development for the services or products specified in '
                'your order.'
            )),
            ('Payment', (
                'Payment is due as specified. {company} reserves the right to withhold '
                'deliverables until payment is received in full.'
            )),
            ('Cancellation', (
                'Cancellation requests must be made in writing. Work completed up to the '
                'cancellation date remains payable.'
            )),
            ('Liability', (
                '{company}\'s total liability under this agreement shall not exceed the '
                'total amount paid by you. We are not liable for indirect or consequential loss.'
            )),
            ('Governing Law', (
                'This agreement is governed by the laws of England and Wales.'
            )),
        ],
    },
}


def _terms_for(terms_type, tenant=None):
    """
    The agreement text with this install's name written into it.

    The literal used to be baked into every clause, which meant a copy of this
    file put another company's name into a client's binding agreement. The
    clauses now carry {company} and it is filled at render time from Settings.
    """
    from apps.pages.branding import company_name
    import copy
    co = company_name(tenant) or 'the supplier'
    block = copy.deepcopy(_TERMS.get(terms_type, _TERMS['general']))
    block['sections'] = [
        (heading, body.replace('{company}', co))
        for heading, body in block['sections']
    ]
    return block


def _site_url():
    from django.conf import settings as _s
    return (getattr(_s, 'SITE_URL', '') or '').rstrip('/')


def _shows_schedule(agreement, order):
    """
    The 40/40/20 schedule applies to project work taking a first instalment,
    not to a domain reservation or a one-off purchase.
    """
    return bool(
        agreement.terms_type == agreement.TERMS_SERVICE
        and getattr(order, 'is_deposit_order', False)
    )


def deal_agreement(request, token):
    """Show the T&C agreement page to the client."""
    agreement = get_object_or_404(DealAgreement, token=token)
    order     = agreement.order

    if agreement.is_accepted:
        return render(request, 'public/deal/already_accepted.html', {
            'agreement': agreement,
            'order':     order,
        })

    terms = _terms_for(agreement.terms_type, getattr(order, 'tenant', None))

    return render(request, 'public/deal/agreement.html', {
        'agreement':     agreement,
        'order':         order,
        'terms':         terms,
        'site_url':      _site_url(),
        'show_schedule': _shows_schedule(agreement, order),
    })


def deal_accept(request, token):
    """Process the signed agreement and redirect to Stripe payment."""
    if request.method != 'POST':
        return redirect('deal_agreement', token=token)

    agreement = get_object_or_404(DealAgreement, token=token)
    order     = agreement.order

    if agreement.is_accepted:
        return redirect('deal_success', token=token)

    signed_name = request.POST.get('signed_name', '').strip()
    confirmed   = request.POST.get('confirmed') == '1'

    # The four boxes are checked here, not just in the browser. A form posted
    # without them must not produce a signed agreement.
    required_ticks = {
        'agree_purchase': 'Purchase Policy',
        'agree_privacy':  'Privacy Policy',
        'agree_terms':    'Terms and Conditions',
        'agree_deal':     'The proposed deal and project',
    }
    ticked = [label for field, label in required_ticks.items() if request.POST.get(field)]
    all_ticked = len(ticked) == len(required_ticks)

    if not signed_name or not confirmed or not all_ticked:
        terms = _terms_for(agreement.terms_type, getattr(order, 'tenant', None))
        return render(request, 'public/deal/agreement.html', {
            'agreement':   agreement,
            'order':       order,
            'terms':       terms,
            'site_url':    _site_url(),
            'show_schedule': _shows_schedule(agreement, order),
            'error':       'Please type your full name in capitals and tick all four boxes to proceed.',
            'form_name':   signed_name,
        })

    # Save the signature
    ip = (request.META.get('HTTP_X_FORWARDED_FOR') or '').split(',')[0].strip() \
         or request.META.get('REMOTE_ADDR', '')
    agreement.signed_name  = signed_name.upper()
    agreement.accepted_at  = timezone.now()
    agreement.accepted_ip  = ip or None
    agreement.user_agent   = request.META.get('HTTP_USER_AGENT', '')[:500]
    agreement.accepted_terms = '\n'.join(f'Accepted: {label}' for label in ticked)
    agreement.save(update_fields=[
        'signed_name', 'accepted_at', 'accepted_ip', 'user_agent', 'accepted_terms',
    ])

    # Create Stripe checkout session
    try:
        import stripe
        from apps.ecommerce.stripe_utils import _get_stripe_secret_key
        stripe.api_key = _get_stripe_secret_key()

        # Determine amount: balance due if partially paid, else full total
        amount_pence = int(order.balance_due * 100) if order.balance_due > 0 else int(order.total * 100)

        if amount_pence <= 0:
            # Already fully paid — go straight to success
            return redirect('deal_success', token=token)

        # Build description
        items_desc = ', '.join(
            item.product_name for item in order.items.all()
        ) or f'Order #{order.order_number}'

        success_url = request.build_absolute_uri(f'/deal/{token}/success/?session_id={{CHECKOUT_SESSION_ID}}')
        cancel_url  = request.build_absolute_uri(f'/deal/{token}/')

        session = stripe.checkout.Session.create(
            payment_method_types=['card'],
            line_items=[{
                'price_data': {
                    'currency': 'gbp',
                    'unit_amount': amount_pence,
                    'product_data': {
                        'name': items_desc,
                        'description': f'Order #{order.order_number} — {company_name(getattr(order, "tenant", None))}',
                    },
                },
                'quantity': 1,
            }],
            mode='payment',
            success_url=success_url,
            cancel_url=cancel_url,
            customer_email=order.customer_email,
            metadata={
                'order_id':      str(order.id),
                'order_number':  order.order_number,
                'agreement_id':  str(agreement.id),
                'is_deposit':    'false',
            },
        )
        agreement.stripe_session_id = session.id
        agreement.save(update_fields=['stripe_session_id'])
        return redirect(session.url)

    except Exception as e:
        # Stripe failed — show success page with manual payment note
        return render(request, 'public/deal/agreement.html', {
            'agreement':     agreement,
            'order':         order,
            'terms':         _terms_for(agreement.terms_type, getattr(order, 'tenant', None)),
            'site_url':      _site_url(),
            'show_schedule': _shows_schedule(agreement, order),
            'error':         f'Your agreement was saved but payment could not be started: {e}. Please contact us.',
        })


def deal_success(request, token):
    """Payment complete — the deal is sealed."""
    agreement = get_object_or_404(DealAgreement, token=token)
    order     = agreement.order

    # Mark order paid if Stripe session succeeded
    session_id = request.GET.get('session_id', '')
    if session_id and not order.is_fully_paid:
        try:
            import stripe
            from apps.ecommerce.stripe_utils import _get_stripe_secret_key
            stripe.api_key = _get_stripe_secret_key()
            session = stripe.checkout.Session.retrieve(session_id)
            if session.payment_status == 'paid':
                amount = session.amount_total / 100
                order.mark_paid(amount, session.payment_intent or '')  # returns False on a duplicate
        except Exception:
            pass

    return render(request, 'public/deal/success.html', {
        'agreement': agreement,
        'order':     order,
    })
