# subscriptions/monnify.py
"""
Monnify Payment Gateway Integration.
Uses real API: https://api.monnify.com
"""
import base64
import hashlib
import hmac
import json
import logging
import requests
from django.conf import settings

logger = logging.getLogger(__name__)

MONNIFY_BASE_URL = getattr(settings, 'MONNIFY_BASE_URL', 'https://api.monnify.com')
MONNIFY_API_KEY = getattr(settings, 'MONNIFY_API_KEY', '')
MONNIFY_SECRET_KEY = getattr(settings, 'MONNIFY_SECRET_KEY', '')
MONNIFY_CONTRACT_CODE = getattr(settings, 'MONNIFY_CONTRACT_CODE', '')


# ─────────────────────────────────────────────────────────────
# AUTH TOKEN
# ─────────────────────────────────────────────────────────────

def _get_auth_token() -> str:
    """Obtain Monnify Bearer token via Basic Auth."""
    credentials = f"{MONNIFY_API_KEY}:{MONNIFY_SECRET_KEY}"
    encoded = base64.b64encode(credentials.encode()).decode()
    url = f"{MONNIFY_BASE_URL}/api/v1/auth/login"
    resp = requests.post(
        url,
        headers={
            "Authorization": f"Basic {encoded}",
            "Content-Type": "application/json",
        },
        timeout=15,
    )
    resp.raise_for_status()
    data = resp.json()
    if not data.get('requestSuccessful'):
        raise ValueError(f"Monnify auth failed: {data.get('responseMessage')}")
    return data['responseBody']['accessToken']


# ─────────────────────────────────────────────────────────────
# INITIALIZE TRANSACTION
# ─────────────────────────────────────────────────────────────

def initialize_transaction(
    amount: float,
    reference: str,
    customer_email: str,
    customer_name: str,
    description: str = "SwiftPOS Subscription",
    redirect_url: str = "",
) -> dict:
    """
    Create a Monnify payment link.
    Returns dict with keys: checkoutUrl, transactionReference, paymentReference
    Raises ValueError on failure.
    """
    token = _get_auth_token()
    url = f"{MONNIFY_BASE_URL}/api/v1/merchant/transactions/init-transaction"
    payload = {
        "amount": float(amount),
        "customerName": customer_name,
        "customerEmail": customer_email,
        "paymentReference": reference,
        "paymentDescription": description,
        "currencyCode": "NGN",
        "contractCode": MONNIFY_CONTRACT_CODE,
        "redirectUrl": redirect_url,
        "paymentMethods": ["CARD", "ACCOUNT_TRANSFER", "USSD", "PHONE_NUMBER"],
    }
    resp = requests.post(
        url,
        headers={
            "Authorization": f"Bearer {token}",
            "Content-Type": "application/json",
        },
        json=payload,
        timeout=20,
    )
    
    try:
        resp.raise_for_status()
    except requests.exceptions.HTTPError as e:
        error_msg = resp.text
        try:
            error_data = resp.json()
            if 'responseMessage' in error_data:
                error_msg = f"{error_data.get('responseMessage')} - {error_data.get('responseBody', '')}"
        except json.JSONDecodeError:
            pass
        raise ValueError(f"Monnify HTTP Error: {e}. Details: {error_msg}")

    data = resp.json()
    if not data.get('requestSuccessful'):
        raise ValueError(f"Monnify init failed: {data.get('responseMessage')}")
    return data['responseBody']


# ─────────────────────────────────────────────────────────────
# VERIFY TRANSACTION
# ─────────────────────────────────────────────────────────────

def verify_transaction(payment_reference: str) -> dict:
    """
    Verify a transaction by our internal payment reference.
    Returns the responseBody dict with paymentStatus etc.
    Raises ValueError on failure.
    """
    token = _get_auth_token()
    encoded_ref = requests.utils.quote(payment_reference, safe='')
    url = f"{MONNIFY_BASE_URL}/api/v1/merchant/transactions/query?paymentReference={encoded_ref}"
    resp = requests.get(
        url,
        headers={
            "Authorization": f"Bearer {token}",
            "Content-Type": "application/json",
        },
        timeout=15,
    )
    resp.raise_for_status()
    data = resp.json()
    if not data.get('requestSuccessful'):
        raise ValueError(f"Monnify verify failed: {data.get('responseMessage')}")
    return data['responseBody']


# ─────────────────────────────────────────────────────────────
# WEBHOOK SIGNATURE VALIDATION
# ─────────────────────────────────────────────────────────────

def validate_webhook_signature(raw_body: bytes, monnify_signature: str) -> bool:
    """
    Validate the Monnify webhook HMAC-SHA512 signature.
    Monnify sends 'monnify-signature' header.
    The hash is HMAC-SHA512(secret_key, raw_body).
    """
    if not monnify_signature or not MONNIFY_SECRET_KEY:
        return False
    try:
        computed = hmac.new(
            MONNIFY_SECRET_KEY.encode('utf-8'),
            raw_body,
            hashlib.sha512,
        ).hexdigest()
        return hmac.compare_digest(computed.lower(), monnify_signature.lower())
    except Exception as e:
        logger.error(f"Monnify signature validation error: {e}")
        return False
