"""
Africa's Talking SMS Service
Mirrors the old PHP notifs/notifs.php integration.

Every outgoing SMS is logged to the SMSLog table so admins can review
all messages from the SMS Logs page.

Credentials from old system:
  username: Uzuriapps
  apiKey:   atsk_e810a145ccd3a1089769cd17887da70ae76124ff044fa0ab949429e6b388954e6db55009
"""

import logging
from django.conf import settings

logger = logging.getLogger(__name__)


def _get_sms_client():
    """Initialise and return the Africa's Talking SMS object."""
    import africastalking
    username = getattr(settings, 'AT_USERNAME', 'Uzuriapps')
    api_key  = getattr(settings, 'AT_API_KEY', '')
    africastalking.initialize(username, api_key)
    return africastalking.SMS


def _admin_numbers():
    """Return the list of admin notification numbers."""
    primary   = getattr(settings, 'COMPANY_PHONE_PRIMARY', '+254112941830')
    secondary = getattr(settings, 'COMPANY_PHONE_SECONDARY',
                        ['+254114457516', '+254115451752', '+254758587153'])
    return [primary] + list(secondary)


def _normalise_phone(phone):
    """Convert any Kenyan phone format to +2547xxxxxxxx."""
    phone = str(phone).strip()
    if phone.startswith('+'):
        return phone
    if phone.startswith('0'):
        return '+254' + phone[1:]
    if phone.startswith('254'):
        return '+' + phone
    return phone


def _log_sms(sms_type, recipients_list, message, sender_id,
             response, loan_number='', borrower_name='', amount=None):
    """Persist every outgoing SMS to SMSLog for admin review."""
    try:
        from payments.sasapay_models import SMSLog

        # Determine delivery status from AT response
        if 'error' in response:
            status = 'failed'
            error_msg = str(response['error'])
        else:
            recips = response.get('SMSMessageData', {}).get('Recipients', [])
            successes = sum(1 for r in recips if r.get('status') == 'Success')
            if successes == 0:
                status = 'failed'
            elif successes < len(recips):
                status = 'partial'
            else:
                status = 'sent'
            error_msg = ''

        SMSLog.objects.create(
            sms_type=sms_type,
            recipients=', '.join(recipients_list),
            message=message,
            sender_id=sender_id,
            status=status,
            at_response=response,
            error_message=error_msg,
            loan_number=loan_number or '',
            borrower_name=borrower_name or '',
            amount=amount,
        )
    except Exception as exc:
        # Never let logging break the SMS flow
        logger.warning(f"Could not save SMS log: {exc}")


def send_sms(recipients, message, sender_id=None,
             sms_type='other', loan_number='', borrower_name='', amount=None):
    """
    Send an SMS via Africa's Talking and log it.

    Args:
        recipients (str | list): Phone number(s) in E.164 or Kenyan format.
        message (str): The SMS body.
        sender_id (str): Alphanumeric sender ID (default: settings.SMS_SENDER_ID).
        sms_type (str): One of the SMS_TYPE_CHOICES keys for the log.
        loan_number (str): Optional loan number for context in the log.
        borrower_name (str): Optional borrower name for context in the log.
        amount (Decimal|float): Optional amount for context in the log.

    Returns:
        dict: The raw AT API response, or an error dict on failure.
    """
    if sender_id is None:
        sender_id = getattr(settings, 'SMS_SENDER_ID', 'HavGrazuri')

    # Normalise recipients to a list
    if isinstance(recipients, str):
        recipients = [r.strip() for r in recipients.split(',') if r.strip()]

    normalised = [_normalise_phone(p) for p in recipients]

    try:
        sms      = _get_sms_client()
        response = sms.send(message, normalised, sender_id)
        logger.info(f"SMS [{sms_type}] sent to {normalised}: {response}")
    except Exception as exc:
        logger.error(f"SMS send failed to {normalised}: {exc}")
        response = {'error': str(exc)}

    _log_sms(sms_type, normalised, message, sender_id,
             response, loan_number, borrower_name, amount)
    return response


# ---------------------------------------------------------------------------
# Convenience helpers — each maps to a specific notification event
# ---------------------------------------------------------------------------

def send_payment_confirmation_sms(borrower_name, amount, reference,
                                   loan_number, new_balance, customer_phone):
    """
    Payment confirmed — sent to all 4 admin numbers + the customer.
    Mirrors old PHP:
      "$reference Confirmed.KES $amount paid to HAVEN GRAZURI by $name on $time..."
    """
    from datetime import datetime
    pmt_time = datetime.now().strftime('%d/%m/%Y %H:%M:%S') + ' HRS'
    message = (
        f"{reference} Confirmed. KES {amount:,.2f} paid to HAVEN GRAZURI by "
        f"{borrower_name.upper()} on {pmt_time} for loan No {loan_number}. "
        f"New Loan Bal: KES {new_balance:,.2f}"
    )
    recipients = _admin_numbers() + [customer_phone]
    return send_sms(recipients, message,
                    sms_type='payment_confirmation',
                    loan_number=loan_number,
                    borrower_name=borrower_name,
                    amount=amount)


def send_unknown_payment_sms(full_name, bill_ref, amount, reference, customer_phone):
    """Unrecognised payment — notify admins + sender."""
    from datetime import datetime
    pmt_time = datetime.now().strftime('%d/%m/%Y %H:%M:%S') + ' HRS'
    details  = f"{full_name.upper()}({bill_ref})"
    message  = (
        f"{reference} Confirmed. KES {amount} unknown payment sent to HAVEN GRAZURI "
        f"by {details} on {pmt_time}. Thank you"
    )
    recipients = _admin_numbers() + [customer_phone]
    return send_sms(recipients, message,
                    sms_type='unknown_payment',
                    borrower_name=full_name,
                    amount=amount)


def send_loan_disbursement_sms(borrower_name, amount, loan_number, customer_phone):
    """Loan disbursed via SasaPay B2C — notify borrower + admins."""
    from datetime import datetime
    pmt_time = datetime.now().strftime('%d/%m/%Y %H:%M:%S') + ' HRS'
    message  = (
        f"Dear {borrower_name}, KES {amount:,.2f} has been disbursed to your M-Pesa "
        f"for loan {loan_number} on {pmt_time}. HAVEN GRAZURI."
    )
    recipients = _admin_numbers() + [customer_phone]
    return send_sms(recipients, message,
                    sms_type='loan_disbursement',
                    loan_number=loan_number,
                    borrower_name=borrower_name,
                    amount=amount)


def send_loan_approval_sms(borrower_name, amount, loan_number, customer_phone):
    """Loan approved — notify borrower only."""
    message = (
        f"Dear {borrower_name}, your loan application {loan_number} for "
        f"KES {amount:,.2f} has been APPROVED. Disbursement will follow shortly. "
        f"HAVEN GRAZURI."
    )
    return send_sms([customer_phone], message,
                    sms_type='loan_approval',
                    loan_number=loan_number,
                    borrower_name=borrower_name,
                    amount=amount)


def send_overdue_reminder_sms(borrower_name, overdue_amount, loan_number, customer_phone):
    """Overdue payment reminder — notify borrower only."""
    message = (
        f"Dear {borrower_name}, your loan {loan_number} has an overdue balance of "
        f"KES {overdue_amount:,.2f}. Please make payment to avoid penalties. "
        f"HAVEN GRAZURI."
    )
    return send_sms([customer_phone], message,
                    sms_type='overdue_reminder',
                    loan_number=loan_number,
                    borrower_name=borrower_name,
                    amount=overdue_amount)


def send_stk_push_initiated_sms(customer_phone, amount, loan_number):
    """STK push sent — notify borrower to check their phone."""
    message = (
        f"A payment request of KES {amount:,.2f} for loan {loan_number} has been "
        f"sent to {customer_phone}. Please check your phone and enter your M-Pesa PIN. "
        f"HAVEN GRAZURI."
    )
    return send_sms([customer_phone], message,
                    sms_type='stk_push',
                    loan_number=loan_number,
                    amount=amount)
