import requests
import json
import base64
from datetime import datetime
from django.conf import settings
from django.utils import timezone
from settings.models import SystemSettings
import logging

logger = logging.getLogger(__name__)

class MpesaService:
    def __init__(self):
        self.settings = SystemSettings.get_mpesa_settings()
        self.consumer_key = self.settings.get('consumer_key', '')
        self.consumer_secret = self.settings.get('consumer_secret', '')
        self.business_short_code = self.settings.get('business_short_code', '')
        self.passkey = self.settings.get('passkey', '')
        self.environment = self.settings.get('environment', 'sandbox')

        # Set base URLs based on environment
        if self.environment == 'production':
            self.base_url = 'https://api.safaricom.co.ke'
        else:
            self.base_url = 'https://sandbox.safaricom.co.ke'

    def get_access_token(self):
        """Get OAuth access token"""
        try:
            url = f"{self.base_url}/oauth/v1/generate?grant_type=client_credentials"

            # Encode credentials
            credentials = f"{self.consumer_key}:{self.consumer_secret}"
            encoded_credentials = base64.b64encode(credentials.encode()).decode()

            headers = {
                'Authorization': f'Basic {encoded_credentials}',
                'Content-Type': 'application/json'
            }

            response = requests.get(url, headers=headers, timeout=30)

            if response.status_code == 200:
                result = response.json()
                return result.get('access_token')
            else:
                logger.error(f"Failed to get access token: {response.text}")
                return None

        except Exception as e:
            logger.error(f"Error getting access token: {str(e)}")
            return None

    def stk_push(self, phone_number, amount, account_reference, transaction_desc):
        """Initiate STK Push request"""
        try:
            access_token = self.get_access_token()
            if not access_token:
                return {'ResponseCode': '1', 'errorMessage': 'Failed to get access token'}

            # Format phone number
            if phone_number.startswith('0'):
                phone_number = '254' + phone_number[1:]
            elif phone_number.startswith('+254'):
                phone_number = phone_number[1:]
            elif not phone_number.startswith('254'):
                phone_number = '254' + phone_number

            # Generate timestamp
            timestamp = timezone.now().strftime('%Y%m%d%H%M%S')

            # Generate password
            password_string = f"{self.business_short_code}{self.passkey}{timestamp}"
            password = base64.b64encode(password_string.encode()).decode()

            # Callback URL - use the actual callback endpoint
            base_callback_url = self.settings.get('callback_url', 'https://system.optinet.co.ke')
            if base_callback_url.endswith('/'):
                base_callback_url = base_callback_url.rstrip('/')
            callback_url = f"{base_callback_url}/payments/stk-callback/"

            url = f"{self.base_url}/mpesa/stkpush/v1/processrequest"

            headers = {
                'Authorization': f'Bearer {access_token}',
                'Content-Type': 'application/json'
            }

            payload = {
                "BusinessShortCode": self.business_short_code,
                "Password": password,
                "Timestamp": timestamp,
                "TransactionType": "CustomerPayBillOnline",
                "Amount": amount,
                "PartyA": phone_number,
                "PartyB": self.business_short_code,
                "PhoneNumber": phone_number,
                "CallBackURL": callback_url,
                "AccountReference": account_reference,
                "TransactionDesc": transaction_desc
            }

            logger.info(f"STK Push payload: {json.dumps(payload, indent=2)}")

            response = requests.post(url, json=payload, headers=headers, timeout=30)
            result = response.json()

            logger.info(f"STK Push response: {json.dumps(result, indent=2)}")

            return result

        except Exception as e:
            logger.error(f"STK Push error: {str(e)}")
            return {'ResponseCode': '1', 'errorMessage': str(e)}