"""WhatsApp (send2.digital) and SMS (leewayapi) senders — mirror the HRMS PHP
helpers. All config comes from settings/.env; nothing is hardcoded. Each function
returns (ok: bool, detail: str) and never raises.
"""
import json
import logging
import re
import urllib.parse
import urllib.request

from django.conf import settings

logger = logging.getLogger(__name__)


def _cfg(name: str, default: str = "") -> str:
    return getattr(settings, name, None) or default


def _digits(phone: str) -> str:
    d = re.sub(r"\D", "", phone or "")
    return d[-10:] if len(d) >= 10 else d


def send_whatsapp(phone: str, message: str, template_name: str = "", variables=None) -> tuple[bool, str]:
    """Send a WhatsApp message via send2.digital (template-based).

    GET {url}?user_name=..&password=..&template_name=..&number=..&variable=<vars>

    send2.digital fills the approved template's {#var#} slots from the `variable`
    param, which it splits by comma. So a template with N variables needs N
    comma-separated VALUES — NOT the fully rendered sentence (that would be
    mis-counted, e.g. "Variable count mismatch: Expected 3").

    Pass `variables` (an ordered list, e.g. [first_name, job_title, apply_link])
    for multi-variable templates. If omitted, the whole `message` is sent as a
    single variable (single-{#var#} templates / OTP).

    Override the param names via .env WHATSAPP_PHONE_PARAM / WHATSAPP_VAR_PARAM.
    """
    url = _cfg("WHATSAPP_API_URL")
    user = _cfg("WHATSAPP_API_USERNAME")
    pwd = _cfg("WHATSAPP_API_PASSWORD")
    tpl = template_name or _cfg("WHATSAPP_TEMPLATE_NAME")
    if not (url and user and pwd):
        return False, "WhatsApp gateway not configured (set WHATSAPP_API_URL / USERNAME / PASSWORD in backend/.env)."
    if not tpl:
        return False, "No WhatsApp template configured (set the template's provider template name)."

    phone_param = _cfg("WHATSAPP_PHONE_PARAM", "number")
    var_param = _cfg("WHATSAPP_VAR_PARAM", "variable")
    media_type = _cfg("WHATSAPP_MEDIA_TYPE", "text")
    # Build the variable value. Commas separate slots for send2.digital, so strip
    # commas out of each value to keep the slot count correct.
    if variables:
        var_value = ",".join(str(v or "").replace(",", " ").strip() for v in variables)
    else:
        var_value = str(message)
    # Match the HRMS PHP exactly: credentials/template are concatenated RAW (not
    # url-encoded), and only the number + variable values are url-encoded.
    q = urllib.parse.quote
    full = (
        f"{url}?user_name={user}&password={pwd}&template_name={tpl}"
        f"&{phone_param}={q(_digits(phone))}"
        f"&media_type={media_type}"
        f"&{var_param}={q(var_value)}"
    )
    try:
        with urllib.request.urlopen(full, timeout=20) as resp:
            body = resp.read().decode(errors="ignore")
    except Exception as e:  # noqa: BLE001
        logger.warning("WhatsApp send failed: %s", e)
        return False, f"WhatsApp gateway error: {e}"

    # Parse status from one or more JSON blocks (like the PHP helper).
    status = ""
    for block in re.findall(r"\{.*?\}", body, re.S):
        try:
            d = json.loads(block)
        except Exception:  # noqa: BLE001
            continue
        status = str(d.get("message_status") or d.get("status") or status).lower()
    if status in ("send", "sent", "accepted", "success"):
        return True, ""
    return False, f"WhatsApp not accepted (response: {body[:200]})"


def _otp_template(channel: str):
    """Return the active OTP template row for a channel, or None.

    Configured entirely from the Notification Templates master — no hardcoding.
    """
    try:
        from apps.notifications.models import NotificationTemplate
        return (
            NotificationTemplate.objects
            .filter(channel=channel, purpose="OTP", is_active=True)
            .order_by("-updated_at")
            .first()
        )
    except Exception:  # noqa: BLE001 — table may not exist yet during migrate
        return None


def _render_otp(body: str, otp: str) -> str:
    """Substitute the OTP placeholder ({{otp}} or {otp}) in a template body."""
    return (body or "").replace("{{otp}}", str(otp)).replace("{otp}", str(otp))


def send_sms_otp(phone: str, otp: str) -> tuple[bool, str]:
    """Send an OTP over SMS.

    Message text + DLT content-id come from the active SMS OTP template in the
    Notification Templates master (channel=SMS, purpose=OTP). Falls back to the
    .env SMS_OTP_TEMPLATE / SMS_OTP_CONTENT_ID only if no template is configured.
    """
    tpl = _otp_template("SMS")
    if tpl and tpl.body.strip():
        message = _render_otp(tpl.body, otp)
        content_id = tpl.provider_template_name or _cfg("SMS_OTP_CONTENT_ID")
    else:
        message = _render_otp(_cfg("SMS_OTP_TEMPLATE", "{otp} is your OTP."), otp)
        content_id = _cfg("SMS_OTP_CONTENT_ID")
    return send_sms(phone, message, content_id=content_id)


def send_whatsapp_otp(phone: str, otp: str) -> tuple[bool, str]:
    """Send an OTP over WhatsApp using the active WhatsApp OTP template
    (channel=WHATSAPP, purpose=OTP) from the master. Falls back to .env."""
    tpl = _otp_template("WHATSAPP")
    if tpl and tpl.body.strip():
        message = _render_otp(tpl.body, otp)
        template_name = tpl.provider_template_name or _cfg("WHATSAPP_TEMPLATE_NAME")
    else:
        message = str(otp)
        template_name = _cfg("WHATSAPP_TEMPLATE_NAME")
    return send_whatsapp(phone, message, template_name=template_name)


def send_sms(phone: str, message: str, content_id: str = "") -> tuple[bool, str]:
    """Send an SMS via leewayapi (DLT). Full URL scheme from the HRMS helper."""
    url = _cfg("SMS_API_URL")
    user = _cfg("SMS_USERNAME")
    pwd = _cfg("SMS_PASSWORD")
    if not (url and user and pwd):
        logger.info("==========================================")
        logger.info("[SMS GATEWAY CONSOLE FALLBACK]")
        logger.info("TO: %s | MESSAGE: %s", phone, message)
        logger.info("==========================================")
        print(f"\n[SMS OTP CONSOLE] Mobile: {phone} | Message: {message}\n", flush=True)
        return True, "SMS gateway not configured in backend/.env — OTP logged to console."

    params = {
        "username": user, "password": pwd, "mobile": _digits(phone),
        "message": message, "senderid": _cfg("SMS_SENDER_ID"),
        "peid": _cfg("SMS_PEID"), "contentid": content_id or _cfg("SMS_CONTENT_ID"),
        "tm_id": _cfg("SMS_TM_ID"),
    }
    full = f"{url}?{urllib.parse.urlencode(params)}"
    try:
        with urllib.request.urlopen(full, timeout=20) as resp:
            body = resp.read().decode(errors="ignore")
    except Exception as e:  # noqa: BLE001
        logger.warning("SMS send failed: %s", e)
        return False, f"SMS gateway error: {e}"

    # leewayapi returns comma-separated; 3rd part like "status:xxx" (per PHP helper).
    parts = body.split(",")
    status = ""
    if len(parts) >= 3 and ":" in parts[2]:
        status = parts[2].split(":")[1].strip().lower()
    if status in ("success", "submitted", "sent", "ok") or "success" in body.lower():
        return True, ""
    return False, f"SMS not accepted (response: {body[:200]})"
