import requests
import base64
import datetime
import logging


class MpesaSTKPush:
    def __init__(self, shop):
        """
        Initialize STK Push class with shop-specific configurations.
        """
        self.shop = shop
        self.consumer_key = shop.mpesa_consumer_key
        self.consumer_secret = shop.mpesa_consumer_secret
        self.short_code = shop.mpesa_short_code
        self.passkey = shop.mpesa_passkey
        self.env = shop.mpesa_env
        self.base_url = (
            "https://sandbox.safaricom.co.ke"
            if self.env == "sandbox"
            else "https://api.safaricom.co.ke"
        )
        self.logger = logging.getLogger(__name__)

    def generate_access_token(self):
        """
        Generate the access token required for API authentication.
        Returns the token or raises an exception on failure.
        """
        url = f"{self.base_url}/oauth/v1/generate?grant_type=client_credentials"
        try:
            response = requests.get(url, auth=(self.consumer_key, self.consumer_secret))
            response.raise_for_status()
            access_token = response.json().get("access_token")
            if not access_token:
                raise ValueError("Access token missing in response")
            self.logger.info("Access token successfully generated")
            return access_token
        except requests.exceptions.RequestException as e:
            self.logger.error(f"Failed to generate access token: {e}")
            raise
        except ValueError as e:
            self.logger.error(f"Invalid response: {e}")
            raise

    def initiate_stk_push(self, phone_number, amount, account_reference):
        """
        Initiates the STK Push transaction.
        Returns the response or raises an exception on failure.
        """
        access_token = self.generate_access_token()
        timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
        password = base64.b64encode(
            f"{self.short_code}{self.passkey}{timestamp}".encode()
        ).decode()

        url = f"{self.base_url}/mpesa/stkpush/v1/processrequest"
        headers = {"Authorization": f"Bearer {access_token}"}
        payload = {
            "BusinessShortCode": self.short_code,
            "Password": password,
            "Timestamp": timestamp,
            "TransactionType": "CustomerPayBillOnline",
            "Amount": amount,
            "PartyA": phone_number,
            "PartyB": self.short_code,
            "PhoneNumber": phone_number,
            "CallBackURL": "https://hyperkenya.posapp.co.ke/shop/mpesa/callback/",
            "AccountReference": account_reference,
            "TransactionDesc": "Payment for Order",
        }

        try:
            response = requests.post(url, json=payload, headers=headers)
            response.raise_for_status()
            response_data = response.json()

            # Log the response for debugging purposes
            self.logger.info(f"STK Push response: {response_data}")

            # Safaricom's successful request check
            if response_data.get("ResponseCode") != "0":
                raise ValueError(f"STK Push request failed: {response_data}")

            return response_data
        except requests.exceptions.RequestException as e:
            self.logger.error(f"Failed to initiate STK Push: {e}")
            raise
        except ValueError as e:
            self.logger.error(f"Invalid response: {e}")
            raise
