<?php
/**
 * Tom's Java Jive - Customer Loyalty Program
 * 
 * Handles loyalty tiers, points, and rewards
 */

class LoyaltyProgram {

    private array $tiers = [];

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

    private function loadTiers(): void {
        $rows = db()->fetchAll("SELECT * FROM loyalty_tiers ORDER BY min_points ASC");
        foreach ($rows as $row) {
            $key = strtolower($row['name']);
            $benefits = json_decode($row['benefits'] ?? '[]', true) ?? [];
            $this->tiers[$key] = [
                'name'        => $row['name'],
                'min_points'  => (int) $row['min_points'],
                'multiplier'  => (float) $row['multiplier'],
                'benefits'    => $benefits,
                'color'       => $row['color'] ?? '#888',
                'icon'        => 'fa-coffee',
            ];
        }
        // Fallback if DB is empty
        if (empty($this->tiers)) {
            $this->tiers = [
                'bronze'   => ['name'=>'Bronze',   'min_points'=>0,    'multiplier'=>1.0, 'benefits'=>[], 'color'=>'#CD7F32', 'icon'=>'fa-coffee'],
                'silver'   => ['name'=>'Silver',   'min_points'=>500,  'multiplier'=>1.5, 'benefits'=>[], 'color'=>'#C0C0C0', 'icon'=>'fa-mug-hot'],
                'gold'     => ['name'=>'Gold',     'min_points'=>1500, 'multiplier'=>2.0, 'benefits'=>[], 'color'=>'#FFD700', 'icon'=>'fa-crown'],
                'platinum' => ['name'=>'Platinum', 'min_points'=>3000, 'multiplier'=>3.0, 'benefits'=>[], 'color'=>'#E5E4E2', 'icon'=>'fa-gem'],
            ];
        }
    }
    
    // Points redemption rates
    private float $pointsToValue = 0.01; // 1 point = $0.01 (100 points = $1)
    
    /**
     * Get all tier definitions
     */
    public function getTiers(): array {
        return $this->tiers;
    }
    
    /**
     * Get a specific tier
     */
    public function getTier(string $tierKey): ?array {
        return $this->tiers[$tierKey] ?? null;
    }
    
    /**
     * Determine customer's tier based on total points earned (lifetime)
     */
    public function calculateTier(int $lifetimePoints): string {
        $currentTier = 'bronze';
        
        foreach ($this->tiers as $key => $tier) {
            if ($lifetimePoints >= $tier['min_points']) {
                $currentTier = $key;
            }
        }
        
        return $currentTier;
    }
    
    /**
     * Get customer's current tier info
     */
    public function getCustomerTier(string $customerId): array {
        $customer = db()->fetch(
            "SELECT reward_points, lifetime_points, loyalty_tier FROM customers WHERE customer_id = :id",
            ['id' => $customerId]
        );
        
        if (!$customer) {
            return ['tier' => 'bronze', 'info' => $this->tiers['bronze'], 'points' => 0];
        }
        
        $lifetimePoints = $customer['lifetime_points'] ?? $customer['reward_points'] ?? 0;
        $tierKey = $this->calculateTier($lifetimePoints);
        $tier = $this->tiers[$tierKey];
        
        // Calculate progress to next tier
        $nextTierKey = $this->getNextTier($tierKey);
        $nextTier = $nextTierKey ? $this->tiers[$nextTierKey] : null;
        
        $progress = 100;
        $pointsToNext = 0;
        
        if ($nextTier) {
            $currentMin = $tier['min_points'];
            $nextMin = $nextTier['min_points'];
            $pointsToNext = $nextMin - $lifetimePoints;
            $progress = min(100, (($lifetimePoints - $currentMin) / ($nextMin - $currentMin)) * 100);
        }
        
        return [
            'tier' => $tierKey,
            'info' => $tier,
            'points' => $customer['reward_points'] ?? 0,
            'lifetime_points' => $lifetimePoints,
            'next_tier' => $nextTierKey,
            'next_tier_info' => $nextTier,
            'points_to_next' => $pointsToNext,
            'progress_percent' => round($progress, 1)
        ];
    }
    
    /**
     * Get next tier key
     */
    private function getNextTier(string $currentTier): ?string {
        $keys = array_keys($this->tiers);
        $index = array_search($currentTier, $keys);
        
        return isset($keys[$index + 1]) ? $keys[$index + 1] : null;
    }
    
    /**
     * Award points for a purchase
     */
    public function awardPoints(string $customerId, float $amount, string $description = 'Purchase', string $orderId = ''): array {
        // Prevent duplicate awards for the same order
        if ($orderId) {
            $already = db()->fetch(
                "SELECT id FROM loyalty_transactions WHERE order_id = :oid AND type = 'earn' LIMIT 1",
                ['oid' => $orderId]
            );
            if ($already) {
                return ['points_earned' => 0, 'already_awarded' => true];
            }
        }

        $customerTier = $this->getCustomerTier($customerId);
        $multiplier = $customerTier['info']['multiplier'];

        // Calculate points (base: 1 point per dollar)
        $basePoints = (int) floor($amount);
        $bonusPoints = (int) floor($basePoints * ($multiplier - 1));
        $totalPoints = $basePoints + $bonusPoints;

        // Update customer points
        db()->query(
            "UPDATE customers SET
                reward_points = reward_points + :points,
                lifetime_points = COALESCE(lifetime_points, 0) + :points2,
                updated_at = NOW()
             WHERE customer_id = :id",
            ['points' => $totalPoints, 'points2' => $totalPoints, 'id' => $customerId]
        );

        $newBalance = db()->fetch(
            "SELECT reward_points FROM customers WHERE customer_id = :id",
            ['id' => $customerId]
        )['reward_points'] ?? $totalPoints;

        // Log the transaction
        db()->insert('loyalty_transactions', [
            'transaction_id' => generateId('lt_'),
            'customer_id'    => $customerId,
            'points'         => $totalPoints,
            'balance_after'  => $newBalance,
            'type'           => 'earn',
            'description'    => $description . ($bonusPoints > 0 ? " (+{$bonusPoints} bonus)" : ''),
            'reference_amount' => $amount,
            'order_id'       => $orderId ?: null,
        ]);
        
        // Check for tier upgrade
        $newTier = $this->checkTierUpgrade($customerId, $customerTier['tier']);
        
        return [
            'points_earned' => $totalPoints,
            'base_points' => $basePoints,
            'bonus_points' => $bonusPoints,
            'multiplier' => $multiplier,
            'tier_upgraded' => $newTier !== null,
            'new_tier' => $newTier
        ];
    }
    
    /**
     * Redeem points for credit
     */
    public function redeemPoints(string $customerId, int $points): array {
        $customer = db()->fetch(
            "SELECT reward_points FROM customers WHERE customer_id = :id",
            ['id' => $customerId]
        );
        
        if (!$customer || $customer['reward_points'] < $points) {
            return ['success' => false, 'error' => 'Insufficient points'];
        }
        
        $creditValue = $points * $this->pointsToValue;
        
        // Deduct points
        db()->query(
            "UPDATE customers SET reward_points = reward_points - :points, updated_at = NOW() WHERE customer_id = :id",
            ['points' => $points, 'id' => $customerId]
        );
        
        // Log the redemption
        db()->insert('loyalty_transactions', [
            'transaction_id' => generateId('lt_'),
            'customer_id' => $customerId,
            'points' => -$points,
            'type' => 'redeem',
            'description' => "Redeemed for " . formatCurrency($creditValue) . " credit",
            'reference_amount' => $creditValue
        ]);
        
        // Add to wallet
        $newBalance = db()->fetch(
            "SELECT wallet_balance FROM customers WHERE customer_id = :id",
            ['id' => $customerId]
        )['wallet_balance'] ?? 0;
        
        $newBalance += $creditValue;
        
        db()->query(
            "UPDATE customers SET wallet_balance = :balance WHERE customer_id = :id",
            ['balance' => $newBalance, 'id' => $customerId]
        );
        
        // Log wallet transaction
        db()->insert('wallet_transactions', [
            'transaction_id' => generateId('wt_'),
            'customer_id' => $customerId,
            'amount' => $creditValue,
            'balance_after' => $newBalance,
            'type' => 'loyalty_redemption',
            'description' => "Redeemed {$points} loyalty points"
        ]);
        
        return [
            'success' => true,
            'points_redeemed' => $points,
            'credit_value' => $creditValue,
            'new_points_balance' => $customer['reward_points'] - $points,
            'new_wallet_balance' => $newBalance
        ];
    }
    
    /**
     * Check and process tier upgrade
     */
    public function checkTierUpgrade(string $customerId, string $currentTier): ?string {
        $customer = db()->fetch(
            "SELECT lifetime_points, loyalty_tier FROM customers WHERE customer_id = :id",
            ['id' => $customerId]
        );
        
        if (!$customer) {
            return null;
        }
        
        $calculatedTier = $this->calculateTier($customer['lifetime_points'] ?? 0);
        $storedTier = $customer['loyalty_tier'] ?? 'bronze';
        
        // Compare tier levels
        $tierOrder = ['bronze', 'silver', 'gold', 'platinum'];
        $calculatedIndex = array_search($calculatedTier, $tierOrder);
        $storedIndex = array_search($storedTier, $tierOrder);
        
        if ($calculatedIndex > $storedIndex) {
            // Upgrade!
            db()->query(
                "UPDATE customers SET loyalty_tier = :tier, updated_at = NOW() WHERE customer_id = :id",
                ['tier' => $calculatedTier, 'id' => $customerId]
            );
            
            // Log the upgrade
            db()->insert('loyalty_transactions', [
                'transaction_id' => generateId('lt_'),
                'customer_id' => $customerId,
                'points' => 0,
                'type' => 'tier_upgrade',
                'description' => "Upgraded from {$this->tiers[$storedTier]['name']} to {$this->tiers[$calculatedTier]['name']}"
            ]);
            
            // Send notifications
            $this->sendTierUpgradeNotifications($customerId, $calculatedTier);
            
            return $calculatedTier;
        }
        
        return null;
    }
    
    /**
     * Send tier upgrade notifications
     */
    private function sendTierUpgradeNotifications(string $customerId, string $newTier): void {
        $customer = db()->fetch(
            "SELECT email, phone, name FROM customers WHERE customer_id = :id",
            ['id' => $customerId]
        );
        
        if (!$customer) return;
        
        $tierInfo = $this->tiers[$newTier];
        
        // Send email notification
        if (!empty($customer['email'])) {
            require_once __DIR__ . '/email.php';
            // Custom email for tier upgrade would go here
        }
        
        // Send SMS notification
        if (!empty($customer['phone'])) {
            require_once __DIR__ . '/sms.php';
            sendSMS()->sendTierUpgrade($customer['phone'], $tierInfo['name']);
        }
        
        // Send push notification
        require_once __DIR__ . '/push.php';
        pushNotify()->sendTierNotification($customerId, $tierInfo['name'], $tierInfo['benefits']);
    }
    
    /**
     * Get points conversion info
     */
    public function getConversionInfo(): array {
        return [
            'points_per_dollar' => 1,
            'points_value' => $this->pointsToValue,
            'points_for_one_dollar' => intval(1 / $this->pointsToValue),
            'description' => 'Earn 1 point for every $1 spent. Redeem 100 points for $1 credit.'
        ];
    }
    
    /**
     * Get customer's loyalty history
     */
    public function getHistory(string $customerId, int $limit = 20): array {
        return db()->fetchAll(
            "SELECT * FROM loyalty_transactions WHERE customer_id = :id ORDER BY created_at DESC LIMIT :limit",
            ['id' => $customerId, 'limit' => $limit]
        );
    }
    
    /**
     * Award birthday bonus
     */
    public function awardBirthdayBonus(string $customerId): array {
        $customerTier = $this->getCustomerTier($customerId);
        
        // Bonus points based on tier
        $bonusPoints = match($customerTier['tier']) {
            'platinum' => 500,
            'gold' => 300,
            'silver' => 200,
            default => 100
        };
        
        db()->query(
            "UPDATE customers SET reward_points = reward_points + :points WHERE customer_id = :id",
            ['points' => $bonusPoints, 'id' => $customerId]
        );
        
        db()->insert('loyalty_transactions', [
            'transaction_id' => generateId('lt_'),
            'customer_id' => $customerId,
            'points' => $bonusPoints,
            'type' => 'birthday_bonus',
            'description' => "Birthday reward - Happy Birthday!"
        ]);
        
        return ['success' => true, 'points' => $bonusPoints];
    }
    
    /**
     * Award referral bonus
     */
    public function awardReferralBonus(string $referrerId, string $newCustomerId): array {
        $referrerBonus = 100;
        $newCustomerBonus = 50;
        
        // Award to referrer
        db()->query(
            "UPDATE customers SET reward_points = reward_points + :points WHERE customer_id = :id",
            ['points' => $referrerBonus, 'id' => $referrerId]
        );
        
        db()->insert('loyalty_transactions', [
            'transaction_id' => generateId('lt_'),
            'customer_id' => $referrerId,
            'points' => $referrerBonus,
            'type' => 'referral_bonus',
            'description' => "Referral bonus - Thank you for spreading the word!"
        ]);
        
        // Award to new customer
        db()->query(
            "UPDATE customers SET reward_points = reward_points + :points WHERE customer_id = :id",
            ['points' => $newCustomerBonus, 'id' => $newCustomerId]
        );
        
        db()->insert('loyalty_transactions', [
            'transaction_id' => generateId('lt_'),
            'customer_id' => $newCustomerId,
            'points' => $newCustomerBonus,
            'type' => 'referral_welcome',
            'description' => "Welcome bonus from referral"
        ]);
        
        return [
            'referrer_bonus' => $referrerBonus,
            'new_customer_bonus' => $newCustomerBonus
        ];
    }

    /**
     * Redeem a gift card code into wallet balance. Shared by the Wallet page
     * and checkout so both go through the same transaction logic instead of
     * duplicating it.
     */
    public function redeemGiftCardToWallet(string $customerId, string $rawCode): array {
        $code = strtoupper(str_replace(['-', ' '], '', trim($rawCode)));

        if (empty($code) || strlen($code) < 8) {
            return ['success' => false, 'error' => 'Invalid gift card code'];
        }

        $giftCard = db()->fetch(
            "SELECT * FROM gift_cards WHERE code = :code AND is_active = 1",
            ['code' => $code]
        );

        if (!$giftCard) {
            return ['success' => false, 'error' => 'Gift card not found or already used'];
        }

        if ($giftCard['current_balance'] <= 0) {
            return ['success' => false, 'error' => 'This gift card has no remaining balance'];
        }

        if ($giftCard['expires_at'] && strtotime($giftCard['expires_at']) < time()) {
            return ['success' => false, 'error' => 'This gift card has expired'];
        }

        $customer = db()->fetch("SELECT wallet_balance FROM customers WHERE customer_id = :id", ['id' => $customerId]);
        if (!$customer) {
            return ['success' => false, 'error' => 'Customer not found'];
        }

        $amount = $giftCard['current_balance'];

        try {
            db()->query("START TRANSACTION");

            db()->query(
                "UPDATE gift_cards SET current_balance = 0, is_active = 0 WHERE gift_card_id = :id",
                ['id' => $giftCard['gift_card_id']]
            );

            db()->insert('gift_card_transactions', [
                'gift_card_id' => $giftCard['gift_card_id'],
                'amount' => -$amount,
                'balance_after' => 0,
                'type' => 'redemption',
            ]);

            $newWalletBalance = (float) $customer['wallet_balance'] + $amount;

            db()->query(
                "UPDATE customers SET wallet_balance = :balance, updated_at = NOW() WHERE customer_id = :id",
                ['balance' => $newWalletBalance, 'id' => $customerId]
            );

            db()->insert('wallet_transactions', [
                'transaction_id' => generateId('wt_'),
                'customer_id' => $customerId,
                'amount' => $amount,
                'balance_after' => $newWalletBalance,
                'type' => 'deposit',
                'description' => 'Gift card redeemed: ' . $code
            ]);

            db()->query("COMMIT");

            return [
                'success' => true,
                'amount' => $amount,
                'new_balance' => $newWalletBalance
            ];
        } catch (Exception $e) {
            db()->query("ROLLBACK");
            return ['success' => false, 'error' => 'Failed to redeem gift card. Please try again.'];
        }
    }
}

// Helper function
function loyalty(): LoyaltyProgram {
    static $instance = null;
    if ($instance === null) {
        $instance = new LoyaltyProgram();
    }
    return $instance;
}
