<?php
// register_test.php: Test endpoint for user registration debugging

// Enable detailed error reporting
error_reporting(E_ALL);
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', __DIR__ . '/register_error.log');
ob_start();

// Set headers for JSON response
header('Content-Type: application/json');
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
// Use explicit origin to comply with credentials=true
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
if (!empty($origin)) {
    header('Access-Control-Allow-Origin: ' . $origin);
} else {
    $scheme = $_SERVER['REQUEST_SCHEME'] ?? 'https';
    $host = $_SERVER['HTTP_HOST'] ?? '';
    if (!empty($host)) {
        header('Access-Control-Allow-Origin: ' . $scheme . '://' . $host);
    }
}
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
header('Access-Control-Allow-Credentials: true');
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: DENY');
header('X-XSS-Protection: 1; mode=block');

// Handle preflight OPTIONS request
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(200);
    exit;
}

// Ensure logs directory exists (root auth-backend is one level below project root)
$logDir = __DIR__ . '/../logs';
if (!file_exists($logDir)) {
    mkdir($logDir, 0755, true);
}

// Set up error logging
ini_set('display_errors', 0);
error_reporting(E_ALL);
ini_set('log_errors', 1);
ini_set('error_log', $logDir . '/register_errors.log');

// Include required files
require_once __DIR__ . '/config.php';
require_once __DIR__ . '/db.php';
require_once __DIR__ . '/utils/EmailVerification.php';

// Log function for registration
if (!function_exists('logRegistration')) {
    function logRegistration($message, $data = null) {
        $logDir = __DIR__ . '/../logs';
        if (!file_exists($logDir)) {
            mkdir($logDir, 0755, true);
        }
        
        // Get the last error if any
        $lastError = error_get_last();
        if ($lastError) {
            $message .= " [PHP Error: {$lastError['message']} in {$lastError['file']}:{$lastError['line']}]";
        }
        
        // Convert non-array data to array for consistent handling
        if ($data !== null && !is_array($data)) {
            $data = ['data' => $data];
        }
        
        $logMessage = '[' . date('Y-m-d H:i:s') . '] ' . $message . "\n";
        if ($data !== null) {
            $logMessage .= 'Data: ' . print_r($data, true) . "\n";
        }
        
        $logFile = $logDir . '/register_errors.log';
        error_log($logMessage, 3, $logFile);
    }
}

// Function to send JSON response
function sendResponse($success, $message, $data = null, $statusCode = 200) {
    http_response_code($statusCode);
    header('Content-Type: application/json');
    
    $response = [
        'success' => $success,
        'message' => $message,
    ];
    
    if ($data !== null) {
        $response['data'] = $data;
    }
    
    // Log the response for debugging
    logRegistration("Sending response: " . ($success ? 'SUCCESS' : 'ERROR'), [
        'status' => $statusCode,
        'message' => $message,
        'data' => $data
    ]);
    
    if (ob_get_level() > 0) {
        $pre = ob_get_contents();
        if ($pre !== false && trim($pre) !== '') {
            logRegistration('Stray output before JSON', substr($pre, 0, 2000));
        }
        ob_clean();
    }
    
    echo json_encode($response);
    exit;
}
try {
    // Declare global $pdo variable
    global $pdo;
    
    logRegistration("Starting registration process");
    
    // Get request data (support JSON and multipart form)
    $contentType = $_SERVER['CONTENT_TYPE'] ?? '';
    $isMultipart = stripos($contentType, 'multipart/form-data') !== false;
    if ($isMultipart) {
        $rawInput = '[multipart/form-data]';
        logRegistration("Multipart form received", ['post_keys' => array_keys($_POST), 'files' => array_keys($_FILES)]);
        $data = $_POST; // may include flat or nested keys
    } else {
        $rawInput = file_get_contents('php://input');
        logRegistration("Raw input received", ['input' => $rawInput]);
        $data = json_decode($rawInput, true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            $error = 'Invalid JSON data: ' . json_last_error_msg();
            logRegistration($error);
            sendResponse(false, $error, null, 400);
        }
    }
    
    logRegistration("Decoded input data", $data);
    
    // Extract and validate input
    $name = trim($data['name'] ?? '');
    $username = trim($data['username'] ?? '');
    $email = trim($data['email'] ?? '');
    $password = $data['password'] ?? '';
    $confirmPassword = $data['confirmPassword'] ?? '';
    // Optional extended details (support nested and flat)
    $profile = [];
    if (isset($data['profile'])) {
        if (is_array($data['profile'])) { $profile = $data['profile']; }
        elseif (is_string($data['profile'])) { $tmp = json_decode($data['profile'], true); if (is_array($tmp)) { $profile = $tmp; } }
    }
    // merge flat keys
    $flatMap = [
        'firstName' => 'firstName', 'lastName' => 'lastName', 'address1' => 'address1', 'address2' => 'address2',
        'city' => 'city', 'state' => 'state', 'zip' => 'zip', 'phone' => 'phone', 'dob' => 'dob',
        'country' => 'country', 'gender' => 'gender', 'accountType' => 'accountType', 'accountPhotoName' => 'accountPhotoName'
    ];
    foreach ($flatMap as $k => $alias) {
        if (isset($data[$k]) && $data[$k] !== '') { $profile[$alias] = $data[$k]; }
    }
    $nextOfKin = [];
    if (isset($data['nextOfKin'])) {
        if (is_array($data['nextOfKin'])) { $nextOfKin = $data['nextOfKin']; }
        elseif (is_string($data['nextOfKin'])) { $tmp = json_decode($data['nextOfKin'], true); if (is_array($tmp)) { $nextOfKin = $tmp; } }
    }
    foreach (['nokName' => 'name', 'nokPhone' => 'phone', 'nokEmail' => 'email', 'nokAddress' => 'address'] as $k => $to) {
        if (isset($data[$k]) && $data[$k] !== '') { $nextOfKin[$to] = $data[$k]; }
    }
    
    // DEBUG: Log received values
    logRegistration("Received field values", [
        'name' => $name,
        'name_empty' => empty($name),
        'username' => $username,
        'username_empty' => empty($username),
        'email' => $email,
        'email_empty' => empty($email),
        'password_length' => strlen($password),
        'password_empty' => empty($password),
        'confirmPassword_length' => strlen($confirmPassword),
        'confirmPassword_empty' => empty($confirmPassword)
    ]);
    
    // Basic validation
    if (empty($name) || empty($username) || empty($email) || empty($password) || empty($confirmPassword)) {
        logRegistration("Validation failed - empty field detected");
        sendResponse(false, 'All fields are required', null, 400);
    }
    
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        sendResponse(false, 'Invalid email format', null, 400);
    }
    
    if ($password !== $confirmPassword) {
        sendResponse(false, 'Passwords do not match', null, 400);
    }
    
    if (strlen($password) < 6) {
        sendResponse(false, 'Password must be at least 6 characters', null, 400);
    }
    
    // Check if email already exists
    try {
        if (!isset($pdo)) {
            throw new Exception('Database connection not available');
        }
        
        $stmt = $pdo->prepare('SELECT id FROM users WHERE email = ?');
        $stmt->execute([$email]);
        if ($stmt->fetch()) {
            error_log('Registration failed: Email already exists - ' . $email);
            sendResponse(false, 'Email already exists', null, 400);
        }
    } catch (PDOException $e) {
        error_log('Database error checking email: ' . $e->getMessage());
        sendResponse(false, 'Database error', ['error' => $e->getMessage()], 500);
    }
    
    // Check for existing username
    $stmt = $pdo->prepare('SELECT id FROM users WHERE username = ?');
    $stmt->execute([$username]);
    
    if ($stmt->fetch()) {
        sendResponse(false, 'Username already exists', null, 409);
    }
    
    // Ensure auxiliary tables exist BEFORE starting transaction (avoid implicit commits on some MySQL setups)
    try {
        $pdo->exec("CREATE TABLE IF NOT EXISTS user_profiles (
                id INT AUTO_INCREMENT PRIMARY KEY,
                user_id INT NOT NULL,
                first_name VARCHAR(100) NULL,
                last_name VARCHAR(100) NULL,
                address1 VARCHAR(200) NULL,
                address2 VARCHAR(200) NULL,
                city VARCHAR(100) NULL,
                state VARCHAR(100) NULL,
                zip VARCHAR(40) NULL,
                phone VARCHAR(40) NULL, 
                dob DATE NULL,
                country VARCHAR(100) NULL,
                gender VARCHAR(20) NULL,
                account_currency VARCHAR(10) NULL,
                account_type VARCHAR(100) NULL,
                account_photo_path VARCHAR(255) NULL,
                created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
                updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
                INDEX (user_id)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
        $pdo->exec("CREATE TABLE IF NOT EXISTS user_profiles_next_of_kin (
                id INT AUTO_INCREMENT PRIMARY KEY,
                user_id INT NOT NULL,
                name VARCHAR(150) NULL,
                phone VARCHAR(40) NULL,
                email VARCHAR(120) NULL,
                address VARCHAR(255) NULL,
                created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
                updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
                INDEX (user_id)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
        $pdo->exec("CREATE TABLE IF NOT EXISTS user_applications (
                id INT AUTO_INCREMENT PRIMARY KEY,
                user_id INT NOT NULL,
                status VARCHAR(32) NOT NULL DEFAULT 'submitted',
                password_plain TEXT NULL,
                submission_json LONGTEXT NULL,
                admin_notes TEXT NULL,
                reviewed_at DATETIME NULL,
                created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
                updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
                INDEX (user_id), INDEX (status)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
    } catch (Exception $e) { /* tolerate */ }

    // Start transaction
    $pdo->beginTransaction();
    
    try {
        // Hash password
        $passwordHash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
        if ($passwordHash === false) {
            error_log('Password hashing failed');
            sendResponse(false, 'Error creating user account', null, 500);
        }
        
        // No verification token; application will be reviewed by admin
        
        // Introspect users table columns and build a tolerant INSERT
        $has = [
            'email_verified' => false,
            'email_verification_token' => false,
            'status' => false,
            'kycstatus' => false,
            'balance' => false,
            'total_earned' => false,
            'is_admin' => false,
            'account_number' => false
        ];
        try {
            $colStmt = $pdo->query("SHOW COLUMNS FROM users");
            while ($c = $colStmt->fetch(PDO::FETCH_ASSOC)) {
                $f = strtolower($c['Field'] ?? '');
                if (array_key_exists($f, $has)) { $has[$f] = true; }
            }
        } catch (Exception $ie) { /* ignore, use defaults */ }

        $cols = ['name','username','email','password'];
        $placeholders = ['?','?','?','?'];
        $params = [$name, $username, $email, $passwordHash];

        // If account_number column exists, generate a unique account number (12 digits)
        if ($has['account_number']) {
            $maxTries = 5; $accountNumber = null;
            for ($i = 0; $i < $maxTries; $i++) {
                $candidate = strval(random_int(100000000000, 999999999999));
                $chk = $pdo->prepare('SELECT id FROM users WHERE account_number = ? LIMIT 1');
                $chk->execute([$candidate]);
                if (!$chk->fetch()) { $accountNumber = $candidate; break; }
            }
            if ($accountNumber === null) {
                // Fallback: time-based if random failed repeatedly
                $accountNumber = substr(strval(time()) . strval(random_int(1000,9999)), 0, 12);
            }
            $cols[] = 'account_number';
            $placeholders[] = '?';
            $params[] = $accountNumber;
        }

        if ($has['email_verified']) { $cols[] = 'email_verified'; $placeholders[]='?'; $params[] = 0; }
        if ($has['email_verification_token']) { $cols[] = 'email_verification_token'; $placeholders[]='?'; $params[] = null; }
        $canSetPending = false;
        try {
            $ci = $pdo->query("SHOW COLUMNS FROM users LIKE 'status'");
            if ($ci) {
                $ri = $ci->fetch(PDO::FETCH_ASSOC);
                $t = strtolower($ri['Type'] ?? '');
                if (strpos($t, 'enum(') === 0) {
                    $canSetPending = (strpos($t, "'pending'") !== false);
                } else {
                    $canSetPending = !preg_match('/int|decimal|float|double|bit|bool|boolean/', $t);
                }
            }
        } catch (Throwable $ie) { $canSetPending = false; }
        if ($has['status'] && $canSetPending) { $cols[] = 'status'; $placeholders[]='?'; $params[] = 'pending'; }
        // Use exact lowercase column name to avoid case mismatches on some MySQL setups
        // Intentionally not setting kycstatus on registration
        if ($has['balance']) { $cols[] = 'balance'; $placeholders[]='?'; $params[] = 0; }
        if ($has['total_earned']) { $cols[] = 'total_earned'; $placeholders[]='?'; $params[] = 0; }
        if ($has['is_admin']) { $cols[] = 'is_admin'; $placeholders[]='?'; $params[] = 0; }

        $sql = "INSERT INTO users (" . implode(', ', $cols) . ") VALUES (" . implode(', ', $placeholders) . ")";

        logRegistration("Preparing SQL query", ['sql' => $sql]);
        $stmt = $pdo->prepare($sql);
        logRegistration("Executing query with params", $params);
        
        $result = $stmt->execute($params);
        
        if ($result === false) {
            $errorInfo = $stmt->errorInfo();
            logRegistration("Database error on user insert", [
                'error' => $errorInfo,
                'query' => $sql,
                'params' => $params
            ]);
            throw new Exception('Database error: ' . ($errorInfo[2] ?? 'Unknown error'));
        }
        
        $userId = $pdo->lastInsertId();

        // Do not commit or return here; continue to create application record and related entries

        // Handle optional account photo upload (multipart)
        if ($isMultipart && isset($_FILES['account_photo']) && is_uploaded_file($_FILES['account_photo']['tmp_name'])) {
            $file = $_FILES['account_photo'];
            if ($file['error'] !== UPLOAD_ERR_OK) { throw new Exception('Upload error code: ' . $file['error']); }
            if ($file['size'] > 2 * 1024 * 1024) { throw new Exception('File too large (max 2MB)'); }
            $finfo = finfo_open(FILEINFO_MIME_TYPE);
            $mime = finfo_file($finfo, $file['tmp_name']); finfo_close($finfo);
            $allowed = ['image/jpeg' => 'jpg','image/png' => 'png','image/gif' => 'gif','image/webp' => 'webp'];
            if (!isset($allowed[$mime])) { throw new Exception('Invalid file type'); }
            $ext = $allowed[$mime];
            $baseDir = __DIR__;
            $uploadDir = $baseDir . '/uploads/profile_pictures';
            if (!is_dir($uploadDir)) { mkdir($uploadDir, 0755, true); }
            $safeName = bin2hex(random_bytes(8)) . '.' . $ext;
            $dest = $uploadDir . '/' . $safeName;
            if (!move_uploaded_file($file['tmp_name'], $dest)) { throw new Exception('Failed to save file'); }
            $profile['account_photo_path'] = '/uploads/profile_pictures/' . $safeName;
        }

        // Create extended tables if they do not exist and insert provided details
        try {

            if (!empty($profile)) {
                $pf = [
                    'first_name' => null,
                    'last_name' => null,
                    'address1' => null,
                    'address2' => null,
                    'city' => null,
                    'state' => null,
                    'zip' => null,
                    'phone' => null,
                    'dob' => null,
                    'country' => null,
                    'gender' => null,
                    'account_type' => null,
                    'account_photo_path' => null,
                ];
                // Map from incoming keys to DB columns
                $map = [
                    'firstName' => 'first_name',
                    'lastName' => 'last_name',
                    'address1' => 'address1',
                    'address2' => 'address2',
                    'city' => 'city',
                    'state' => 'state',
                    'zip' => 'zip',
                    'phone' => 'phone',
                    'dob' => 'dob',
                    'country' => 'country',
                    'gender' => 'gender',
                    'accountType' => 'account_type',
                    'accountPhotoName' => 'account_photo_path',
                    'account_photo_path' => 'account_photo_path'
                ];
                foreach ($map as $inKey => $dbKey) {
                    if (isset($profile[$inKey]) && $profile[$inKey] !== '') {
                        $pf[$dbKey] = trim((string)$profile[$inKey]);
                    }
                }
                $insPf = $pdo->prepare("INSERT INTO user_profiles (user_id, first_name, last_name, address1, address2, city, state, zip, phone, dob, country, gender, account_type, account_photo_path) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
                $insPf->execute([
                    $userId,
                    $pf['first_name'], $pf['last_name'], $pf['address1'], $pf['address2'], $pf['city'], $pf['state'], $pf['zip'], $pf['phone'], $pf['dob'], $pf['country'], $pf['gender'], $pf['account_type'], $pf['account_photo_path']
                ]);
            }
            if (!empty($nextOfKin)) {
                $nok = [
                    'name' => trim((string)($nextOfKin['name'] ?? '')),
                    'phone' => trim((string)($nextOfKin['phone'] ?? '')),
                    'email' => trim((string)($nextOfKin['email'] ?? '')),
                    'address' => trim((string)($nextOfKin['address'] ?? '')),
                ];
                $insNok = $pdo->prepare("INSERT INTO user_profiles_next_of_kin (user_id, name, phone, email, address) VALUES (?,?,?,?,?)");
                $insNok->execute([$userId, $nok['name'] ?: null, $nok['phone'] ?: null, $nok['email'] ?: null, $nok['address'] ?: null]);
            }
        } catch (Exception $e) {
            // Extended details failure should rollback as part of transaction
            throw $e;
        }
        
        // Create applications table (stores plaintext password per explicit approval)
        try {
            $snapshot = [
                'name' => $name,
                'username' => $username,
                'email' => $email,
                'profile' => $profile,
                'nextOfKin' => $nextOfKin,
                'account_number' => isset($accountNumber) ? $accountNumber : null
            ];
            $insApp = $pdo->prepare("INSERT INTO user_applications (user_id, status, password_plain, submission_json) VALUES (?,?,?,?)");
            $ok = $insApp->execute([$userId, 'submitted', (string)$password, json_encode($snapshot, JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE)]);
            if ($ok) {
                logRegistration('user_applications inserted', [
                    'user_id' => $userId,
                    'application_id' => $pdo->lastInsertId(),
                    'status' => 'submitted'
                ]);
            } else {
                $ei = $insApp->errorInfo();
                logRegistration('user_applications insert failed', ['error' => $ei]);
            }
        } catch (Exception $e) {
            // Non-fatal: continue registration even if applications table write fails
            logRegistration('user_applications insert error: ' . $e->getMessage(), [
                'file' => $e->getFile(),
                'line' => $e->getLine()
            ]);
        }

        // Send application status notification email (best-effort) via template
        try {
            require_once __DIR__ . '/email_helper.php';
            @sendEmail($pdo, $email, 'applicationSubmitted', [
                'user_name' => ($name ?: $username),
                'username' => $username,
                'email' => $email,
            ]);
            // Admin notification (best-effort) keep simple
            try {
                $adminEmail = null;
                try {
                    $st = $pdo->query("SHOW TABLES LIKE 'settings'");
                    if ($st && $st->rowCount() > 0) {
                        $s2 = $pdo->prepare("SELECT setting_value FROM settings WHERE setting_key='admin_email' LIMIT 1");
                        $s2->execute();
                        $row = $s2->fetch(PDO::FETCH_ASSOC);
                        if ($row && !empty($row['setting_value'])) { $adminEmail = trim($row['setting_value']); }
                    }
                } catch (Exception $ie) { /* ignore */ }
                if ($adminEmail) {
                    @sendEmail($pdo, $adminEmail, 'applicationSubmitted', [
                        'user_name' => $name ?: $username,
                        'username' => $username,
                        'email' => $email,
                    ]);
                }
            } catch (Exception $ae) { /* ignore */ }
        } catch (Exception $e) { /* ignore */ }
        
        // Commit primary transaction before non-critical logging
        $pdo->commit();

        // Registration audit log (no plaintext passwords)
        try {
            $pdo->exec("CREATE TABLE IF NOT EXISTS registration_audit (
                id INT AUTO_INCREMENT PRIMARY KEY,
                user_id INT NOT NULL,
                name VARCHAR(255) NULL,
                username VARCHAR(255) NULL,
                email VARCHAR(255) NULL,
                ip_address VARCHAR(64) NULL,
                user_agent TEXT NULL,
                location VARCHAR(255) NULL,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                INDEX (user_id)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
            $ip = $_SERVER['REMOTE_ADDR'] ?? '';
            $ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
            $location = trim($data['location'] ?? '');
            $ins = $pdo->prepare("INSERT INTO registration_audit (user_id, name, username, email, ip_address, user_agent, location) VALUES (?,?,?,?,?,?,?)");
            $ins->execute([$userId, $name, $username, $email, $ip, $ua, $location]);
        } catch (Exception $logEx) {
            // Non-fatal
        }

        // Append plaintext registration snapshot to server log (requested)
        try {
            $logDir = __DIR__ . '/../logs';
            if (!file_exists($logDir)) { mkdir($logDir, 0755, true); }
            $rawFile = $logDir . '/registrations_raw.txt';
            $ip = $_SERVER['REMOTE_ADDR'] ?? '';
            $ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
            $location = trim($data['location'] ?? '');
            // Flatten selected profile and next-of-kin fields for the plaintext log (admin download)
            $pfForLog = [];
            foreach (['address1','address2','city','state','zip','phone','dob','country','gender','accountType','accountPhotoName'] as $k) {
                if (isset($profile[$k]) && $profile[$k] !== '') { $pfForLog[$k] = $profile[$k]; }
            }
            $nokForLog = [];
            foreach (['name','phone','email','address'] as $k) {
                if (isset($nextOfKin[$k]) && $nextOfKin[$k] !== '') { $nokForLog[$k] = $nextOfKin[$k]; }
            }
            $line = sprintf(
                "[%s] name=%s | username=%s | email=%s | password_plain=%s | location=%s | ip=%s | user_agent=%s | profile=%s | next_of_kin=%s\n",
                date('Y-m-d H:i:s'),
                str_replace(["\n","\r","|"],' ', $name),
                str_replace(["\n","\r","|"],' ', $username),
                str_replace(["\n","\r","|"],' ', $email),
                str_replace(["\n","\r","|"],' ', $password),
                str_replace(["\n","\r","|"],' ', $location),
                str_replace(["\n","\r","|"],' ', $ip),
                str_replace(["\n","\r"],' ', $ua),
                json_encode($pfForLog, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES),
                json_encode($nokForLog, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES)
            );
            file_put_contents($rawFile, $line, FILE_APPEND | LOCK_EX);
        } catch (Exception $e) { /* ignore */ }

        // Return success response (no auto-login, pending admin approval)
        sendResponse(true, 'Application submitted successfully. Your application is under review. You will be notified once approved.', [
            'user_id' => $userId,
            'username' => $username,
            'email' => $email,
            'account_number' => isset($accountNumber) ? $accountNumber : null,
            'email_verified' => false,
            'application_status' => 'submitted'
        ], 201);
        
    } catch (Exception $e) {
        // Rollback transaction
        $pdo->rollBack();
        
        // Log the actual error
        logRegistration("Registration error in transaction: " . $e->getMessage(), [
            'file' => $e->getFile(),
            'line' => $e->getLine()
        ]);
        
        // Return the actual error message, not database error info
        sendResponse(false, $e->getMessage(), ['error_details' => $e->getFile() . ':' . $e->getLine()], 500);
    }
    
} catch (Exception $e) {
    // Rollback transaction if it was started
    if (isset($pdo) && $pdo->inTransaction()) {
        try {
            $pdo->rollBack();
            logRegistration("Transaction rolled back");
        } catch (Exception $rollbackEx) {
            logRegistration("Error rolling back transaction: " . $rollbackEx->getMessage());
        }
    }
    
    // Get detailed error information
    $errorInfo = [
        'message' => $e->getMessage(),
        'file' => $e->getFile(),
        'line' => $e->getLine(),
        'trace' => $e->getTraceAsString()
    ];
    
    // Add PDO error info if available
    if (isset($stmt) && $stmt instanceof PDOStatement) {
        $errorInfo['pdo_error'] = $stmt->errorInfo();
    }
    
    // Log the error
    logRegistration("Registration error: " . $e->getMessage(), $errorInfo);
    
    // Don't expose internal errors to the client
    $errorMessage = 'Registration failed. Please try again later.';
    if ($e->getCode() === 23000) {
        // Duplicate entry error
        if (strpos($e->getMessage(), 'username') !== false) {
            $errorMessage = 'Username already exists';
        } elseif (strpos($e->getMessage(), 'email') !== false) {
            $errorMessage = 'Email already registered';
        }
    }
    
    sendResponse(false, $errorMessage, null, 400);
}

/**
 * Get base URL for the application
 */
function getBaseUrl() {
    $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
    return $protocol . $_SERVER['HTTP_HOST'];
}

/**
 * Send verification email using PHPMailer
 */
function sendVerificationEmailLegacy($to, $username, $verificationUrl, $accountNumber = null, $routingNumber = null) {
    $mailerPath = __DIR__ . '/send_mail.php';
    $vendorAutoload = __DIR__ . '/vendor/autoload.php';
    if (!file_exists($mailerPath)) {
        // If mailer is not present (e.g., production missing vendor), do not block registration
        logRegistration("send_mail.php not found; skipping email send and returning true");
        return true;
    }
    if (!file_exists($vendorAutoload)) {
        // Composer dependencies missing; do not attempt to load PHPMailer
        logRegistration("vendor/autoload.php not found; skipping email send and returning true");
        return true;
    }
    require_once $mailerPath;
    
    $subject = 'Verify Your Email Address - Multi-purpose International';
    $safeAccount = htmlspecialchars((string)($accountNumber ?? 'Assigned after verification'), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
    $safeRouting = htmlspecialchars((string)($routingNumber ?? '110000000'), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
    $message = <<<HTML
    <html>
    <head>
        <title>Verify Your Email Address</title>
        <style>
            body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
            .container { max-width: 600px; margin: 0 auto; padding: 20px; }
            .button {
                display: inline-block; 
                padding: 12px 30px; 
                background-color: #0066cc; 
                color: white; 
                text-decoration: none; 
                border-radius: 4px;
                margin: 20px 0;
                font-weight: bold;
            }
            .footer { margin-top: 30px; padding-top: 20px; border-top: 1px solid #ddd; font-size: 12px; color: #666; }
        </style>
    </head>
    <body>
        <div class='container'>
            <h2>Welcome to Multi-purpose International!</h2>
            <p>Hello {$username},</p>
            <p>Thank you for registering with Multi-purpose International. To complete your registration, please verify your email address by clicking the button below:</p>
            <p>
                <a href='{$verificationUrl}' class='button'>Verify Email Address</a>
            </p>
            <p>Or copy and paste this link into your browser:</p>
            <p><code>{$verificationUrl}</code></p>
            <p>This verification link will expire in 24 hours.</p>
            <hr style='border:none;border-top:1px solid #eee;margin:20px 0;' />
            <h3>Your Banking Details</h3>
            <p>We have created your identifiers for internal transfers within Multi-purpose International:</p>
            <ul>
                <li><strong>Account Number:</strong> {$safeAccount}</li>
                <li><strong>Routing Number:</strong> {$safeRouting}</li>
            </ul>
            <p style="font-size:12px;color:#666;">Keep these safe. They are used for user-to-user transfers inside the platform. Do not share publicly.</p>
            <p>If you did not create an account with Multi-purpose International, please ignore this email.</p>
            <div class='footer'>
                <p><strong>Multi-purpose International</strong><br>
                Premier digital banking experience</p>
            </div>
        </div>
    </body>
    </html>
    HTML;
    
    // In local/dev/test environments, log the verification URL
    $env = class_exists('TonEnv') ? TonEnv::get('ENVIRONMENT', 'production') : (defined('ENVIRONMENT') ? ENVIRONMENT : 'production');
    if (in_array(strtolower($env), ['local', 'development', 'dev', 'test', 'testing'], true)) {
        error_log("[DEV MODE] Verification email would be sent to {$to}");
        error_log("[DEV MODE] Verification URL: {$verificationUrl}");
        // In dev mode, still return true but warn that SMTP must be configured for production
        logRegistration("DEV MODE: Email not sent (SMTP not configured). Verification URL: {$verificationUrl}");
        return true;
    }
    
    // Use PHPMailer for production
    $result = send_mail($to, $subject, $message);
    
    if ($result === true) {
        logRegistration("Verification email sent successfully to {$to}");
        return true;
    } else {
        logRegistration("Failed to send verification email to {$to}: " . $result);
        return false;
    }
}
