<?php
class PremiumCalculator {
    private $conn;
    private $corp_id;
    private $settings;
    private $rates = null;
    private $rate_cache = [];
    private $benefit_names = [];

    public function __construct($conn, $corp_id) {
        $this->conn = $conn;
        $this->corp_id = $corp_id;
        $this->loadSettings();
        $this->loadBenefitNames();
    }

    /**
     * Load all tax and system settings
     */
    private function loadSettings() {
        error_log("Loading system settings for premium calculation");
        
        $sql = "SELECT setting_key, setting_value FROM settings 
                WHERE setting_key IN ('phcf_percentage', 'stamp_duty', 'training_levy')";
        $result = $this->conn->query($sql);
        
        if (!$result) {
            error_log("Error loading settings: " . $this->conn->error);
            throw new Exception("Failed to load system settings");
        }
        
        $this->settings = [];
        while ($row = $result->fetch_assoc()) {
            $this->settings[$row['setting_key']] = floatval($row['setting_value']);
        }
        
        // Validate required settings exist
        $required_settings = ['phcf_percentage', 'stamp_duty', 'training_levy'];
        foreach ($required_settings as $setting) {
            if (!isset($this->settings[$setting])) {
                error_log("Missing required setting: $setting");
                throw new Exception("Missing required system setting: $setting");
            }
        }
        
        error_log("Successfully loaded settings: " . print_r($this->settings, true));
    }

    /**
     * Load benefit names for reference
     */
    private function loadBenefitNames() {
        $sql = "SELECT code, benefit FROM benefit";
        $result = $this->conn->query($sql);
        
        if (!$result) {
            error_log("Error loading benefit names: " . $this->conn->error);
            throw new Exception("Failed to load benefit names");
        }
        
        while ($row = $result->fetch_assoc()) {
            $this->benefit_names[$row['code']] = $row['benefit'];
        }
    }

    /**
     * Load corporate-specific rates
     */
    private function loadRates() {
        error_log("Loading rates for corp_id: " . $this->corp_id);
    
        // Check cache first
        if (isset($this->rate_cache[$this->corp_id])) {
            $this->rates = $this->rate_cache[$this->corp_id];
            error_log("Using cached rates");
            return;
        }
    
        // First get corporate groups to know which benefits are configured
        $sql = "SELECT cg.benefit, cg.category, cg.sharing, cg.group_limit
                FROM corp_groups cg
                WHERE cg.corp_id = ?
                AND cg.anniv = (
                    SELECT MAX(anniv)
                    FROM corp_groups
                    WHERE corp_id = ?
                )";
                
        $stmt = $this->conn->prepare($sql);
        if (!$stmt) {
            throw new Exception("Database error: " . $this->conn->error);
        }
        
        $stmt->bind_param('ss', $this->corp_id, $this->corp_id);
        $stmt->execute();
        $result = $stmt->get_result();
        
        $configured_benefits = [];
        while ($row = $result->fetch_assoc()) {
            $configured_benefits[$row['benefit']] = $row;
        }
    
        if (empty($configured_benefits)) {
            throw new Exception("No benefits configured for this corporate");
        }
    
        // Now get rates for configured benefits
        $sql = "SELECT r.*, b.benefit as benefit_name
               FROM insuring_rates r
               LEFT JOIN benefit b ON r.benefit = b.code
               WHERE r.corp_id = ? 
               AND r.benefit IN (" . implode(',', array_keys($configured_benefits)) . ")
               AND r.year = (
                   SELECT MAX(year) 
                   FROM insuring_rates 
                   WHERE corp_id = ?
               )";
               
        $stmt = $this->conn->prepare($sql);
        $stmt->bind_param('ss', $this->corp_id, $this->corp_id);
        $stmt->execute();
        $result = $stmt->get_result();
        
        $this->rates = [];
        while ($row = $result->fetch_assoc()) {
            // Merge with configured benefit data
            $row = array_merge($configured_benefits[$row['benefit']], $row);
            $this->rates[$row['benefit']] = $row;
        }
        
        // Cache the rates
        $this->rate_cache[$this->corp_id] = $this->rates;
        
        error_log("Loaded rates: " . print_r($this->rates, true));
    }

    /**
     * Validate member data
     */
    public function validateMemberLimits($member_data) {
        error_log("Validating member data: " . print_r($member_data, true));
        
        $errors = [];

        // Validate age
        if (!isset($member_data['age']) || !is_numeric($member_data['age'])) {
            $errors[] = "Age is required and must be numeric";
        } else {
            $age = (int)$member_data['age'];
            if ($age < 0 || $age > 120) {
                $errors[] = "Age must be between 0 and 120 years";
            }
        }

        // Validate relation
        if (!isset($member_data['relation']) || empty($member_data['relation'])) {
            $errors[] = "Relation type is required";
        } else {
            $valid_relations = ['principal', 'spouse', 'child', 'parent'];
            if (!in_array(strtolower($member_data['relation']), $valid_relations)) {
                $errors[] = "Invalid relation type";
            }
            
            // Additional child age validation
            if (strtolower($member_data['relation']) === 'child') {
                if (isset($member_data['age']) && $member_data['age'] >= 25) {
                    $errors[] = "Maximum age for children is 24 years";
                }
            }
        }

        // Validate benefits if provided
        if (isset($member_data['benefits'])) {
            if (!is_array($member_data['benefits'])) {
                $errors[] = "Benefits must be provided as an array";
            } elseif (empty($member_data['benefits'])) {
                $errors[] = "At least one benefit must be selected";
            } else {
                // Load rates to validate benefits
                try {
                    $this->loadRates();
                    foreach ($member_data['benefits'] as $benefit_code) {
                        if (!isset($this->rates[$benefit_code])) {
                            $errors[] = "Invalid benefit code: " . $benefit_code;
                        }
                    }
                } catch (Exception $e) {
                    $errors[] = "Error validating benefits: " . $e->getMessage();
                }
            }
        }

        error_log("Validation completed. Errors found: " . print_r($errors, true));
        return $errors;
    }

    /**
     * Calculate premium for a member
     */
    public function calculatePremium($member_data) {
        error_log("Starting premium calculation for member: " . print_r($member_data, true));
        
        // Load rates if not already loaded
        $this->loadRates();

        $benefit_premiums = [];
        $total_premium = 0;

        // Calculate premium for each benefit
        foreach ($member_data['benefits'] as $benefit_code) {
            error_log("Processing benefit code: " . $benefit_code);
            
            if (!isset($this->rates[$benefit_code])) {
                throw new Exception("No rate found for benefit " . $benefit_code);
            }

            $rate = $this->rates[$benefit_code];
            $base_premium = floatval($rate['premium']);
            
            // Apply age loading
            $loaded_premium = $this->applyAgeLoading($base_premium, $member_data['age'], $benefit_code);
            
            // Apply relationship adjustments
            $final_premium = $this->applyRelationshipAdjustment(
                $loaded_premium, 
                $member_data['relation'],
                $benefit_code
            );

            // Store benefit details
            $benefit_premiums[$benefit_code] = [
                'benefit_name' => $rate['benefit_name'] ?? $this->benefit_names[$benefit_code] ?? 'Unknown Benefit',
                'base_premium' => $base_premium,
                'loaded_premium' => $loaded_premium,
                'final_premium' => $final_premium,
                'limit' => $rate['limit'],
                'sharing' => (bool)($rate['sharing'] ?? false),
                'category' => $rate['category'] ?? null,
                'group_limit' => $rate['group_limit'] ?? null
            ];

            $total_premium += $final_premium;
        }

        // Calculate taxes and levies
        $taxes = $this->calculateTaxesAndLevies($total_premium);
        
        // Calculate grand total
        $grand_total = $total_premium + $taxes['phcf'] + $taxes['training_levy'] + $taxes['stamp_duty'];

        $result = [
            'benefit_premiums' => $benefit_premiums,
            'total_premium' => $total_premium,
            'taxes' => $taxes,
            'grand_total' => $grand_total
        ];

        error_log("Final premium calculation: " . print_r($result, true));
        return $result;
    }

    /**
     * Apply age-based loading to premium
     */
    private function applyAgeLoading($base_premium, $age, $benefit_code) {
        error_log("Applying age loading - Age: $age, Base premium: $base_premium, Benefit: $benefit_code");
        
        // Age brackets and loading factors
        $loading_factors = [
            ['min' => 0, 'max' => 17, 'factor' => 0.5],    // Children
            ['min' => 18, 'max' => 35, 'factor' => 1.0],   // Young adults
            ['min' => 36, 'max' => 50, 'factor' => 1.1],   // Middle age
            ['min' => 51, 'max' => 64, 'factor' => 1.25],  // Senior
            ['min' => 65, 'max' => 120, 'factor' => 1.5]   // Elderly
        ];

        // Find applicable loading factor
        foreach ($loading_factors as $bracket) {
            if ($age >= $bracket['min'] && $age <= $bracket['max']) {
                $loaded_premium = $base_premium * $bracket['factor'];
                error_log("Applied age loading factor {$bracket['factor']}, resulting premium: $loaded_premium");
                return $loaded_premium;
            }
        }

        // Default to no loading if no bracket found (shouldn't happen due to validation)
        error_log("No age bracket found, using base premium");
        return $base_premium;
    }

    /**
     * Apply relationship-based premium adjustments
     */
    private function applyRelationshipAdjustment($premium, $relation, $benefit_code) {
        error_log("Applying relationship adjustment - Relation: $relation, Premium: $premium, Benefit: $benefit_code");
        
        $relation = strtolower($relation);
        $adjustment_factors = [
            'principal' => 1.0,
            'spouse' => 0.9,    // 10% discount for spouse
            'child' => 0.5,     // 50% discount for children
            'parent' => 1.2     // 20% loading for parents
        ];

        if (isset($adjustment_factors[$relation])) {
            $adjusted_premium = $premium * $adjustment_factors[$relation];
            error_log("Applied relationship factor {$adjustment_factors[$relation]}, resulting premium: $adjusted_premium");
            return $adjusted_premium;
        }

        error_log("No relationship adjustment applied, using original premium");
        return $premium;
    }

    /**
     * Calculate applicable taxes and levies
     */
    private function calculateTaxesAndLevies($premium) {
        error_log("Calculating taxes for premium amount: $premium");

        $taxes = [
            'phcf' => $premium * ($this->settings['phcf_percentage'] / 100),
            'training_levy' => $premium * ($this->settings['training_levy'] / 100),
            'stamp_duty' => floatval($this->settings['stamp_duty'])
        ];

        error_log("Calculated taxes: " . print_r($taxes, true));
        return $taxes;
    }

    /**
     * Get corporate ID
     */
    public function getCorporateId() {
        return $this->corp_id;
    }
}
?>