<?php
// declare(strict_types=1); // Temporarily disabled for compatibility

require_once __DIR__ . '/../config/constants.php';
require_once __DIR__ . '/../config/database.php';

if (!class_exists('PHPMailer\PHPMailer\PHPMailer')) {
    if (file_exists(__DIR__ . '/../vendor/autoload.php')) {
        require_once __DIR__ . '/../vendor/autoload.php';
    } else {
        require_once __DIR__ . '/../vendor/phpmailer/phpmailer/src/Exception.php';
        require_once __DIR__ . '/../vendor/phpmailer/phpmailer/src/PHPMailer.php';
        require_once __DIR__ . '/../vendor/phpmailer/phpmailer/src/SMTP.php';
    }
}

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

/**
 * Investment Functions Class
 * Handles all business logic for the investment platform
 */
class InvestmentFunctions
{
    public PDO $db;

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

    // ============ USER FUNCTIONS ============

    /**
     * Get user by ID
     */
    public function getUserById(int $id): ?array
    {
        $stmt = $this->db->prepare('SELECT * FROM users WHERE id = ?');
        $stmt->execute([$id]);
        $result = $stmt->fetch(PDO::FETCH_ASSOC);
        return $result ?: null;
    }

    /**
     * Get user by email
     */
    public function getUserByEmail(string $email): ?array
    {
        $stmt = $this->db->prepare('SELECT * FROM users WHERE email = ?');
        $stmt->execute([$email]);
        $result = $stmt->fetch(PDO::FETCH_ASSOC);
        return $result ?: null;
    }

    /**
     * Get user balance
     */
    public function getUserBalance(int $userId): float
    {
        $stmt = $this->db->prepare('SELECT balance FROM users WHERE id = ?');
        $stmt->execute([$userId]);
        $result = $stmt->fetch(PDO::FETCH_ASSOC);
        return $result ? (float)$result['balance'] : 0.0;
    }

    /**
     * Get user statistics
     */
    public function getUserStats(int $userId): array
    {
        $stats = [];

        // Total investments
        $stmt = $this->db->prepare('SELECT COUNT(*) as total_investments FROM investments WHERE user_id = ?');
        $stmt->execute([$userId]);
        $stats['total_investments'] = (int)$stmt->fetch(PDO::FETCH_ASSOC)['total_investments'];

        // Running investments
        $stmt = $this->db->prepare('SELECT COUNT(*) as running_investments, SUM(amount) as running_amount FROM investments WHERE user_id = ? AND status = ?');
        $stmt->execute([$userId, 'running']);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
        $stats['running_investments'] = (int)$row['running_investments'];
        $stats['running_amount'] = (float)($row['running_amount'] ?? 0);

        // Completed investments
        $stmt = $this->db->prepare('SELECT COUNT(*) as completed_investments, SUM(total_profit) as total_profit FROM investments WHERE user_id = ? AND status = ?');
        $stmt->execute([$userId, 'completed']);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
        $stats['completed_investments'] = (int)$row['completed_investments'];
        $stats['total_profit'] = (float)($row['total_profit'] ?? 0);

        // Total deposits
        $stmt = $this->db->prepare('SELECT SUM(amount) as total_deposits FROM transactions WHERE user_id = ? AND type = ? AND status = ?');
        $stmt->execute([$userId, 'deposit', 'completed']);
        $stats['total_deposits'] = (float)($stmt->fetch(PDO::FETCH_ASSOC)['total_deposits'] ?? 0);

        // Total withdrawals
        $stmt = $this->db->prepare('SELECT SUM(amount) as total_withdrawals FROM transactions WHERE user_id = ? AND type = ? AND status = ?');
        $stmt->execute([$userId, 'withdrawal', 'completed']);
        $stats['total_withdrawals'] = (float)($stmt->fetch(PDO::FETCH_ASSOC)['total_withdrawals'] ?? 0);

        // Referral earnings
        $stmt = $this->db->prepare('SELECT SUM(amount) as referral_earnings FROM transactions WHERE user_id = ? AND type = ?');
        $stmt->execute([$userId, 'referral_bonus']);
        $stats['referral_earnings'] = (float)($stmt->fetch(PDO::FETCH_ASSOC)['referral_earnings'] ?? 0);

        return $stats;
    }

    /**
     * Update user balance
     */
    public function updateUserBalance(int $userId, float $amount, string $type = 'add'): bool
    {
        $operator = $type === 'add' ? '+' : '-';
        $stmt = $this->db->prepare("UPDATE users SET balance = balance {$operator} ? WHERE id = ?");
        return $stmt->execute([$amount, $userId]);
    }

    // ============ TRANSACTION FUNCTIONS ============

    /**
     * Create transaction
     */
    public function createTransaction(array $data): bool
    {
        $sql = 'INSERT INTO transactions (user_id, type, amount, method, description, reference, status, details)
                VALUES (:user_id, :type, :amount, :method, :description, :reference, :status, :details)';

        $stmt = $this->db->prepare($sql);
        $reference = $data['reference'] ?? ('TRX' . time() . random_int(1000, 9999));

        return $stmt->execute([
            ':user_id' => $data['user_id'],
            ':type' => $data['type'],
            ':amount' => $data['amount'],
            ':method' => $data['method'] ?? '',
            ':description' => $data['description'] ?? '',
            ':reference' => $reference,
            ':status' => $data['status'] ?? 'pending',
            ':details' => json_encode($data['details'] ?? [])
        ]);
    }

    /**
     * Get transactions
     */
    public function getTransactions(int $userId, ?string $type = null, int $limit = 50): array
    {
        $sql = 'SELECT * FROM transactions WHERE user_id = ?';
        $params = [$userId];

        if ($type !== null) {
            $sql .= ' AND type = ?';
            $params[] = $type;
        }

        $sql .= ' ORDER BY created_at DESC LIMIT ?';
        $params[] = $limit;

        $stmt = $this->db->prepare($sql);
        $stmt->execute($params);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    // ============ INVESTMENT FUNCTIONS ============

    /**
     * Get investment plans
     */
    public function getInvestmentPlans(bool $activeOnly = true): array
    {
        $sql = 'SELECT * FROM investment_plans';
        if ($activeOnly) {
            $sql .= ' WHERE status = ?';
        }
        $sql .= ' ORDER BY min_amount ASC';

        $stmt = $this->db->prepare($sql);
        if ($activeOnly) {
            $stmt->execute(['active']);
        } else {
            $stmt->execute();
        }
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    /**
     * Get plan by ID
     */
    public function getPlanById(int $planId): ?array
    {
        $stmt = $this->db->prepare('SELECT * FROM investment_plans WHERE id = ?');
        $stmt->execute([$planId]);
        $result = $stmt->fetch(PDO::FETCH_ASSOC);
        return $result ?: null;
    }

    /**
     * Create investment
     */
    public function createInvestment(int $userId, int $planId, float $amount): array
    {
        $this->db->beginTransaction();

        try {
            // Get plan details
            $plan = $this->getPlanById($planId);
            if (!$plan) {
                throw new Exception('Plan not found');
            }

            // Check minimum amount
            if ($amount < $plan['min_amount']) {
                throw new Exception('Minimum investment is $' . $plan['min_amount']);
            }

            // Check maximum amount
            if ($amount > $plan['max_amount']) {
                throw new Exception('Maximum investment is $' . $plan['max_amount']);
            }

            // Check user balance
            $user = $this->getUserById($userId);
            if (!$user || $user['balance'] < $amount) {
                throw new Exception('Insufficient balance');
            }

            // Calculate daily profit
            $dailyProfit = ($amount * $plan['daily_return']) / 100;
            $endDate = date('Y-m-d H:i:s', strtotime("+{$plan['duration_days']} days"));

            // Deduct from balance
            $this->updateUserBalance($userId, $amount, 'subtract');

            // Create investment
            $stmt = $this->db->prepare('INSERT INTO investments (user_id, plan_id, amount, daily_profit, end_date, status)
                                       VALUES (?, ?, ?, ?, ?, ?)');
            $stmt->execute([$userId, $planId, $amount, $dailyProfit, $endDate, 'running']);

            $investmentId = (int)$this->db->lastInsertId();

            // Record transaction
            $this->createTransaction([
                'user_id' => $userId,
                'type' => 'investment',
                'amount' => $amount,
                'method' => 'balance',
                'description' => "Investment in {$plan['name']}",
                'status' => 'completed',
                'details' => ['investment_id' => $investmentId, 'plan_id' => $planId]
            ]);

            $this->db->commit();
            return ['success' => true, 'investment_id' => $investmentId];

        } catch (Exception $e) {
            $this->db->rollBack();
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }

    // ============ DEPOSIT FUNCTIONS ============

    /**
     * Process deposit
     */
    public function processDeposit(int $userId, float $amount, string $method, ?string $paymentProof = null)
    {
        $reference = 'DEP' . time() . random_int(1000, 9999);

        $data = [
            'user_id' => $userId,
            'type' => 'deposit',
            'amount' => $amount,
            'method' => $method,
            'description' => "Deposit via {$method}",
            'reference' => $reference,
            'status' => 'pending',
            'details' => [
                'payment_method' => $method,
                'payment_proof' => $paymentProof,
                'processed_at' => date('Y-m-d H:i:s')
            ]
        ];

        if ($this->createTransaction($data)) {
            return $reference;
        }

        return false;
    }

    // ============ WITHDRAWAL FUNCTIONS ============

    /**
     * Process withdrawal
     */
    public function processWithdrawal(int $userId, float $amount, string $method, ?string $walletAddress = null): array
    {
        // Check minimum withdrawal
        if ($amount < MIN_WITHDRAWAL) {
            return ['success' => false, 'message' => 'Minimum withdrawal is $' . MIN_WITHDRAWAL];
        }

        // Check user balance
        $user = $this->getUserById($userId);
        if (!$user || $user['balance'] < $amount) {
            return ['success' => false, 'message' => 'Insufficient balance'];
        }

        // Calculate fee
        $fee = $amount * WITHDRAWAL_FEE;
        $netAmount = $amount - $fee;

        $reference = 'WTH' . time() . random_int(1000, 9999);

        $data = [
            'user_id' => $userId,
            'type' => 'withdrawal',
            'amount' => $amount,
            'method' => $method,
            'description' => "Withdrawal to {$method}",
            'reference' => $reference,
            'status' => 'pending',
            'details' => [
                'fee' => $fee,
                'net_amount' => $netAmount,
                'wallet_address' => $walletAddress,
                'requested_at' => date('Y-m-d H:i:s')
            ]
        ];

        if ($this->createTransaction($data)) {
            // Lock the amount by deducting from balance
            $this->updateUserBalance($userId, $amount, 'subtract');
            return ['success' => true, 'reference' => $reference];
        }

        return ['success' => false, 'message' => 'Withdrawal request failed'];
    }

    // ============ REFERRAL FUNCTIONS ============

    /**
     * Add referral bonus
     */
    public function addReferralBonus(int $referrerId, int $newUserId): void
    {
        $bonusAmount = REFERRAL_BONUS_AMOUNT;

        // Update referrer's balance
        $this->updateUserBalance($referrerId, $bonusAmount, 'add');

        // Update referral balance
        $stmt = $this->db->prepare('UPDATE users SET referral_balance = referral_balance + ? WHERE id = ?');
        $stmt->execute([$bonusAmount, $referrerId]);

        // Record transaction
        $this->createTransaction([
            'user_id' => $referrerId,
            'type' => 'referral_bonus',
            'amount' => $bonusAmount,
            'method' => 'system',
            'description' => "Referral bonus for new user #{$newUserId}",
            'status' => 'completed',
            'details' => ['new_user_id' => $newUserId]
        ]);
    }

    // ============ SUPPORT FUNCTIONS ============

    /**
     * Create support ticket
     */
    public function createSupportTicket(int $userId, string $subject, string $message, string $category = 'general'): bool
    {
        $stmt = $this->db->prepare('INSERT INTO support_tickets (user_id, subject, message, category, status)
                                   VALUES (?, ?, ?, ?, ?)');
        return $stmt->execute([$userId, $subject, $message, $category, 'open']);
    }

    // ============ UTILITY FUNCTIONS ============

    /**
     * Sanitize input
     */
    public function sanitize(string $input): string
    {
        return htmlspecialchars(strip_tags(trim($input)), ENT_QUOTES, 'UTF-8');
    }

    /**
     * Format currency
     */
    public function formatCurrency(float $amount): string
    {
        return '$' . number_format($amount, 2);
    }

    /**
     * Generate reference
     */
    public function generateReference(string $prefix = 'REF'): string
    {
        return $prefix . time() . random_int(1000, 9999);
    }

    /**
     * Validate email
     */
    public function validateEmail(string $email): bool
    {
        return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
    }

    /**
     * Send an email using configured SMTP settings.
     */
    public function sendEmail(string $to, string $subject, string $body): bool
    {
        if (!$this->validateEmail($to)) {
            return false;
        }

        $mail = new PHPMailer(true);
        try {
            $mail->isSMTP();
            $mail->Host = SMTP_HOST;
            $mail->SMTPAuth = true;
            $mail->Username = SMTP_USERNAME;
            $mail->Password = SMTP_PASSWORD;
            $mail->SMTPSecure = SMTP_ENCRYPTION;
            $mail->Port = SMTP_PORT;
            $mail->CharSet = 'UTF-8';
            $mail->setFrom(SITE_EMAIL, SITE_NAME);
            $mail->addAddress($to);
            $mail->isHTML(true);
            $mail->Subject = $subject;
            $mail->Body = $body;

            return $mail->send();
        } catch (Exception $e) {
            error_log("Notification email failed to {$to}: " . $mail->ErrorInfo);
            return false;
        }
    }

    /**
     * Validate password
     */
    public function validatePassword(string $password): bool
    {
        // At least 8 characters, 1 uppercase, 1 lowercase, 1 number
        return preg_match('/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/', $password) === 1;
    }

    // ============ SECURITY FUNCTIONS ============

    /**
     * Generate token
     */
    public function generateToken(int $length = 32): string
    {
        return bin2hex(random_bytes($length));
    }

    /**
     * Hash password
     */
    public function hashPassword(string $password): string
    {
        return password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
    }

    /**
     * Verify password
     */
    public function verifyPassword(string $password, string $hash): bool
    {
        return password_verify($password, $hash);
    }

    /**
     * Log activity
     */
    public function logActivity(int $userId, string $action, string|array $details = []): void
    {
        $stmt = $this->db->prepare('INSERT INTO activity_logs (user_id, action, description, ip_address, user_agent, details, created_at)
                                   VALUES (?, ?, ?, ?, ?, ?, NOW())');

        $stmt->execute([
            $userId,
            $action,
            is_string($details) ? $details : json_encode($details),
            $_SERVER['REMOTE_ADDR'] ?? 'unknown',
            $_SERVER['HTTP_USER_AGENT'] ?? 'unknown',
            json_encode($details)
        ]);
    }

    // ============ SETTINGS FUNCTIONS ============

    /**
     * Get setting
     */
    public function getSetting(string $key, $default = null)
    {
        $stmt = $this->db->prepare('SELECT `value`, `type` FROM settings WHERE `key` = ?');
        $stmt->execute([$key]);
        $setting = $stmt->fetch(PDO::FETCH_ASSOC);

        if ($setting) {
            switch ($setting['type']) {
                case 'boolean':
                    return (bool)$setting['value'];
                case 'number':
                    return (float)$setting['value'];
                default:
                    return $setting['value'];
            }
        }

        return $default;
    }

    /**
     * Set setting
     */
    public function setSetting(string $key, $value, string $type = 'text'): bool
    {
        $stmt = $this->db->prepare('
            INSERT INTO settings (`key`, `value`, `type`)
            VALUES (?, ?, ?)
            ON DUPLICATE KEY UPDATE `value` = VALUES(`value`), `type` = VALUES(`type`)
        ');
        return $stmt->execute([$key, $value, $type]);
    }

    // ============ ADMIN FUNCTIONS ============

    /**
     * Get all users
     */
    public function getAllUsers(int $limit = 100, int $offset = 0): array
    {
        $stmt = $this->db->prepare('SELECT * FROM users ORDER BY created_at DESC LIMIT ? OFFSET ?');
        $stmt->bindValue(1, $limit, PDO::PARAM_INT);
        $stmt->bindValue(2, $offset, PDO::PARAM_INT);
        $stmt->execute();
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    /**
     * Update transaction status
     */
    public function updateTransactionStatus(int $transactionId, string $status, int $adminId): bool
    {
        $stmt = $this->db->prepare('UPDATE transactions SET status = ?, admin_action_by = ?, updated_at = NOW() WHERE id = ?');
        return $stmt->execute([$status, $adminId, $transactionId]);
    }

    /**
     * Get dashboard stats
     */
    public function getDashboardStats(): array
    {
        $stats = [];

        // Total users
        $stmt = $this->db->query('SELECT COUNT(*) as total_users FROM users');
        $stats['total_users'] = (int)$stmt->fetch(PDO::FETCH_ASSOC)['total_users'];

        // Active users today
        $stmt = $this->db->query('SELECT COUNT(DISTINCT user_id) as active_today FROM activity_logs WHERE DATE(created_at) = CURDATE()');
        $stats['active_today'] = (int)$stmt->fetch(PDO::FETCH_ASSOC)['active_today'];

        // Total deposits
        $stmt = $this->db->query('SELECT SUM(amount) as total_deposits FROM transactions WHERE type = \'deposit\' AND status = \'completed\'');
        $stats['total_deposits'] = (float)($stmt->fetch(PDO::FETCH_ASSOC)['total_deposits'] ?? 0);

        // Total withdrawals
        $stmt = $this->db->query('SELECT SUM(amount) as total_withdrawals FROM transactions WHERE type = \'withdrawal\' AND status = \'completed\'');
        $stats['total_withdrawals'] = (float)($stmt->fetch(PDO::FETCH_ASSOC)['total_withdrawals'] ?? 0);

        // Pending transactions
        $stmt = $this->db->query('SELECT COUNT(*) as pending_transactions FROM transactions WHERE status = \'pending\'');
        $stats['pending_transactions'] = (int)$stmt->fetch(PDO::FETCH_ASSOC)['pending_transactions'];

        // Active investments
        $stmt = $this->db->query('SELECT COUNT(*) as active_investments, SUM(amount) as total_invested FROM investments WHERE status = \'running\'');
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
        $stats['active_investments'] = (int)$row['active_investments'];
        $stats['total_invested'] = (float)($row['total_invested'] ?? 0);

        return $stats;
    }
}

// Initialize functions
$functions = new InvestmentFunctions();