<?php
// Enable error reporting for debugging (disable in production)
error_reporting(E_ALL);
ini_set('display_errors', 1);

session_start();
require_once 'connection.php';

// CSRF Protection
if (!isset($_POST['csrf_token']) || strlen($_POST['csrf_token']) !== 64) {
    header("Location: ../register.php?error=" . urlencode("Invalid security token"));
    exit();
}

// Rate limiting
$ip = $_SERVER['REMOTE_ADDR'];
$rate_limit_file = sys_get_temp_dir() . '/reg_' . md5($ip) . '.txt';
$current_time = time();
$time_window = 3600; // 1 hour
$max_attempts = 5; // 5 attempts per hour

if (file_exists($rate_limit_file)) {
    $attempts = unserialize(file_get_contents($rate_limit_file));
    // Clean old attempts
    $attempts = array_filter($attempts, function($time) use ($current_time, $time_window) {
        return ($current_time - $time) < $time_window;
    });
    
    if (count($attempts) >= $max_attempts) {
        header("Location: ../register.php?error=" . urlencode("Too many registration attempts. Please try again later."));
        exit();
    }
} else {
    $attempts = [];
}

$attempts[] = $current_time;
file_put_contents($rate_limit_file, serialize($attempts));

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['public_registration'])) {
    
    // Validate and sanitize inputs
    $sponsor_id = isset($_POST['sponsor_id']) ? (int)$_POST['sponsor_id'] : 0;
    $pin = isset($_POST['pin']) ? trim($_POST['pin']) : '';
    $name = isset($_POST['name']) ? trim($_POST['name']) : '';
    $email = isset($_POST['email']) ? trim($_POST['email']) : '';
    $phone = isset($_POST['phone']) ? trim($_POST['phone']) : '';
    $password = isset($_POST['password']) ? $_POST['password'] : '';
    $confirm_password = isset($_POST['confirm_password']) ? $_POST['confirm_password'] : '';

    // Validate required fields
    if (empty($sponsor_id) || empty($pin) || empty($name) || empty($phone) || empty($password) || empty($confirm_password)) {
        header("Location: ../register.php?error=" . urlencode("All fields are required"));
        exit();
    }

    // Validate email if provided
    if (!empty($email) && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
        header("Location: ../register.php?error=" . urlencode("Invalid email format"));
        exit();
    }

    // Validate phone number
    if (!preg_match('/^[0-9]{10}$/', $phone)) {
        header("Location: ../register.php?error=" . urlencode("Invalid phone number. Must be 10 digits."));
        exit();
    }

    // Validate password
    if (strlen($password) < 6 || !preg_match('/[0-9]/', $password) || !preg_match('/[a-zA-Z]/', $password)) {
        header("Location: ../register.php?error=" . urlencode("Password must be at least 6 characters and contain both letters and numbers"));
        exit();
    }

    // Check password match
    if ($password !== $confirm_password) {
        header("Location: ../register.php?error=" . urlencode("Passwords do not match"));
        exit();
    }

    // Hash password
    $hashed_password = password_hash($password, PASSWORD_DEFAULT);

    $conn->begin_transaction();

    try {
        // Validate sponsor exists and is active
        $sponsor_query = $conn->prepare("SELECT user_id, name FROM users WHERE user_id = ? AND status = 1");
        $sponsor_query->bind_param("i", $sponsor_id);
        $sponsor_query->execute();
        $sponsor_result = $sponsor_query->get_result();
        
        if ($sponsor_result->num_rows == 0) {
            throw new Exception("Invalid Sponsor ID");
        }
        $sponsor = $sponsor_result->fetch_assoc();

        // Validate PIN (check if exists and unused)
        $pin_query = $conn->prepare("SELECT * FROM pin WHERE pin_value = ? AND status = '0'");
        $pin_query->bind_param("s", $pin);
        $pin_query->execute();
        $pin_result = $pin_query->get_result();
        
        if ($pin_result->num_rows == 0) {
            throw new Exception("Invalid or already used PIN");
        }
        
        $pin_data = $pin_result->fetch_assoc();

        // Get the TOP ROOT user
        $root_query = $conn->query("SELECT user_id FROM users WHERE user_id = 12345678");
        if ($root_query->num_rows == 0) {
            throw new Exception("System configuration error");
        }
        $root = $root_query->fetch_assoc();
        $root_id = $root['user_id'];

        // Generate unique 8-digit user_id
        $max_attempts = 100;
        $attempt_count = 0;
        do {
            $new_user_id = rand(10000000, 99999999);
            $check = $conn->query("SELECT 1 FROM users WHERE user_id = $new_user_id");
            $attempt_count++;
            if ($attempt_count > $max_attempts) {
                throw new Exception("Unable to generate unique user ID. Please try again.");
            }
        } while ($check && $check->num_rows > 0);

        // Find placement
        $placement = findGlobalLevelWisePlacement($conn, $root_id);
        
        if (!$placement['success']) {
            throw new Exception($placement['message']);
        }

        $placement_id = $placement['placement_id'];
        $position = $placement['position'];

        // Insert new user
        $insert = $conn->prepare("INSERT INTO users (
            user_id, name, email, mobile, password, sponsor_id, placement_id,
            left_1_id, left_2_id, right_1_id, right_2_id, wallet, rank, joining_date, status, pin_used
        ) VALUES (?, ?, ?, ?, ?, ?, ?, 0, 0, 0, 0, 0, 'Bronze', NOW(), 1, ?)");
        
        $insert->bind_param("isssisss", $new_user_id, $name, $email, $phone, $hashed_password, $sponsor_id, $placement_id, $pin);
        
        if (!$insert->execute()) {
            throw new Exception("Failed to create user account");
        }

        // Update parent's position
        $update_parent = $conn->prepare("UPDATE users SET $position = ? WHERE user_id = ?");
        $update_parent->bind_param("ii", $new_user_id, $placement_id);
        
        if (!$update_parent->execute()) {
            throw new Exception("Failed to update placement");
        }

        // Update PIN status
        $update_pin = $conn->prepare("UPDATE pin SET status = '1', used_by = ?, used_at = NOW() WHERE pin_value = ?");
        $update_pin->bind_param("is", $new_user_id, $pin);
        
        if (!$update_pin->execute()) {
            throw new Exception("Failed to update PIN status");
        }

        // Record sponsor income (if applicable)
        recordSponsorIncome($conn, $sponsor_id, $new_user_id, 500, "Sponsor Commission for new member");

        $conn->commit();
        
        // Clear rate limiting for successful registration
        if (file_exists($rate_limit_file)) {
            unlink($rate_limit_file);
        }
        
        // Send welcome email (if configured)
        // sendWelcomeEmail($email, $name, $new_user_id);
        
        $success_message = "Registration successful! Your User ID is: $new_user_id. Please login with your password.";
        
        // Add flag to indicate new registration for localStorage
        $success_message .= "&new_registration=1";
        
        header("Location: ../register.php?success=" . urlencode($success_message));
        exit();

    } catch (Exception $e) {
        $conn->rollback();
        error_log("Registration Error: " . $e->getMessage());
        header("Location: ../register.php?error=" . urlencode($e->getMessage()));
        exit();
    }
} else {
    header("Location: ../register.php");
    exit();
}

// Include placement functions (same as before)
function findGlobalLevelWisePlacement($conn, $root_id) {
    $positions = ['left_1_id', 'left_2_id', 'right_1_id', 'right_2_id'];
    
    // Check root's direct slots first
    $root_result = $conn->query("SELECT left_1_id, left_2_id, right_1_id, right_2_id FROM users WHERE user_id = $root_id");
    if (!$root_result) {
        return ['success' => false, 'message' => 'Error checking root'];
    }
    $root = $root_result->fetch_assoc();
    
    foreach ($positions as $pos) {
        if (isset($root[$pos]) && $root[$pos] == 0) {
            return [
                'success' => true,
                'placement_id' => $root_id,
                'position' => $pos,
                'level' => 0
            ];
        }
    }
    
    // Get tree by level
    $treeByLevel = getGlobalTreeByLevel($conn, $root_id);
    $currentLevel = 1;
    
    while ($currentLevel <= 25) {
        
        if (!isset($treeByLevel[$currentLevel]) || empty($treeByLevel[$currentLevel])) {
            $prevLevel = $currentLevel - 1;
            
            if (isset($treeByLevel[$prevLevel])) {
                foreach ($treeByLevel[$prevLevel] as $nodeId) {
                    $node_result = $conn->query("SELECT left_1_id, left_2_id, right_1_id, right_2_id FROM users WHERE user_id = $nodeId");
                    if (!$node_result) continue;
                    $node = $node_result->fetch_assoc();
                    
                    foreach ($positions as $pos) {
                        if (isset($node[$pos]) && $node[$pos] == 0) {
                            return [
                                'success' => true,
                                'placement_id' => $nodeId,
                                'position' => $pos,
                                'level' => $prevLevel
                            ];
                        }
                    }
                }
            }
            
            $currentLevel++;
            continue;
        }
        
        $levelNodes = $treeByLevel[$currentLevel];
        $nodeFillCounts = [];
        
        foreach ($levelNodes as $nodeId) {
            $node_result = $conn->query("SELECT left_1_id, left_2_id, right_1_id, right_2_id FROM users WHERE user_id = $nodeId");
            if (!$node_result) continue;
            $node = $node_result->fetch_assoc();
            
            $filledCount = 0;
            foreach ($positions as $pos) {
                if (isset($node[$pos]) && $node[$pos] != 0) {
                    $filledCount++;
                }
            }
            
            if ($filledCount < 4) {
                $nodeFillCounts[$nodeId] = $filledCount;
            }
        }
        
        if (empty($nodeFillCounts)) {
            $currentLevel++;
            continue;
        }
        
        $minFill = min($nodeFillCounts);
        $candidateNodes = [];
        
        foreach ($nodeFillCounts as $nodeId => $fillCount) {
            if ($fillCount == $minFill) {
                $candidateNodes[] = $nodeId;
            }
        }
        
        foreach ($candidateNodes as $nodeId) {
            $node_result = $conn->query("SELECT left_1_id, left_2_id, right_1_id, right_2_id FROM users WHERE user_id = $nodeId");
            if (!$node_result) continue;
            $node = $node_result->fetch_assoc();
            
            foreach ($positions as $pos) {
                if (isset($node[$pos]) && $node[$pos] == 0) {
                    return [
                        'success' => true,
                        'placement_id' => $nodeId,
                        'position' => $pos,
                        'level' => $currentLevel
                    ];
                }
            }
        }
        
        $currentLevel++;
    }
    
    return [
        'success' => false,
        'message' => 'Maximum tree depth reached. No positions available.'
    ];
}

function getGlobalTreeByLevel($conn, $root_id) {
    $treeByLevel = [];
    $queue = [[$root_id, 0]];
    $visited = [];
    $positions = ['left_1_id', 'left_2_id', 'right_1_id', 'right_2_id'];
    
    while (!empty($queue)) {
        list($current_id, $level) = array_shift($queue);
        
        if (in_array($current_id, $visited)) {
            continue;
        }
        $visited[] = $current_id;
        
        if (!isset($treeByLevel[$level])) {
            $treeByLevel[$level] = [];
        }
        $treeByLevel[$level][] = $current_id;
        
        $user_result = $conn->query("SELECT user_id, left_1_id, left_2_id, right_1_id, right_2_id FROM users WHERE user_id = $current_id");
        if (!$user_result) continue;
        $user = $user_result->fetch_assoc();
        
        if ($user) {
            foreach ($positions as $pos) {
                if (isset($user[$pos]) && !empty($user[$pos]) && $user[$pos] != 0) {
                    $queue[] = [(int)$user[$pos], $level + 1];
                }
            }
        }
    }
    
    return $treeByLevel;
}

function recordSponsorIncome($conn, $sponsor_id, $new_user_id, $amount, $description) {
    $transaction_id = 'SPR' . time() . rand(100, 999);
    
    // Get balance before
    $balance_query = $conn->query("SELECT wallet FROM users WHERE user_id = $sponsor_id");
    $balance_before = $balance_query->fetch_assoc()['wallet'];
    $balance_after = $balance_before + $amount;
    
    // Update sponsor's wallet
    $conn->query("UPDATE users SET wallet = wallet + $amount WHERE user_id = $sponsor_id");
    
    // Record income
    $insert = $conn->prepare("INSERT INTO income_history (
        user_id, amount, description, credit_debit, admin_charges, tds,
        from_user_id, to_user_id, income_type, transaction_id,
        balance_before, balance_after, processed_at
    ) VALUES (?, ?, ?, 0, 0, 0, ?, ?, 'Sponsor Commission', ?, ?, ?, NOW())");
    
    $insert->bind_param("idsiissd", $sponsor_id, $amount, $description, $new_user_id, $sponsor_id, $transaction_id, $balance_before, $balance_after);
    $insert->execute();
}
?>