import logging
import requests
from django.conf import settings

logger = logging.getLogger(__name__)

# mNotify has two API versions with different endpoints and auth styles.
# V1: GET https://apps.mnotify.net/smsapi?key=KEY&to=NUM&msg=MSG&sender_id=ID
# V2: POST https://api.mnotify.com/api/sms/quick?key=KEY  (JSON body)
# Check your dashboard (Developer section) to see which key type you have.
# V1 keys look like short alphanumeric strings.
# V2 keys are longer and require a different endpoint.
MNOTIFY_V1_BASE = "https://apps.mnotify.net/smsapi"
MNOTIFY_V2_BASE = "https://api.mnotify.com/api/sms/quick"


def _send(phone: str, message: str) -> bool:
    """
    Send SMS via mNotify. Automatically tries V2 first, falls back to V1.
    Ghana phone numbers accepted as 0XXXXXXXXX, 233XXXXXXXXX, or +233XXXXXXXXX.
    mNotify success code: "1000"
    """
    api_key = getattr(settings, "MNOTIFY_API_KEY", "")
    sender_id = getattr(settings, "MNOTIFY_SENDER_ID", "ACA")

    if not api_key:
        logger.warning("MNOTIFY_API_KEY not configured — SMS skipped: %s", message[:60])
        return False

    # Normalise phone: mNotify accepts 0XXXXXXXXX or 233XXXXXXXXX
    phone = phone.strip().replace(" ", "").replace("-", "")

    # Try V2 (JSON POST) first — this is the current recommended API
    try:
        v2_result = _send_v2(api_key, sender_id, phone, message)
        if v2_result is not None:
            return v2_result
    except Exception as exc:
        logger.debug("mNotify V2 attempt failed, falling back to V1: %s", exc)

    # Fallback to V1 (GET query params) — legacy endpoint
    return _send_v1(api_key, sender_id, phone, message)


def _send_v2(api_key: str, sender_id: str, phone: str, message: str):
    """
    mNotify API V2: POST to https://api.mnotify.com/api/sms/quick
    Body: { recipient: [...], sender: "ID", message: "...", is_schedule: false, schedule_date: "" }
    Auth: ?key=API_KEY as query param
    Returns True on success, False on known failure, None if response is unrecognisable.
    """
    url = f"{MNOTIFY_V2_BASE}?key={api_key}"
    payload = {
        "recipient": [phone],
        "sender": sender_id,
        "message": message,
        "is_schedule": False,
        "schedule_date": "",
    }
    try:
        resp = requests.post(url, json=payload, timeout=10)
        data = resp.json() if resp.content else {}
        code = str(data.get("code", ""))
        status = str(data.get("status", "")).lower()

        if code == "1000" or status == "success":
            logger.info("SMS sent via mNotify V2 to %s", _mask_phone(phone))
            return True
        elif code in ("1002", "1003", "1004", "1005"):
            logger.warning("mNotify V2 error %s: %s", code, data.get("message", ""))
            return False
        else:
            # Unknown response — let V1 fallback try
            logger.debug("mNotify V2 unrecognised response: %s", data)
            return None
    except Exception as exc:
        logger.debug("mNotify V2 request failed: %s", exc)
        return None


def _send_v1(api_key: str, sender_id: str, phone: str, message: str) -> bool:
    """
    mNotify API V1: GET https://apps.mnotify.net/smsapi
    Params: key, to, msg, sender_id
    Returns True on success code "1000".
    """
    params = {
        "key": api_key,
        "to": phone,
        "msg": message,
        "sender_id": sender_id,
    }
    try:
        resp = requests.get(MNOTIFY_V1_BASE, params=params, timeout=10)
        # V1 returns plain text "1000" or a JSON object depending on version
        text = resp.text.strip() if resp.content else ""
        # Try JSON first
        try:
            import json as _json
            data = _json.loads(text)
            code = str(data.get("code", ""))
            if code == "1000":
                logger.info("SMS sent via mNotify V1 to %s", _mask_phone(phone))
                return True
            logger.warning("mNotify V1 returned non-success: %s", data)
            return False
        except Exception:
            pass
        # Plain text response
        if text == "1000":
            logger.info("SMS sent via mNotify V1 to %s", _mask_phone(phone))
            return True
        logger.warning("mNotify V1 non-success response: %s", text)
        return False
    except Exception as exc:
        logger.error("mNotify V1 request error: %s", exc)
        return False


def _mask_phone(phone: str) -> str:
    if len(phone) > 6:
        return phone[:4] + "****" + phone[-3:]
    return "***"


# ─────────────────────────────────────────────────────────────────────────────
# Business-level SMS functions — unchanged interface, all call _send()
# ─────────────────────────────────────────────────────────────────────────────

def sms_buyer_payment_confirmed(phone: str, order_number: str, amount: float, vendor_name: str) -> bool:
    msg = (
        f"ACA: Payment of GHS {amount:.2f} received for order {order_number} "
        f"from {vendor_name}. Funds are held is held securely until you confirm order delivery. "
        f"You will be notified after the seller delivers the order."
    )
    return _send(phone, msg)


def sms_vendor_payment_received(phone: str, order_number: str, amount: float, payout: float) -> bool:
    msg = (
        f"ACA: New order {order_number} paid — GHS {amount:.2f}. "
        f"Your payout of GHS {payout:.2f} will be released once the buyer confirms delivery. "
        f"Please mark delivery complete with a photo once delivered."
    )
    return _send(phone, msg)


def sms_buyer_delivery_uploaded(
    phone: str, order_number: str, vendor_name: str, confirm_url: str
) -> bool:
    msg = (
        f"ACA: {vendor_name} has delivered order {order_number}. "
        f"Have you received your item? Confirm here: {confirm_url} "
        f"(If you don't respond in 48 hours, payment is auto-released to seller.)"
    )
    return _send(phone, msg)


def sms_buyer_reminder_auto_release(phone: str, order_number: str, hours_left: int, confirm_url: str) -> bool:
    msg = (
        f"ACA Reminder: Order {order_number} delivery is confirmed. "
        f"You have {hours_left}h left before payment is auto-released to the seller if you don't confirm receipt. "
        f"Confirm here: {confirm_url}"
    )
    return _send(phone, msg)


def sms_vendor_buyer_confirmed(phone: str, order_number: str, payout: float) -> bool:
    msg = (
        f"ACA: Great news! The buyer has confirmed receipt of order {order_number}. "
        f"GHS {payout:.2f} is being transferred to your payout account. "
        f"Thank you for selling on ACA."
    )
    return _send(phone, msg)


def sms_vendor_payout_sent(phone: str, order_number: str, payout: float) -> bool:
    msg = (
        f"ACA: GHS {payout:.2f} payout for order {order_number} has been sent to "
        f"your payout account. Please allow 1-2 business days for bank transfers."
    )
    return _send(phone, msg)


def sms_vendor_disputed(phone: str, order_number: str) -> bool:
    msg = (
        f"ACA: The buyer for order {order_number} has raised a dispute regarding order delivery. "
        f"Our team will contact both parties within 48 hours to resolve this. "
        f"Please hold off on any further action until you hear from us."
    )
    return _send(phone, msg)


def sms_vendor_auto_released(phone: str, order_number: str, payout: float) -> bool:
    msg = (
        f"ACA: The buyer did not respond within 48 hours for order {order_number}, "
        f"GHS {payout:.2f} has been auto-released and sent to your payout account."
    )
    return _send(phone, msg)


def sms_buyer_auto_released(phone: str, order_number: str) -> bool:
    msg = (
        f"ACA: Since you did not respond within 48 hours for order {order_number}, "
        f"the payment has been auto-released to the seller. "
        f"Contact support@mirjy.com if you have any concerns."
    )
    return _send(phone, msg)


def sms_admin_dispute_alert(phone: str, order_number: str, buyer_name: str, vendor_name: str) -> bool:
    msg = (
        f"ACA Admin Alert: Dispute raised on order {order_number}. "
        f"Buyer: {buyer_name} | Seller: {vendor_name}. "
        f"Dispute investigation triggered. Kindly allow 48 hours for investigation."
        f"Please hold off on any further action until you hear from us."
    )
    return _send(phone, msg)