<?php

class BillingCalculator {
    private $db;
    private $settings;
    
    public function __construct($db) {
        $this->db = $db;
        $this->loadSettings();
    }
    
    private function loadSettings() {
        $stmt = $this->db->query('SELECT * FROM settings LIMIT 1');
        $this->settings = $stmt->fetchArray(SQLITE3_ASSOC);
    }
    
    public function calculateInvoice($consumptionId) {
        // Get consumption and subscriber data
        $stmt = $this->db->prepare('
            SELECT c.*, s.family_members 
            FROM consumption c 
            JOIN subscribers s ON c.subscriber_id = s.id 
            WHERE c.id = :consumption_id
        ');
        $stmt->bindValue(':consumption_id', $consumptionId, SQLITE3_INTEGER);
        $result = $stmt->execute();
        $data = $result->fetchArray(SQLITE3_ASSOC);
        
        if (!$data) {
            throw new Exception('Consumption record not found');
        }
        
        // Calculate consumption value
        $consumption = $data['current_reading'] - $data['previous_reading'];
        
        // 1. المستحقات الثابتة: تطبق فقط عند انعدام الاستهلاك
        $fixed_fees = 0;
        if ($consumption == 0) {
            $fixed_fees = $this->settings['fixed_fees'];
        }
        
        // 2. مبلغ الاستحقاق الجماعي: يساوي جداء عدد أفراد الأسرة في ثمن الاستحقاق الفردي
        // يكون مساويا للصفر عند انعدام الاستهلاك
        $collective_entitlement_amount = 0;
        if ($consumption > 0) {
            $collective_entitlement_amount = $data['family_members'] * $this->settings['individual_entitlement_price'];
        }
        
        // 3. مبلغ الاستهلاك
        $consumption_amount = 0;
        if ($consumption == 0) {
            // إذا كان الاستهلاك منعدما فإن ثمن الاستهلاك يساوي 0
            $consumption_amount = 0;
        } elseif ($consumption < $this->settings['consumption_threshold']) {
            // إذا كان الاستهلاك الشهري أقل من العتبة وغير منعدم
            // فإن المبلغ الإجمالي يكون مساويا للمبلغ الأدنى للأداء عند وجود استهلاك
            $consumption_amount = $this->settings['minimum_payment_amount'];
        } else {
            // إذا كان الاستهلاك أكبر من أو يساوي العتبة
            // فإن ثمن الاستهلاك يساوي جداء الاستهلاك في ثمن الوحدة
            $consumption_amount = $consumption * $this->settings['unit_price'];
        }
        
        // Return all components
        return [
            'subscriber_id' => $data['subscriber_id'],
            'consumption_id' => $consumptionId,
            'consumption' => $consumption,
            'fixed_fees' => $fixed_fees,
            'collective_entitlement_amount' => $collective_entitlement_amount,
            'consumption_amount' => $consumption_amount,
            'penalties' => 0, // Default to 0, can be modified later
            'total_amount' => $fixed_fees + $collective_entitlement_amount + $consumption_amount // Penalties will be added later if any
        ];
    }
    
    public function createInvoice($consumptionId, $dueDate = null) {
        // Calculate billing components
        $billing = $this->calculateInvoice($consumptionId);
        
        // Set due date if not provided
        if ($dueDate === null) {
            $dueDate = date('Y-m-d', strtotime('+1 month'));
        }
        
        // Generate invoice number
        $invoice_number = $this->generateInvoiceNumber();
        
        // Insert invoice
        $stmt = $this->db->prepare('
            INSERT INTO invoices (
                subscriber_id, consumption_id, fixed_fees, 
                collective_entitlement_amount, consumption_amount, penalties,
                total_amount, due_date, invoice_number
            ) VALUES (
                :subscriber_id, :consumption_id, :fixed_fees,
                :collective_entitlement_amount, :consumption_amount, :penalties,
                :total_amount, :due_date, :invoice_number
            )
        ');
        
        $stmt->bindValue(':subscriber_id', $billing['subscriber_id'], SQLITE3_INTEGER);
        $stmt->bindValue(':consumption_id', $billing['consumption_id'], SQLITE3_INTEGER);
        $stmt->bindValue(':fixed_fees', $billing['fixed_fees'], SQLITE3_FLOAT);
        $stmt->bindValue(':collective_entitlement_amount', $billing['collective_entitlement_amount'], SQLITE3_FLOAT);
        $stmt->bindValue(':consumption_amount', $billing['consumption_amount'], SQLITE3_FLOAT);
        $stmt->bindValue(':penalties', $billing['penalties'], SQLITE3_FLOAT);
        $stmt->bindValue(':total_amount', $billing['total_amount'], SQLITE3_FLOAT);
        $stmt->bindValue(':due_date', $dueDate);
        $stmt->bindValue(':invoice_number', $invoice_number);
        
        if (!$stmt->execute()) {
            throw new Exception('Failed to create invoice');
        }
        
        return $this->db->lastInsertRowID();
    }
    
    private function generateInvoiceNumber() {
        // Get the last invoice number
        $stmt = $this->db->query('SELECT invoice_number FROM invoices ORDER BY id DESC LIMIT 1');
        $last = $stmt->fetchArray(SQLITE3_ASSOC);
        
        if (!$last) {
            return date('Ym') . '0001';
        }
        
        $last_number = $last['invoice_number'];
        $year_month = date('Ym');
        
        if (strpos($last_number, $year_month) === 0) {
            // Same month, increment the sequence
            $sequence = intval(substr($last_number, -4)) + 1;
        } else {
            // New month, start from 1
            $sequence = 1;
        }
        
        return $year_month . str_pad($sequence, 4, '0', STR_PAD_LEFT);
    }
}
