"""
Initiate a Paystack charge-by-phone (mobile money) for WhatsApp checkout.
Paystack supports sending a USSD/MoMo prompt directly to a phone number.
"""
import logging
from typing import Optional

import requests
from django.conf import settings

logger = logging.getLogger(__name__)

PAYSTACK_BASE = "https://api.paystack.co"


def _headers():
    return {
        "Authorization": f"Bearer {settings.PAYSTACK_SECRET_KEY}",
        "Content-Type": "application/json",
    }


def initiate_mobile_money_charge(
    phone: str,
    email: str,
    amount_ghs: float,
    reference: str,
    metadata: dict = None,
    provider: str = "mtn",
) -> dict:
    """
    Send a mobile money prompt to the user's phone.
    provider: 'mtn' | 'vodafone' | 'airteltigo'
    Returns Paystack charge response dict.
    """
    payload = {
        "amount": int(round(amount_ghs * 100)),
        "email": email,
        "currency": "GHS",
        "reference": reference,
        "mobile_money": {
            "phone": _normalize_phone(phone),
            "provider": provider,
        },
        "metadata": metadata or {},
    }
    resp = requests.post(
        f"{PAYSTACK_BASE}/charge",
        headers=_headers(),
        json=payload,
        timeout=20,
    )
    resp.raise_for_status()
    data = resp.json()
    if not data.get("status"):
        raise ValueError(f"Paystack charge init failed: {data.get('message')}")
    return data["data"]


def submit_otp(reference: str, otp: str) -> dict:
    """User enters OTP to confirm payment."""
    resp = requests.post(
        f"{PAYSTACK_BASE}/charge/submit_otp",
        headers=_headers(),
        json={"reference": reference, "otp": otp},
        timeout=15,
    )
    resp.raise_for_status()
    return resp.json().get("data", {})


def submit_pin(reference: str, pin: str) -> dict:
    """User enters PIN to confirm payment."""
    resp = requests.post(
        f"{PAYSTACK_BASE}/charge/submit_pin",
        headers=_headers(),
        json={"reference": reference, "pin": pin},
        timeout=15,
    )
    resp.raise_for_status()
    return resp.json().get("data", {})


def verify_charge(reference: str) -> dict:
    resp = requests.get(
        f"{PAYSTACK_BASE}/transaction/verify/{reference}",
        headers=_headers(),
        timeout=15,
    )
    resp.raise_for_status()
    return resp.json().get("data", {})


def verify_charge_safe(reference: str) -> Optional[dict]:
    """
    Same as verify_charge but returns None on HTTP/network errors instead of raising.
    Missing or not-yet-settled transactions may return empty data.
    """
    try:
        resp = requests.get(
            f"{PAYSTACK_BASE}/transaction/verify/{reference}",
            headers=_headers(),
            timeout=15,
        )
        if resp.status_code == 404:
            return {}
        resp.raise_for_status()
        return resp.json().get("data") or {}
    except requests.RequestException as exc:
        logger.warning("verify_charge_safe failed for %s: %s", reference, exc)
        return None


def _normalize_phone(phone: str) -> str:
    """Ensure phone is in 0XXXXXXXXX format for Paystack Ghana."""
    phone = phone.strip().replace(" ", "").replace("-", "")
    if phone.startswith("+233"):
        phone = "0" + phone[4:]
    elif phone.startswith("233"):
        phone = "0" + phone[3:]
    return phone


def detect_provider(phone: str) -> str:
    """
    Guess MoMo provider from Ghana phone prefix.
    MTN: 024,054,055,059
    Vodafone: 020,050
    AirtelTigo: 026,056,027,057
    """
    p = _normalize_phone(phone)
    if p[:3] in ("024", "054", "055", "059", "023", "053"):
        return "mtn"
    if p[:3] in ("020", "050"):
        return "vodafone"
    if p[:3] in ("026", "056", "027", "057", "028", "058"):
        return "airteltigo"
    return "mtn"