"""
Tests for M-Pesa IPN endpoint: signature validation, deduplication, missing secret.
"""
import json, hmac, hashlib, pytest
from unittest.mock import patch


class TestMpesaIPN:
    IPN_URL = '/api/mpesa/ipn'

    def _make_sig(self, body: bytes, secret: str) -> str:
        return hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()

    def test_ipn_rejected_without_secret_configured(self, client):
        """IPN must return 503 when MPESA_SECRET is not set."""
        with patch('app.MPESA_SECRET', ''):
            r = client.post(self.IPN_URL,
                            data=json.dumps({'TransID': 'X1', 'TransAmount': 100}),
                            content_type='application/json')
        assert r.status_code == 503

    def test_ipn_rejected_with_bad_signature(self, client):
        """IPN must return 401 when signature doesn't match."""
        with patch('app.MPESA_SECRET', 'correct_secret'):
            body = json.dumps({'TransID': 'ABC123', 'TransAmount': 50}).encode()
            r = client.post(self.IPN_URL,
                            data=body,
                            content_type='application/json',
                            headers={'X-Safaricom-Signature': 'badsignature'})
        assert r.status_code == 401

    def test_ipn_accepted_with_correct_signature(self, client):
        """IPN must accept and record a transaction with correct HMAC."""
        secret = 'test_mpesa_secret'
        body = json.dumps({
            'TransID': 'TESTREF001',
            'TransAmount': 250,
            'MSISDN': '254700000001',
            'BusinessShortCode': '174379'
        }).encode()
        sig = self._make_sig(body, secret)
        with patch('app.MPESA_SECRET', secret):
            r = client.post(self.IPN_URL,
                            data=body,
                            content_type='application/json',
                            headers={'X-Safaricom-Signature': sig})
        assert r.status_code == 200
        assert json.loads(r.data)['ResultCode'] == 0

    def test_ipn_deduplication(self, client):
        """Duplicate M-Pesa ref must be silently accepted without double-recording."""
        secret = 'test_mpesa_secret'
        body = json.dumps({
            'TransID': 'DUPREF999',
            'TransAmount': 100,
            'MSISDN': '254700000002',
        }).encode()
        sig = self._make_sig(body, secret)
        with patch('app.MPESA_SECRET', secret):
            r1 = client.post(self.IPN_URL, data=body, content_type='application/json',
                             headers={'X-Safaricom-Signature': sig})
            r2 = client.post(self.IPN_URL, data=body, content_type='application/json',
                             headers={'X-Safaricom-Signature': sig})
        assert r1.status_code == 200
        assert r2.status_code == 200   # duplicate accepted silently
