<?php
// member-b2c-api.php
error_reporting(E_ALL);
ini_set('display_errors', 0);
ini_set('log_errors', 1);

require_once __DIR__ . '/includes/cors.php';
configureCors();
require_once __DIR__ . '/includes/config_loader.php';
require_once __DIR__ . '/includes/config.php';
require_once __DIR__ . '/includes/audit_helper.php';
require_once __DIR__ . '/email.php';
require_once __DIR__ . '/STKPushPaymentProcessor.php';
require_once __DIR__ . '/b2c/b2c_config.php';
// Include required files

//require_once './auth/middleware.php';

// Set timezone to Africa/Nairobi
date_default_timezone_set('Africa/Nairobi');

// Set content type
header('Content-Type: application/json; charset=UTF-8');

// Enhanced logging function for Member B2C
function logMemberB2CApiEvent($message, $level = 'INFO', $context = []) {
    $timestamp = date('Y-m-d H:i:s');
    $logMessage = "[$timestamp] [$level] $message";
    
    if (!empty($context)) {
        $logMessage .= " | Context: " . json_encode($context);
    }
    
    $logMessage .= PHP_EOL;
    
    // Ensure logs directory exists
    if (!is_dir('./logs')) {
        mkdir('./logs', 0755, true);
    }
    
    // Log to file
    error_log($logMessage, 3, './logs/member_b2c_api_debug.log');
    
    if ($level === 'ERROR') {
        error_log("MEMBER_B2C_API_ERROR: $message");
    }
}

function sendJsonResponse($success, $data = null, $error = null, $statusCode = 200) {
    http_response_code($statusCode);
    $response = ['success' => $success];
    if ($data !== null) $response['data'] = $data;
    if ($error !== null) $response['error'] = $error;
    echo json_encode($response);
    exit;
}

/**
 * Phone Number Formatter Class for B2C
 */
class MemberB2CPhoneNumberFormatter {
    public static function formatPhoneNumber($phone) {
        // Remove all non-digit characters including plus sign
        $phone = preg_replace('/[^0-9]/', '', $phone);
        
        // Handle different formats
        if (strlen($phone) === 9 && substr($phone, 0, 1) === '7') {
            // Format: 712345678 -> 254712345678
            return '254' . $phone;
        } elseif (strlen($phone) === 10 && substr($phone, 0, 1) === '0') {
            // Format: 0712345678 -> 254712345678
            return '254' . substr($phone, 1);
        } elseif (strlen($phone) === 12 && substr($phone, 0, 3) === '254') {
            // Format: 254712345678 -> 254712345678 (already correct)
            if (preg_match('/^2547\d{8}$/', $phone)) {
                return $phone;
            }
        } elseif (strlen($phone) === 13 && substr($phone, 0, 4) === '2547') {
            // Keep only first 12 characters
            return substr($phone, 0, 12);
        }
        
        // Try to extract valid number
        if (preg_match('/(7\d{8})/', $phone, $matches)) {
            // Found 9-digit number starting with 7
            return '254' . $matches[1];
        }
        
        // Return as is for validation to handle
        return $phone;
    }
    
    public static function validatePhoneNumber($phone) {
        $formatted = self::formatPhoneNumber($phone);
        return preg_match('/^2547\d{8}$/', $formatted);
    }
    
    public static function getDisplayFormat($phone) {
        $formatted = self::formatPhoneNumber($phone);
        
        // Convert to local format: 254712345678 -> 0712345678
        if (preg_match('/^2547(\d{8})$/', $formatted, $matches)) {
            return '0' . $matches[1];
        }
        
        // Try to extract display format from any phone
        $clean = preg_replace('/[^0-9]/', '', $phone);
        
        // Check for 2547XXXXXXXX format
        if (preg_match('/2547(\d{8})/', $clean, $matches)) {
            return '0' . $matches[1];
        }
        
        // Check for 7XXXXXXXX format (9 digits)
        if (preg_match('/7\d{8}/', $clean, $matches)) {
            return '0' . $matches[0];
        }
        
        // Check for 0XXXXXXXXX format (10 digits)
        if (preg_match('/0\d{9}/', $clean, $matches)) {
            return $matches[0];
        }
        
        // If not in standard format, return cleaned version
        return $clean;
    }
    
    public static function cleanPhoneForInput($phone) {
        // Remove all non-digit characters
        $clean = preg_replace('/[^0-9]/', '', $phone);
        
        // If starts with 2547, remove 2547 prefix
        if (substr($clean, 0, 4) === '2547') {
            return substr($clean, 4);
        }
        
        // If starts with 254, remove 254 prefix
        if (substr($clean, 0, 3) === '254') {
            return substr($clean, 3);
        }
        
        // If starts with 0, remove 0 prefix
        if (substr($clean, 0, 1) === '0') {
            return substr($clean, 1);
        }
        
        // Return as is (should be 9 digits starting with 7)
        return $clean;
    }
}

/**
 * B2C M-Pesa Integration Class
 */
class MemberB2CMpesaIntegration {
    private $consumerKey;
    private $consumerSecret;
    private $env;
    private $baseUrl;
    private $initiatorName;
    private $securityCredential;
    private $shortCode;
    private $commandId;
    private $resultUrl;
    private $queueTimeoutUrl;
    private $configValid = false;
    
    public function __construct() {
        // Use B2C config constants
        $this->consumerKey = B2C_MPESA_CONSUMER_KEY;
        $this->consumerSecret = B2C_MPESA_CONSUMER_SECRET;
        $this->env = B2C_MPESA_ENVIRONMENT;
        $this->shortCode = B2C_MPESA_SHORTCODE;
        $this->initiatorName = B2C_MPESA_INITIATOR_NAME;
        $this->commandId = B2C_MPESA_COMMAND_ID;
        $this->resultUrl = B2C_MPESA_RESULT_URL;
        $this->queueTimeoutUrl = B2C_MPESA_TIMEOUT_URL;
        
        $this->baseUrl = $this->env === 'sandbox' 
            ? 'https://sandbox.safaricom.co.ke' 
            : 'https://api.safaricom.co.ke';
        
        // Validate configuration
        $this->validateConfig();
        
        if ($this->configValid) {
            $this->securityCredential = $this->generateSecurityCredential();
        }
    }
    
    private function validateConfig() {
        $required = [
            'consumerKey' => $this->consumerKey,
            'consumerSecret' => $this->consumerSecret,
            'shortCode' => $this->shortCode,
            'initiatorName' => $this->initiatorName,
            'initiatorPassword' => B2C_MPESA_INITIATOR_PASSWORD,
            'commandId' => $this->commandId
        ];
        
        $missing = [];
        foreach ($required as $key => $value) {
            if (empty($value)) {
                $missing[] = $key;
            }
        }
        
        if (!empty($missing)) {
            logMemberB2CApiEvent('Missing required B2C configuration', 'ERROR', ['missing' => $missing]);
            $this->configValid = false;
            return;
        }
        
        $this->configValid = true;
    }
    
    public function isConfigValid() {
        return $this->configValid;
    }
    
    public function getConfigStatus() {
        return [
            'valid' => $this->configValid,
            'environment' => $this->env,
            'shortCode' => $this->shortCode,
            'initiatorName' => $this->initiatorName,
            'commandId' => $this->commandId
        ];
    }
    
    private function generateSecurityCredential() {
        $initiatorPassword = B2C_MPESA_INITIATOR_PASSWORD;
        
        $certPath = $this->env === 'sandbox'
    ? dirname(__DIR__) . '/backend-main/b2c/SandboxCertificate.cer'
    : dirname(__DIR__) . '/backend-main/b2c/production_cert.cer';

        
        if (!file_exists($certPath)) {
            throw new Exception("Certificate file not found: " . $certPath);
        }
        
        $publicKey = file_get_contents($certPath);
        if (!$publicKey) {
            throw new Exception("Failed to read certificate file");
        }
        
        $encrypted = '';
        $success = openssl_public_encrypt($initiatorPassword, $encrypted, $publicKey, OPENSSL_PKCS1_PADDING);
        
        if (!$success) {
            $error = openssl_error_string();
            throw new Exception("Failed to encrypt security credential: " . $error);
        }
        
        return base64_encode($encrypted);
    }

    private function getAccessToken() {
        $url = $this->baseUrl . '/oauth/v1/generate?grant_type=client_credentials';
        $credentials = base64_encode($this->consumerKey . ':' . $this->consumerSecret);
        
        $headers = ['Authorization: Basic ' . $credentials];

        $curl = curl_init();
        curl_setopt_array($curl, [
            CURLOPT_URL => $url,
            CURLOPT_HTTPHEADER => $headers,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HEADER => false,
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_SSL_VERIFYHOST => 2,
            CURLOPT_TIMEOUT => 30
        ]);

        $response = curl_exec($curl);
        $status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
        $error = curl_error($curl);
        curl_close($curl);

        if ($status != 200) {
            throw new Exception('Failed to get access token. Status: ' . $status . ' Error: ' . $error);
        }

        $result = json_decode($response);
        if (!$result || !isset($result->access_token)) {
            throw new Exception('Invalid response from access token request: ' . $response);
        }
        
        return $result->access_token;
    }

    public function b2cPayment($phoneNumber, $amount, $remarks) {
        if (!$this->configValid) {
            throw new Exception("B2C configuration is not valid.");
        }
        
        $payload = [
            'InitiatorName' => $this->initiatorName,
            'SecurityCredential' => $this->securityCredential,
            'CommandID' => $this->commandId,
            'Amount' => $amount,
            'PartyA' => $this->shortCode,
            'PartyB' => $phoneNumber,
            'Remarks' => $remarks,
            'QueueTimeOutURL' => $this->queueTimeoutUrl,
            'ResultURL' => $this->resultUrl,
            'Occasion' => 'Member Withdrawal'
        ];

        $url = $this->baseUrl . '/mpesa/b2c/v1/paymentrequest';
        $response = $this->makeApiRequest($url, $payload);
        
        return [
            'ConversationID' => $response['ConversationID'] ?? '',
            'OriginatorConversationID' => $response['OriginatorConversationID'] ?? '',
            'ResponseCode' => $response['ResponseCode'] ?? '0',
            'ResponseDescription' => $response['ResponseDescription'] ?? 'Success. Request accepted for processing'
        ];
    }

    private function makeApiRequest($url, $payload) {
        $token = $this->getAccessToken();
        $headers = [
            'Authorization: Bearer ' . $token,
            'Content-Type: ' . 'application/json'
        ];

        $curl = curl_init();
        curl_setopt_array($curl, [
            CURLOPT_URL => $url,
            CURLOPT_HTTPHEADER => $headers,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => json_encode($payload),
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_SSL_VERIFYHOST => 2,
            CURLOPT_TIMEOUT => 30
        ]);

        $response = curl_exec($curl);
        $status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
        $error = curl_error($curl);
        curl_close($curl);

        if ($status != 200) {
            throw new Exception('B2C API request failed. Status: ' . $status . ' Error: ' . $error);
        }

        $result = json_decode($response, true);
        if (!$result) {
            throw new Exception('Invalid JSON response from B2C API: ' . $response);
        }

        return $result;
    }
}

/**
 * Database Wrapper Class
 */
class Database {
    private $pdo;

    public function __construct($pdo) {
        $this->pdo = $pdo;
    }

    public function fetchAll($sql, $params = []) {
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute($params);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    public function fetchOne($sql, $params = []) {
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute($params);
        return $stmt->fetch(PDO::FETCH_ASSOC);
    }

    public function execute($sql, $params = []) {
        $stmt = $this->pdo->prepare($sql);
        return $stmt->execute($params);
    }

    public function beginTransaction() {
        return $this->pdo->beginTransaction();
    }

    public function commit() {
        return $this->pdo->commit();
    }

    public function rollBack() {
        return $this->pdo->rollBack();
    }

    public function lastInsertId() {
        return $this->pdo->lastInsertId();
    }
    
    public function getPdo() {
        return $this->pdo;
    }
}

/**
 * Member B2C Transaction Handler
 */
class MemberB2CTransactionHandler {
    private $db;

    public function __construct(Database $db) {
        $this->db = $db;
    }

    public function fetchMemberDetails($memberId) {
        return $this->db->fetchOne("SELECT * FROM members WHERE id = ?", [$memberId]);
    }

    public function fetchMemberWithdrawalAccounts($memberId) {
        return $this->db->fetchAll("
            SELECT at.id, at.account_name, at.type_code,
                   ma.available_balance, ma.reserved_balance, ma.running_balance,
                   (ma.available_balance - COALESCE(ma.reserved_balance, 0)) as net_available_balance,
                   at.allow_withdrawals
            FROM account_types at
            INNER JOIN member_accounts ma ON at.id = ma.account_type_id
            WHERE ma.member_id = ? 
            AND at.status = 1
            AND at.allow_withdrawals = 1
            AND ma.sub_account_code=1
            ORDER BY at.account_name
        ", [$memberId]);
    }

    public function getMemberBalanceInfo($memberId, $accountTypeId) {
        return $this->db->fetchOne("
            SELECT 
                available_balance,
                COALESCE(reserved_balance, 0) as reserved_balance,
                running_balance,
                (available_balance - COALESCE(reserved_balance, 0)) as net_available_balance
            FROM member_accounts 
            WHERE member_id = ? AND account_type_id = ?
        ", [$memberId, $accountTypeId]);
    }

    public function reserveFunds($memberId, $accountTypeId, $amount) {
        $this->db->beginTransaction();
        
        try {
            // Check and reserve funds
            $stmt = $this->db->getPdo()->prepare(
                "UPDATE member_accounts 
                 SET reserved_balance = COALESCE(reserved_balance, 0) + ?,
                     updated_at = NOW()
                 WHERE member_id = ? AND account_type_id = ? 
                 AND available_balance >= ?"
            );
            
            $result = $stmt->execute([$amount, $memberId, $accountTypeId, $amount]);
            $affectedRows = $stmt->rowCount();
            
            if ($affectedRows === 0) {
                $this->db->rollBack();
                $balance = $this->getMemberBalanceInfo($memberId, $accountTypeId);
                throw new Exception("Insufficient available balance. Available: KES " . number_format($balance['net_available_balance'] ?? 0, 2));
            }

            // Log the reservation
            $this->db->execute(
                "INSERT INTO fund_reservations (member_id, account_type_id, amount, reserved_by, created_at, initiated_by_member) 
                 VALUES (?, ?, ?, ?, NOW(), 1)",
                [$memberId, $accountTypeId, $amount, $memberId]
            );

            $this->db->commit();
            return true;
            
        } catch (Exception $e) {
            $this->db->rollBack();
            throw $e;
        }
    }

    public function recordMemberB2CTransaction($data) {
        $this->db->execute(
            "INSERT INTO b2c_transactions (
                conversation_id,
                originator_conversation_id,
                command_id,
                amount,
                phone_number,
                remarks,
                transaction_status,
                initiator_id,
                member_id,
                account_type_id,
                asset_ledger_id,
                response_code,
                response_description,
                initiated_by_member,
                created_at
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())",
            [
                $data['conversation_id'],
                $data['originator_conversation_id'],
                $data['command_id'],
                $data['amount'],
                $data['phone_number'],
                $data['remarks'],
                'pending',
                $data['initiator_id'],
                $data['member_id'] ?? null,
                $data['account_type_id'] ?? null,
                B2C_MPESA_LEDGER_ID,
                $data['response_code'] ?? '',
                $data['response_description'] ?? '',
                1 // Flag indicating member-initiated transaction
            ]
        );
        return $this->db->lastInsertId();
    }

    public function fetchMemberB2CTransactions($memberId, $filters = []) {
        $page = max(1, intval($filters['page'] ?? 1));
        $limit = min(100, max(1, intval($filters['limit'] ?? 10)));
        $offset = ($page - 1) * $limit;
        
        $status = $filters['status'] ?? '';
        $accountTypeId = $filters['account_type_id'] ?? '';
        $startDate = $filters['start_date'] ?? '';
        $endDate = $filters['end_date'] ?? '';
        
        // Build query with filters
        $query = "
            SELECT bt.*, at.account_name,
                   CASE 
                     WHEN bt.transaction_status = 'completed' THEN 'Completed'
                     WHEN bt.transaction_status = 'pending' THEN 'Pending'
                     WHEN bt.transaction_status = 'failed' THEN 'Failed'
                     ELSE bt.transaction_status
                   END as display_status
            FROM b2c_transactions bt
            LEFT JOIN account_types at ON bt.account_type_id = at.id
            WHERE bt.member_id = ?
        ";
        
        $params = [$memberId];
        
        if ($status) {
            $query .= " AND bt.transaction_status = ?";
            $params[] = $status;
        }
        
        if ($accountTypeId) {
            $query .= " AND bt.account_type_id = ?";
            $params[] = $accountTypeId;
        }
        
        if ($startDate) {
            $query .= " AND DATE(bt.created_at) >= ?";
            $params[] = $startDate;
        }
        
        if ($endDate) {
            $query .= " AND DATE(bt.created_at) <= ?";
            $params[] = $endDate;
        }
        
        $limit  = (int) $limit;
        $offset = (int) $offset;

        $query .= " ORDER BY bt.created_at DESC LIMIT $limit OFFSET $offset";

        
        $transactions = $this->db->fetchAll($query, $params);
        
        // Format phone numbers for display
        foreach ($transactions as &$transaction) {
            if (!empty($transaction['phone_number'])) {
                $transaction['display_phone'] = MemberB2CPhoneNumberFormatter::getDisplayFormat($transaction['phone_number']);
            }
            
            // Format date
            if (!empty($transaction['created_at'])) {
                $date = new DateTime($transaction['created_at']);
                $transaction['formatted_date'] = $date->format('d M Y H:i');
            }
        }
        
        // Get total count for pagination
        $countQuery = "SELECT COUNT(*) as total FROM b2c_transactions bt WHERE bt.member_id = ?";
        $countParams = [$memberId];
        
        if ($status) {
            $countQuery .= " AND bt.transaction_status = ?";
            $countParams[] = $status;
        }
        
        if ($accountTypeId) {
            $countQuery .= " AND bt.account_type_id = ?";
            $countParams[] = $accountTypeId;
        }
        
        if ($startDate) {
            $countQuery .= " AND DATE(bt.created_at) >= ?";
            $countParams[] = $startDate;
        }
        
        if ($endDate) {
            $countQuery .= " AND DATE(bt.created_at) <= ?";
            $countParams[] = $endDate;
        }
        
        $totalResult = $this->db->fetchOne($countQuery, $countParams);
        $total = $totalResult['total'] ?? 0;
        
        return [
            'transactions' => $transactions,
            'pagination' => [
                'page' => $page,
                'limit' => $limit,
                'total' => $total,
                'pages' => ceil($total / $limit)
            ]
        ];
    }

    public function getMemberB2CStats($memberId) {
        $stats = [];
        
        // Total completed
        $result = $this->db->fetchOne(
            "SELECT COALESCE(SUM(amount), 0) as total 
             FROM b2c_transactions 
             WHERE member_id = ? AND transaction_status = 'completed'",
            [$memberId]
        );
        $stats['total_completed'] = $result['total'] ?? 0;
        
        // Count by status
        $statuses = ['completed', 'pending', 'failed'];
        foreach ($statuses as $status) {
            $result = $this->db->fetchOne(
                "SELECT COUNT(*) as count, COALESCE(SUM(amount), 0) as total 
                 FROM b2c_transactions 
                 WHERE member_id = ? AND transaction_status = ?",
                [$memberId, $status]
            );
            $stats[$status] = $result ?? ['count' => 0, 'total' => 0];
        }
        
        // Recent activity
        $recent = $this->db->fetchAll(
            "SELECT bt.*, at.account_name 
             FROM b2c_transactions bt
             LEFT JOIN account_types at ON bt.account_type_id = at.id
             WHERE bt.member_id = ? 
             ORDER BY bt.created_at DESC 
             LIMIT 5",
            [$memberId]
        );
        
        // Format recent transactions
        foreach ($recent as &$tx) {
            if (!empty($tx['phone_number'])) {
                $tx['display_phone'] = MemberB2CPhoneNumberFormatter::getDisplayFormat($tx['phone_number']);
            }
            if (!empty($tx['created_at'])) {
                $date = new DateTime($tx['created_at']);
                $tx['formatted_date'] = $date->format('d M H:i');
            }
        }
        
        $stats['recent_activity'] = $recent;
        
        return $stats;
    }

    public function getAccountTypeName($accountTypeId) {
        $result = $this->db->fetchOne(
            "SELECT account_name FROM account_types WHERE id = ?", 
            [$accountTypeId]
        );
        return $result ? $result['account_name'] : null;
    }

    public function getMemberPhoneNumber($memberId) {
        $member = $this->fetchMemberDetails($memberId);
        if ($member && !empty($member['phone_number'])) {
            return MemberB2CPhoneNumberFormatter::getDisplayFormat($member['phone_number']);
        }
        return '';
    }

    public function getWithdrawalLimits() {
        return [
            'minimum' => 10,
            'maximum' => 150000,
            'daily_limit' => 300000
        ];
    }

    public function processSuccessfulB2C($conversationId, $mpesaReceipt = null) {
        $this->db->beginTransaction();
        
        try {
            // Get the transaction details
            $transaction = $this->db->fetchOne(
                "SELECT * FROM b2c_transactions 
                 WHERE conversation_id = ? AND transaction_status = 'pending'",
                [$conversationId]
            );
            
            if (!$transaction) {
                throw new Exception("Pending transaction not found");
            }

            // Move from reserved balance and reduce available balance
            $this->db->execute(
                "UPDATE member_accounts 
                 SET reserved_balance = reserved_balance - ?,
                     available_balance = available_balance - ?,
                     running_balance = running_balance - ?,
                     updated_at = NOW()
                 WHERE member_id = ? AND account_type_id = ?",
                [
                    $transaction['amount'], 
                    $transaction['amount'],
                    $transaction['amount'],
                    $transaction['member_id'], 
                    $transaction['account_type_id']
                ]
            );

            // Update transaction status
            $this->db->execute(
                "UPDATE b2c_transactions 
                 SET transaction_status = 'completed',
                     mpesa_receipt_number = ?,
                     result_description = 'Payment completed successfully',
                     completed_at = NOW()
                 WHERE conversation_id = ?",
                [$mpesaReceipt, $conversationId]
            );

            // Remove reservation record
            $this->db->execute(
                "UPDATE fund_reservations 
                 SET released_at = NOW(), status = 'completed'
                 WHERE member_id = ? AND account_type_id = ? 
                 AND amount = ? AND released_at IS NULL
                 ORDER BY created_at DESC LIMIT 1",
                [$transaction['member_id'], $transaction['account_type_id'], $transaction['amount']]
            );

            $this->db->commit();
            return true;
            
        } catch (Exception $e) {
            $this->db->rollBack();
            throw $e;
        }
    }

    public function processFailedB2C($conversationId, $errorDescription) {
        $this->db->beginTransaction();
        
        try {
            // Get the transaction details
            $transaction = $this->db->fetchOne(
                "SELECT * FROM b2c_transactions 
                 WHERE conversation_id = ? AND transaction_status = 'pending'",
                [$conversationId]
            );
            
            if (!$transaction) {
                throw new Exception("Pending transaction not found");
            }

            // Release reserved funds
            $this->db->execute(
                "UPDATE member_accounts 
                 SET reserved_balance = reserved_balance - ?,
                     updated_at = NOW()
                 WHERE member_id = ? AND account_type_id = ?",
                [$transaction['amount'], $transaction['member_id'], $transaction['account_type_id']]
            );

            // Update transaction status
            $this->db->execute(
                "UPDATE b2c_transactions 
                 SET transaction_status = 'failed',
                     result_description = ?,
                     completed_at = NOW()
                 WHERE conversation_id = ?",
                [$errorDescription, $conversationId]
            );

            // Mark reservation as released
            $this->db->execute(
                "UPDATE fund_reservations 
                 SET released_at = NOW(), status = 'failed', notes = ?
                 WHERE member_id = ? AND account_type_id = ? 
                 AND amount = ? AND released_at IS NULL
                 ORDER BY created_at DESC LIMIT 1",
                [$errorDescription, $transaction['member_id'], $transaction['account_type_id'], $transaction['amount']]
            );

            $this->db->commit();
            return true;
            
        } catch (Exception $e) {
            $this->db->rollBack();
            throw $e;
        }
    }
}

// Main API Logic
try {
    // Check database connection
    if (!$pdo) {
        throw new Exception('Database connection failed');
    }

    // Check if user is logged in and is a member
    if (!isset($_SESSION['member_id'])) {
        sendJsonResponse(false, null, 'Authentication required. Please login to access withdrawal services.', 401);
    }

    $memberId = $_SESSION['member_id'];
    
    // Initialize classes
    $db = new Database($pdo);
    $memberB2CHandler = new MemberB2CTransactionHandler($db);

    // Initialize B2C M-Pesa integration
    try {
        $b2cMpesa = new MemberB2CMpesaIntegration();
        $b2cInitialized = $b2cMpesa->isConfigValid();
        $configStatus = $b2cMpesa->getConfigStatus();
        
    } catch (Exception $e) {
        logMemberB2CApiEvent('Failed to initialize B2CMpesaIntegration', 'ERROR', ['error' => $e->getMessage()]);
        $b2cInitialized = false;
        $b2cError = $e->getMessage();
    }

    $method = $_SERVER['REQUEST_METHOD'];

    switch ($method) {
        // GET — fetch member's B2C data
        case 'GET':
            $action = $_GET['action'] ?? '';
            
            if ($action === 'get_member_phone') {
                // Get member's own phone number
                $displayPhone = $memberB2CHandler->getMemberPhoneNumber($memberId);
                sendJsonResponse(true, ['phone' => $displayPhone]);
                
            } elseif ($action === 'get_withdrawal_accounts') {
                // Get member's withdrawal accounts
                $accounts = $memberB2CHandler->fetchMemberWithdrawalAccounts($memberId);
                sendJsonResponse(true, ['accounts' => $accounts]);
                
            } elseif ($action === 'get_account_balance') {
                // Get specific account balance
                $accountTypeId = $_GET['account_type_id'] ?? '';
                
                if (empty($accountTypeId)) {
                    sendJsonResponse(false, null, 'Account Type ID is required');
                }
                
                $balanceInfo = $memberB2CHandler->getMemberBalanceInfo($memberId, $accountTypeId);
                if ($balanceInfo) {
                    sendJsonResponse(true, $balanceInfo);
                } else {
                    sendJsonResponse(true, [
                        'available_balance' => 0,
                        'reserved_balance' => 0,
                        'net_available_balance' => 0,
                        'running_balance' => 0
                    ]);
                }
                
            } elseif ($action === 'get_transactions') {
                // Get member's B2C transactions
                $filters = [
                    'page' => $_GET['page'] ?? 1,
                    'limit' => $_GET['limit'] ?? 10,
                    'status' => $_GET['status'] ?? '',
                    'account_type_id' => $_GET['account_type_id'] ?? '',
                    'start_date' => $_GET['start_date'] ?? '',
                    'end_date' => $_GET['end_date'] ?? ''
                ];
                
                $transactions = $memberB2CHandler->fetchMemberB2CTransactions($memberId, $filters);
                sendJsonResponse(true, $transactions);
                
            } elseif ($action === 'get_stats') {
                // Get member's B2C statistics
                $stats = $memberB2CHandler->getMemberB2CStats($memberId);
                sendJsonResponse(true, ['stats' => $stats]);
                
            } elseif ($action === 'get_limits') {
                // Get withdrawal limits
                $limits = $memberB2CHandler->getWithdrawalLimits();
                sendJsonResponse(true, ['limits' => $limits]);
                
            } else {
                // Fetch all data for member dashboard
                logMemberB2CApiEvent('Fetching member B2C data', 'INFO', [
                    'member_id' => $memberId,
                    'timezone' => date_default_timezone_get()
                ]);
                
                try {
                    // Fetch member details
                    $member = $memberB2CHandler->fetchMemberDetails($memberId);
                    
                    // Format member phone for display
                    if ($member && !empty($member['phone_number'])) {
                        $member['display_phone'] = MemberB2CPhoneNumberFormatter::getDisplayFormat($member['phone_number']);
                    }
                    
                    // Fetch withdrawal accounts
                    $accounts = $memberB2CHandler->fetchMemberWithdrawalAccounts($memberId);
                    
                    // Fetch recent transactions
                    $transactions = $memberB2CHandler->fetchMemberB2CTransactions($memberId, ['limit' => 5]);
                    
                    // Fetch statistics
                    $stats = $memberB2CHandler->getMemberB2CStats($memberId);
                    
                    // Get limits
                    $limits = $memberB2CHandler->getWithdrawalLimits();
                    
                    sendJsonResponse(true, [
                        'member' => $member,
                        'accounts' => $accounts,
                        'recent_transactions' => $transactions['transactions'] ?? [],
                        'stats' => $stats,
                        'limits' => $limits,
                        'config' => [
                            'initialized' => $b2cInitialized,
                            'environment' => B2C_MPESA_ENVIRONMENT,
                            'shortCode' => B2C_MPESA_SHORTCODE,
                            'error' => $b2cError ?? null
                        ],
                        'timezone' => date_default_timezone_get(),
                        'generated_at' => date('Y-m-d H:i:s')
                    ]);
                    
                } catch (Exception $e) {
                    throw new Exception("Error fetching member B2C data: " . $e->getMessage());
                }
            }
            break;
            
        // POST — process B2C withdrawals (member-initiated)
        case 'POST':
            // Parse JSON input
            $input = json_decode(file_get_contents('php://input'), true);
            if ($input === null && json_last_error() !== JSON_ERROR_NONE) {
                $input = $_POST;
            }
            
            $action = $input['action'] ?? '';
            
            if ($action === 'b2c_withdrawal') {
                logMemberB2CApiEvent('Member B2C withdrawal request received', 'INFO', [
                    'member_id' => $memberId,
                    'timezone' => date_default_timezone_get()
                ]);
                
                try {
                    // Validate required fields
                    $required = ['account_type_id', 'amount'];
                    foreach ($required as $field) {
                        if (empty($input[$field])) {
                            throw new Exception("$field is required");
                        }
                    }
                    
                    $amount = filter_var($input['amount'], FILTER_VALIDATE_FLOAT);
                    if ($amount === false || $amount <= 0) {
                        throw new Exception("Invalid amount");
                    }
                    
                    // Validate B2C amount limits
                    $limits = $memberB2CHandler->getWithdrawalLimits();
                    if ($amount < $limits['minimum']) {
                        throw new Exception("Minimum withdrawal amount is KES " . number_format($limits['minimum'], 2));
                    }
                    if ($amount > $limits['maximum']) {
                        throw new Exception("Maximum withdrawal amount is KES " . number_format($limits['maximum'], 2));
                    }
                    
                    // Get member details
                    $member = $memberB2CHandler->fetchMemberDetails($memberId);
                    if (!$member) {
                        throw new Exception("Member not found");
                    }
                    
                    // Use member's phone number or provided phone
                    $phone = $input['phone'] ?? $member['phone_number'];
                    if (empty($phone)) {
                        throw new Exception("Phone number is required. Please update your profile or provide a phone number.");
                    }
                    
                    if (!MemberB2CPhoneNumberFormatter::validatePhoneNumber($phone)) {
                        throw new Exception("Invalid phone number format. Use formats like: 0727576400, 254727576400, +254727576400, or 727576400");
                    }
                    
                    $formattedPhone = MemberB2CPhoneNumberFormatter::formatPhoneNumber($phone);
                    
                    // Verify account access and get account name
                    $accounts = $memberB2CHandler->fetchMemberWithdrawalAccounts($memberId);
                    $accountTypeId = $input['account_type_id'];
                    $account = null;
                    
                    foreach ($accounts as $acc) {
                        if ($acc['id'] == $accountTypeId) {
                            $account = $acc;
                            break;
                        }
                    }
                    
                    if (!$account) {
                        throw new Exception("Account not found or you don't have access to this account");
                    }
                    
                    // Check if member has sufficient balance
                    if ($amount > $account['net_available_balance']) {
                        throw new Exception("Insufficient available balance. Available: KES " . number_format($account['net_available_balance'], 2));
                    }
                    
                    // Check if B2C M-Pesa was initialized
                    if (!$b2cInitialized || !isset($b2cMpesa)) {
                        throw new Exception("Withdrawal service is not available. Please try again later.");
                    }
                    
                    // Reserve funds first
                    $memberB2CHandler->reserveFunds($memberId, $accountTypeId, $amount);
                    
                    // Create remarks
                    $remarks = $input['remarks'] ?? "Withdrawal from " . $account['account_name'];
                    
                    // Make B2C payment request
                    $response = $b2cMpesa->b2cPayment($formattedPhone, $amount, $remarks);
                    
                    // Record B2C transaction in database with member-initiated flag
                    $transactionId = $memberB2CHandler->recordMemberB2CTransaction([
                        'conversation_id' => $response['ConversationID'] ?? '',
                        'originator_conversation_id' => $response['OriginatorConversationID'] ?? '',
                        'command_id' => B2C_MPESA_COMMAND_ID,
                        'amount' => $amount,
                        'phone_number' => $formattedPhone,
                        'remarks' => $remarks,
                        'initiator_id' => $memberId,
                        'member_id' => $memberId,
                        'account_type_id' => $accountTypeId,
                        'response_code' => $response['ResponseCode'] ?? '',
                        'response_description' => $response['ResponseDescription'] ?? ''
                    ]);
                    
                    // Log successful transaction initiation
                    logMemberB2CApiEvent('Member B2C withdrawal initiated successfully', 'INFO', [
                        'member_id' => $memberId,
                        'amount' => $amount,
                        'phone' => $formattedPhone,
                        'account' => $account['account_name'],
                        'transaction_id' => $transactionId
                    ]);
                    
                    // Send SMS notification to member
                    if (!empty($member['phone_number'])) {
                        try {
                            $smsMessage = "Hello " . $member['first_name'] . ", your withdrawal of KES " . number_format($amount, 2) . " from " . $account['account_name'] . " has been initiated. You will receive confirmation shortly.";
                            // Uncomment if SMS helper is configured
                            // sendSMS($member['phone_number'], $smsMessage);
                        } catch (Exception $smsError) {
                            logMemberB2CApiEvent('SMS notification failed', 'WARNING', ['error' => $smsError->getMessage()]);
                        }
                    }
                    
                    sendJsonResponse(true, [
                        'message' => 'Withdrawal request initiated successfully. You will receive an M-Pesa confirmation shortly.',
                        'conversation_id' => $response['ConversationID'] ?? '',
                        'originator_conversation_id' => $response['OriginatorConversationID'] ?? '',
                        'response_description' => $response['ResponseDescription'] ?? 'Success. Request accepted for processing',
                        'transaction_id' => $transactionId,
                        'amount' => $amount,
                        'phone' => MemberB2CPhoneNumberFormatter::getDisplayFormat($formattedPhone),
                        'account_name' => $account['account_name'],
                        'member_name' => $member['first_name'] . ' ' . $member['last_name']
                    ]);
                    
                } catch (Exception $e) {
                    logMemberB2CApiEvent('Member B2C withdrawal Error', 'ERROR', [
                        'error' => $e->getMessage(),
                        'member_id' => $memberId
                    ]);
                    
                    sendJsonResponse(false, null, $e->getMessage(), 400);
                }
                
            } elseif ($action === 'callback') {
                // Handle B2C callback - no authentication required for callbacks
                $callbackData = $input;
                
                try {
                    logMemberB2CApiEvent('B2C Callback received', 'INFO', $callbackData);
                    
                    // Process based on result code
                    if (isset($callbackData['Result'])) {
                        $result = $callbackData['Result'];
                        
                        if (isset($result['ResultCode']) && $result['ResultCode'] == 0) {
                            // Success
                            $memberB2CHandler->processSuccessfulB2C(
                                $result['ConversationID'] ?? '',
                                $result['TransactionReceipt'] ?? null
                            );
                            
                            logMemberB2CApiEvent('B2C Callback processed successfully', 'INFO', [
                                'conversation_id' => $result['ConversationID'] ?? '',
                                'receipt' => $result['TransactionReceipt'] ?? ''
                            ]);
                            
                            sendJsonResponse(true, [
                                'message' => 'B2C payment completed successfully',
                                'receipt' => $result['TransactionReceipt'] ?? ''
                            ]);
                        } else {
                            // Failure
                            $memberB2CHandler->processFailedB2C(
                                $result['ConversationID'] ?? '',
                                $result['ResultDesc'] ?? 'Payment failed'
                            );
                            
                            logMemberB2CApiEvent('B2C Callback processed as failed', 'WARNING', [
                                'conversation_id' => $result['ConversationID'] ?? '',
                                'error' => $result['ResultDesc'] ?? ''
                            ]);
                            
                            sendJsonResponse(true, [
                                'message' => 'B2C payment failed',
                                'error' => $result['ResultDesc'] ?? ''
                            ]);
                        }
                    } else {
                        throw new Exception('Invalid callback data structure');
                    }
                    
                } catch (Exception $e) {
                    logMemberB2CApiEvent('B2C Callback processing failed', 'ERROR', [
                        'error' => $e->getMessage(),
                        'callback_data' => $callbackData
                    ]);
                    
                    sendJsonResponse(false, null, $e->getMessage(), 400);
                }
                
            } else {
                sendJsonResponse(false, null, 'Invalid action', 400);
            }
            break;
            
        default:
            logMemberB2CApiEvent('Method not allowed', 'WARNING', [
                'method' => $method,
                'timezone' => date_default_timezone_get()
            ]);
            sendJsonResponse(false, null, 'Method not allowed', 405);
    }

} catch (PDOException $e) {
    logMemberB2CApiEvent('Database error in Member B2C API', 'ERROR', [
        'error' => $e->getMessage(),
        'member_id' => $_SESSION['member_id'] ?? 'unknown',
        'timezone' => date_default_timezone_get()
    ]);
    sendJsonResponse(false, null, 'Service temporarily unavailable', 503);
} catch (Exception $e) {
    logMemberB2CApiEvent('Application error in Member B2C API', 'ERROR', [
        'error' => $e->getMessage(),
        'member_id' => $_SESSION['member_id'] ?? 'unknown',
        'timezone' => date_default_timezone_get()
    ]);
    sendJsonResponse(false, null, 'Internal server error: ' . $e->getMessage(), 500);
}
?>