# -*- coding: utf-8 -*-
import json
import re

from django.http import JsonResponse
from django.shortcuts import render
from django.views.decorators.http import require_POST

from . import pricing
from .models import Order

# Mirrors BD_MOBILE_RE in index.html
BD_MOBILE_RE = re.compile(r'^(?:\+?88)?01[3-9]\d{8}$')

# Bengali digits ০-৯ -> 0-9
BN_DIGITS = {ord('০') + i: str(i) for i in range(10)}

# spaces, zero-width joiners, dashes, dots and brackets a customer may type
PHONE_JUNK_RE = re.compile(r'[\s ​‌‍\-().]')


def index(request):
    return render(request, 'index.html')


# --------------------------------------------------------------------------
# helpers
# --------------------------------------------------------------------------
def _bn_to_en(value):
    return str(value or '').translate(BN_DIGITS)


def _clean_phone(raw):
    """Same cleaning the page does before it validates a number."""
    s = PHONE_JUNK_RE.sub('', _bn_to_en(raw))
    s = re.sub(r'^00', '+', s)
    if s.find('+') > 0:
        s = s.replace('+', '')
    return s


def _normalise_msisdn(raw):
    """'8801XXXXXXXXX' (13 digits, no plus) or None when the number is wrong."""
    c = _clean_phone(raw)
    if not BD_MOBILE_RE.match(c):
        return None
    digits = c.lstrip('+')
    return digits if digits.startswith('88') else '88' + digits


def _squash(value, limit):
    return re.sub(r'\s+', ' ', str(value or '')).strip()[:limit]


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


def _payload(request):
    """Read the order from a JSON body, falling back to a normal form POST."""
    if 'application/json' in request.META.get('CONTENT_TYPE', ''):
        try:
            data = json.loads(request.body.decode('utf-8') or '{}')
        except (ValueError, UnicodeDecodeError):
            return None
        return data if isinstance(data, dict) else None
    return request.POST.dict()


# --------------------------------------------------------------------------
# validation — the same rules, and the same Bangla messages, as the page
# --------------------------------------------------------------------------
def _validate(data):
    """Return (cleaned, errors). Error keys are the input ids used on the page."""
    errors = {}
    cleaned = {}

    name = _squash(data.get('name'), 60)
    if not name:
        errors['cust-name'] = 'আপনার নাম লিখুন।'
    elif len(name) < 2:
        errors['cust-name'] = 'আপনার নামটি লিখুন (কমপক্ষে ২ অক্ষর)।'
    cleaned['customer_name'] = name

    address = _squash(data.get('address'), 300)
    if not address:
        errors['cust-address'] = 'ডেলিভারির সম্পূর্ণ ঠিকানা লিখুন।'
    elif len(address) < 10:
        errors['cust-address'] = ('পূর্ণ ঠিকানা লিখুন — বাসা/রোড, এলাকা, থানা ও '
                                  'জেলা সহ (কমপক্ষে ১০ অক্ষর)।')
    cleaned['address'] = address

    phone_typed = _squash(data.get('phone'), 25)
    msisdn = _normalise_msisdn(phone_typed)
    if not phone_typed:
        errors['cust-phone'] = 'মোবাইল নম্বর লিখুন।'
    elif msisdn is None:
        errors['cust-phone'] = 'সঠিক মোবাইল নম্বর লিখুন, যেমন ০১৭XXXXXXXX।'
    cleaned['phone'] = msisdn or ''
    cleaned['phone_typed'] = phone_typed

    area = str(data.get('area') or '').strip()
    if area not in ('inside', 'outside'):
        errors['area'] = 'ডেলিভারি এলাকা নির্বাচন করুন।'
        area = 'outside'
    cleaned['delivery_area'] = area

    try:
        qty = int(_bn_to_en(data.get('qty')))
    except (TypeError, ValueError):
        qty = pricing.MIN_QTY
    cleaned['quantity'] = max(pricing.MIN_QTY, min(pricing.MAX_QTY, qty))

    color = _squash(data.get('color'), 20)
    if pricing.COLOR_VALUES:
        if color not in pricing.COLOR_VALUES:
            errors['color'] = 'কোন রঙের ব্যাগটি চান বেছে নিন।'
            color = ''
    else:
        color = ''
    cleaned['color'] = color

    gift_size = _squash(data.get('gift_size'), 10)
    if pricing.GIFT:
        if gift_size not in pricing.GIFT_SIZES:
            errors['giftSize'] = 'বাবুর কিডস টি-শার্টের সাইজটি বেছে নিন।'
            gift_size = ''
    else:
        gift_size = ''
    cleaned['gift'] = pricing.GIFT if pricing.GIFT else ''
    cleaned['gift_size'] = gift_size

    return cleaned, errors


# --------------------------------------------------------------------------
# the order endpoint
# --------------------------------------------------------------------------
@require_POST
def place_order(request):
    data = _payload(request)
    if data is None:
        return JsonResponse(
            {'ok': False, 'message': 'অর্ডারের তথ্য পড়া যায়নি। আবার চেষ্টা করুন।'},
            status=400)

    cleaned, errors = _validate(data)
    if errors:
        return JsonResponse(
            {'ok': False,
             'errors': errors,
             'message': 'কিছু তথ্য ঠিক করতে হবে — লাল লেখাগুলো দেখুন।'},
            status=400)

    # Money is never read from the browser.
    money = pricing.quote(cleaned['quantity'], cleaned['delivery_area'])

    order = Order.objects.create(
        customer_name=cleaned['customer_name'],
        phone=cleaned['phone'],
        phone_typed=cleaned['phone_typed'],
        address=cleaned['address'],
        country='BD',
        product_name=pricing.PRODUCT_NAME,
        product_name_en=pricing.PRODUCT_NAME_EN,
        product_sku=pricing.PRODUCT_SKU,
        color=cleaned['color'],
        quantity=cleaned['quantity'],
        delivery_area=cleaned['delivery_area'],
        gift=cleaned['gift'],
        gift_size=cleaned['gift_size'],
        ip_address=_client_ip(request),
        user_agent=request.META.get('HTTP_USER_AGENT', '')[:300],
        **money
    )

    return JsonResponse({
        'ok': True,
        'order_no': order.order_no,
        'total': order.total,
        'delivery_charge': order.delivery_charge,
        'subtotal': order.subtotal,
        'message': 'অর্ডারটি আমরা পেয়েছি।',
    })
