<?php
require_once __DIR__ . '/BaseModel.php';

/**
 * Payment Management Class
 * Handles payment processing, MPesa integration, and payment tracking
 */
class Payment extends BaseModel {
    protected $tableName = 'payments';
    protected $tenantColumn = null; // Payments are isolated by payer_id
    
    public function __construct() {
        parent::__construct();
    }
    
    /**
     * Record a payment
     */
    public function recordPayment($data) {
        // Validate required fields
        $required = ['payer_id', 'amount', 'payment_method', 'transaction_reference'];
        foreach ($required as $field) {
            if (empty($data[$field])) {
                throw new Exception("Field {$field} is required");
            }
        }
        
        // Check if transaction reference already exists
        $checkSql = "SELECT id FROM payments WHERE transaction_reference = ?";
        $checkResult = $this->db->query($checkSql, [$data['transaction_reference']]);
        
        if ($checkResult->num_rows > 0) {
            throw new Exception("Transaction reference already exists");
        }
        
        $paymentData = [
            'invoice_id' => $data['invoice_id'] ?? null,
            'payer_id' => $data['payer_id'],
            'amount' => $data['amount'],
            'payment_method' => $data['payment_method'],
            'transaction_reference' => $data['transaction_reference'],
            'transaction_date' => $data['transaction_date'] ?? date('Y-m-d H:i:s'),
            'payment_proof_url' => $data['payment_proof_url'] ?? null,
            'status' => $data['status'] ?? 'verified'
        ];
        
        $this->db->beginTransaction();
        
        try {
            $paymentId = $this->create($paymentData);
            
            // Update invoice balance if invoice_id is provided
            if (!empty($data['invoice_id'])) {
                $invoiceModel = new Invoice();
                $invoiceModel->updateBalance($data['invoice_id'], $data['amount']);
            }
            
            $this->db->commit();
            
            return $paymentId;
        } catch (Exception $e) {
            $this->db->rollback();
            throw $e;
        }
    }
    
    /**
     * Process MPesa payment
     */
    public function processMPesaPayment($data) {
        // Validate MPesa-specific fields
        if (empty($data['mpesa_code']) || empty($data['phone_number'])) {
            throw new Exception("MPesa code and phone number are required");
        }
        
        // Verify MPesa transaction (this would integrate with MPesa API)
        $mpesaVerified = $this->verifyMPesaTransaction($data['mpesa_code'], $data['phone_number'], $data['amount']);
        
        if (!$mpesaVerified) {
            throw new Exception("MPesa transaction verification failed");
        }
        
        // Record payment
        return $this->recordPayment([
            'invoice_id' => $data['invoice_id'] ?? null,
            'payer_id' => $data['payer_id'],
            'amount' => $data['amount'],
            'payment_method' => 'M-Pesa',
            'transaction_reference' => $data['mpesa_code'],
            'status' => 'verified'
        ]);
    }
    
    /**
     * Process bank transfer payment
     */
    public function processBankTransfer($data) {
        $required = ['bank_name', 'account_number', 'reference_number'];
        foreach ($required as $field) {
            if (empty($data[$field])) {
                throw new Exception("Field {$field} is required for bank transfer");
            }
        }
        
        // Record payment (status pending until verified)
        return $this->recordPayment([
            'invoice_id' => $data['invoice_id'] ?? null,
            'payer_id' => $data['payer_id'],
            'amount' => $data['amount'],
            'payment_method' => 'Bank Transfer',
            'transaction_reference' => $data['reference_number'],
            'payment_proof_url' => $data['payment_proof_url'] ?? null,
            'status' => 'pending' // Requires manual verification
        ]);
    }
    
    /**
     * Process card payment
     */
    public function processCardPayment($data) {
        // This would integrate with a payment gateway (e.g., Stripe, PayPal)
        // For now, we'll record it as pending verification
        
        return $this->recordPayment([
            'invoice_id' => $data['invoice_id'] ?? null,
            'payer_id' => $data['payer_id'],
            'amount' => $data['amount'],
            'payment_method' => 'Credit Card',
            'transaction_reference' => $data['transaction_id'] ?? uniqid('CARD-'),
            'status' => 'pending'
        ]);
    }
    
    /**
     * Verify payment (admin function)
     */
    public function verifyPayment($paymentId, $verifiedBy) {
        $payment = $this->getById($paymentId);
        
        if (!$payment) {
            throw new Exception("Payment not found");
        }
        
        if ($payment['status'] === 'verified') {
            throw new Exception("Payment already verified");
        }
        
        $this->update($paymentId, [
            'status' => 'verified',
            'verified_by' => $verifiedBy
        ]);
        
        // Update invoice balance if invoice_id exists
        if ($payment['invoice_id']) {
            $invoiceModel = new Invoice();
            $invoiceModel->updateBalance($payment['invoice_id'], $payment['amount']);
        }
        
        return true;
    }
    
    /**
     * Get payments by invoice
     */
    public function getPaymentsByInvoice($invoiceId) {
        $sql = "SELECT p.*, u.first_name, u.last_name 
                FROM payments p 
                INNER JOIN users u ON p.payer_id = u.id 
                WHERE p.invoice_id = ? 
                ORDER BY p.transaction_date DESC";
        
        $result = $this->db->query($sql, [$invoiceId]);
        $payments = [];
        
        while ($row = $result->fetch_assoc()) {
            $payments[] = $row;
        }
        
        return $payments;
    }
    
    /**
     * Get payments by payer
     */
    public function getPaymentsByPayer($payerId, $filters = []) {
        $sql = "SELECT p.*, i.invoice_number, i.type as invoice_type, i.description 
                FROM payments p 
                LEFT JOIN invoices i ON p.invoice_id = i.id 
                WHERE p.payer_id = ?";
        
        $params = [$payerId];
        
        foreach ($filters as $column => $value) {
            $sql .= " AND p.{$column} = ?";
            $params[] = $value;
        }
        
        $sql .= " ORDER BY p.transaction_date DESC";
        
        $result = $this->db->query($sql, $params);
        $payments = [];
        
        while ($row = $result->fetch_assoc()) {
            $payments[] = $row;
        }
        
        return $payments;
    }
    
    /**
     * Get payment statistics
     */
    public function getPaymentStats($propertyId = null, $startDate = null, $endDate = null) {
        $sql = "SELECT 
                    COUNT(*) as total_payments,
                    SUM(amount) as total_amount,
                    SUM(CASE WHEN payment_method = 'M-Pesa' THEN amount ELSE 0 END) as mpesa_amount,
                    SUM(CASE WHEN payment_method = 'Bank Transfer' THEN amount ELSE 0 END) as bank_amount,
                    SUM(CASE WHEN payment_method = 'Credit Card' THEN amount ELSE 0 END) as card_amount,
                    SUM(CASE WHEN payment_method = 'Cash' THEN amount ELSE 0 END) as cash_amount,
                    SUM(CASE WHEN status = 'verified' THEN amount ELSE 0 END) as verified_amount,
                    SUM(CASE WHEN status = 'pending' THEN amount ELSE 0 END) as pending_amount
                FROM payments 
                WHERE 1=1";
        
        $params = [];
        
        if ($propertyId) {
            $sql .= " AND invoice_id IN (SELECT id FROM invoices WHERE property_id = ?)";
            $params[] = $propertyId;
        }
        
        if ($startDate) {
            $sql .= " AND transaction_date >= ?";
            $params[] = $startDate;
        }
        
        if ($endDate) {
            $sql .= " AND transaction_date <= ?";
            $params[] = $endDate;
        }
        
        $result = $this->db->query($sql, $params);
        return $result->fetch_assoc();
    }
    
    /**
     * Verify MPesa transaction (placeholder - integrate with actual MPesa API)
     */
    private function verifyMPesaTransaction($mpesaCode, $phoneNumber, $amount) {
        // TODO: Integrate with actual MPesa API
        // For now, return true if code format is valid
        // MPesa codes are typically 10 characters (e.g., "QK12345678")
        
        if (strlen($mpesaCode) >= 8 && strlen($mpesaCode) <= 10) {
            return true;
        }
        
        return false;
    }
    
    /**
     * Refund payment
     */
    public function refundPayment($paymentId, $reason = null) {
        $payment = $this->getById($paymentId);
        
        if (!$payment) {
            throw new Exception("Payment not found");
        }
        
        if ($payment['status'] === 'refunded') {
            throw new Exception("Payment already refunded");
        }
        
        $this->db->beginTransaction();
        
        try {
            // Update payment status
            $this->update($paymentId, ['status' => 'refunded']);
            
            // Reverse invoice balance if invoice_id exists
            if ($payment['invoice_id']) {
                $invoice = (new Invoice())->getById($payment['invoice_id']);
                $newBalance = $invoice['balance'] + $payment['amount'];
                $newPaidAmount = $invoice['paid_amount'] - $payment['amount'];
                
                $status = 'partial';
                if ($newBalance >= $invoice['total_amount']) {
                    $status = 'unpaid';
                }
                
                (new Invoice())->update($payment['invoice_id'], [
                    'balance' => $newBalance,
                    'paid_amount' => $newPaidAmount,
                    'status' => $status
                ]);
            }
            
            $this->db->commit();
            return true;
        } catch (Exception $e) {
            $this->db->rollback();
            throw $e;
        }
    }
}
?>
