<?php
/**
 * EdumacFlo Automated Web Installer Engine
 * -------------------------------------------------------------
 * Supports both Multi-Tenant SaaS and Single-Tenant Deployments.
 */

class Installer
{
    private static $lockFile = __DIR__ . '/installed.lock';

    /**
     * Check if application is already installed.
     */
    public static function isInstalled(): bool
    {
        return file_exists(self::$lockFile) || file_exists(dirname(__DIR__) . '/install.lock');
    }

    /**
     * Verify PHP environment, extensions, and directory permissions.
     */
    public static function checkRequirements(): array
    {
        $requirements = [];
        $allPassed = true;

        // PHP Version Check (>= 7.4, recommended 8.0 - 8.3)
        $phpVersion = PHP_VERSION;
        $phpOk = version_compare($phpVersion, '7.4.0', '>=');
        if (!$phpOk) $allPassed = false;
        $requirements[] = [
            'key'         => 'php_version',
            'name'        => 'PHP Version',
            'required'    => '>= 7.4.0',
            'current'     => $phpVersion,
            'status'      => $phpOk ? 'pass' : 'fail',
            'critical'    => true,
            'description' => 'PHP 7.4+ is required; PHP 8.0–8.2 is recommended.',
        ];

        // Required PHP Extensions
        $requiredExtensions = [
            'mysqli'   => ['name' => 'MySQLi Driver', 'critical' => true, 'desc' => 'Required for high-performance database operations.'],
            'pdo'      => ['name' => 'PDO Core', 'critical' => true, 'desc' => 'Required for database abstraction and query sanitization.'],
            'pdo_mysql'=> ['name' => 'PDO MySQL Driver', 'critical' => true, 'desc' => 'Required for PDO MySQL connections.'],
            'mbstring' => ['name' => 'Multibyte String (mbstring)', 'critical' => true, 'desc' => 'Required for Unicode and multi-language school names.'],
            'curl'     => ['name' => 'cURL Extension', 'critical' => true, 'desc' => 'Required for Payment Gateway API (Paystack / Flutterwave) communications.'],
            'openssl'  => ['name' => 'OpenSSL Extension', 'critical' => true, 'desc' => 'Required for secure cryptographic token & password generation.'],
            'json'     => ['name' => 'JSON Extension', 'critical' => true, 'desc' => 'Required for subscription module entitlement parsing.'],
            'gd'       => ['name' => 'GD Graphics Library', 'critical' => false, 'desc' => 'Required for student ID photo resizing and school badges.'],
            'zip'      => ['name' => 'ZipArchive Extension', 'critical' => false, 'desc' => 'Required for backup generation and automated schema upgrades.'],
        ];

        foreach ($requiredExtensions as $ext => $info) {
            $loaded = extension_loaded($ext);
            if (!$loaded && $info['critical']) {
                $allPassed = false;
            }
            $requirements[] = [
                'key'         => 'ext_' . $ext,
                'name'        => $info['name'],
                'required'    => 'Enabled',
                'current'     => $loaded ? 'Enabled' : 'Missing',
                'status'      => $loaded ? 'pass' : ($info['critical'] ? 'fail' : 'warn'),
                'critical'    => $info['critical'],
                'description' => $info['desc'],
            ];
        }

        // Writable Directories Check
        $rootDir = dirname(__DIR__);
        $dirsToCheck = [
            $rootDir . '/uploads'                => 'uploads/',
            $rootDir . '/public/cache'          => 'public/cache/',
            $rootDir                             => 'Root Directory (for config generation)',
            __DIR__                              => 'install/ Directory (for lock file)',
        ];

        foreach ($dirsToCheck as $path => $label) {
            $writable = is_dir($path) ? is_writable($path) : false;
            if (!$writable) {
                // Try creating if missing
                if (!file_exists($path)) {
                    @mkdir($path, 0755, true);
                    $writable = is_writable($path);
                }
            }

            if (!$writable) $allPassed = false;

            $requirements[] = [
                'key'         => 'dir_' . md5($path),
                'name'        => 'Write Permission: ' . $label,
                'required'    => 'Writable (0755/0775)',
                'current'     => $writable ? 'Writable' : 'Not Writable',
                'status'      => $writable ? 'pass' : 'fail',
                'critical'    => true,
                'description' => 'The web server must have write permissions to write configuration, student photos, and tenant caches.',
            ];
        }

        // Environment Directives (Memory Limit & Execution Time)
        $memoryLimit = ini_get('memory_limit');
        $memBytes = self::parseSize($memoryLimit);
        $memOk = ($memBytes >= 128 * 1024 * 1024) || ($memBytes === -1);
        $requirements[] = [
            'key'         => 'memory_limit',
            'name'        => 'PHP Memory Limit',
            'required'    => '>= 128M',
            'current'     => $memoryLimit ?: '128M',
            'status'      => $memOk ? 'pass' : 'warn',
            'critical'    => false,
            'description' => 'Adequate memory ensures smooth PDF report card compilation and database seed imports.',
        ];

        return [
            'all_passed'   => $allPassed,
            'requirements' => $requirements,
        ];
    }

    /**
     * Establish a resilient MySQL connection with auto-fallback between localhost, 127.0.0.1, and Unix sockets.
     */
    public static function connectMySQL(string &$host, string $user, string $pass, string $dbname = '', int $port = 3306): array
    {
        if ($port <= 0) $port = 3306;
        $host = trim($host);
        if ($host === '') $host = '127.0.0.1';

        // Candidate connection targets to attempt in priority order
        $attempts = [];
        $attempts[] = ['host' => $host, 'socket' => null];

        // If localhost or empty, queue 127.0.0.1 (TCP/IP bypasses Linux Unix socket issues)
        if ($host === 'localhost') {
            $attempts[] = ['host' => '127.0.0.1', 'socket' => null];
        } elseif ($host === '127.0.0.1') {
            $attempts[] = ['host' => 'localhost', 'socket' => null];
        }

        // Standard Linux MySQL/MariaDB socket paths (cPanel, Ubuntu/Debian, CentOS/CloudLinux)
        $knownSockets = [
            '/var/lib/mysql/mysql.sock',
            '/var/run/mysqld/mysqld.sock',
            '/tmp/mysql.sock',
        ];
        foreach ($knownSockets as $sock) {
            if (file_exists($sock)) {
                $attempts[] = ['host' => 'localhost', 'socket' => $sock];
            }
        }

        $lastError = '';
        $lastErrno = 0;

        foreach ($attempts as $att) {
            $h = $att['host'];
            $s = $att['socket'];

            try {
                $conn = $s
                    ? @new mysqli($h, $user, $pass, $dbname, $port, $s)
                    : @new mysqli($h, $user, $pass, $dbname, $port);

                if ($conn && !$conn->connect_error) {
                    // Success! Update $host by reference so configs and tenant records use this working host
                    $host = $h;
                    return [
                        'conn'   => $conn,
                        'host'   => $h,
                        'socket' => $s,
                        'error'  => null,
                        'errno'  => 0,
                    ];
                }

                if ($conn) {
                    $lastError = $conn->connect_error;
                    $lastErrno = $conn->connect_errno;
                }
            } catch (\Throwable $e) {
                $lastError = $e->getMessage();
                $lastErrno = (int)$e->getCode();
            }
        }

        // Helpful actionable message
        $friendlyMessage = $lastError ?: 'Unknown database connection error.';
        if (strpos($friendlyMessage, 'No such file or directory') !== false || $lastErrno === 2002) {
            $friendlyMessage .= '. (On Linux/cPanel hosting, MySQL often requires "127.0.0.1" instead of "localhost", or the MySQL service is not running on port ' . $port . ')';
        } elseif (strpos($friendlyMessage, 'Access denied') !== false || $lastErrno === 1045) {
            $friendlyMessage .= '. (Please verify that your database username and password are correct and that the user is assigned to the database in cPanel with all privileges)';
        }

        return [
            'conn'   => null,
            'host'   => $host,
            'socket' => null,
            'error'  => $friendlyMessage,
            'errno'  => $lastErrno,
        ];
    }

    /**
     * Test MySQL database connectivity.
     */
    public static function testDatabaseConnection(array $params): array
    {
        $host = trim($params['host'] ?? '127.0.0.1');
        $port = (int)($params['port'] ?? 3306);
        $user = trim($params['username'] ?? 'root');
        $pass = (string)($params['password'] ?? '');
        $dbname = trim($params['dbname'] ?? '');

        if ($port <= 0) $port = 3306;

        $res = self::connectMySQL($host, $user, $pass, '', $port);
        if (!$res['conn']) {
            return [
                'success'       => false,
                'message'       => 'Connection failed: ' . $res['error'] . ' (Error code: ' . $res['errno'] . ')',
                'resolved_host' => $host,
            ];
        }

        $conn = $res['conn'];
        $serverVersion = $conn->server_info;

        // Check if database exists or if we have CREATE privilege
        $dbExists = false;
        $canCreate = false;
        if (!empty($dbname)) {
            $checkDb = @$conn->select_db($dbname);
            if ($checkDb) {
                $dbExists = true;
            } else {
                // Try testing CREATE DATABASE privilege
                $testDbName = '`' . $conn->real_escape_string($dbname) . '`';
                $createTest = @$conn->query("CREATE DATABASE IF NOT EXISTS $testDbName CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
                if ($createTest) {
                    $canCreate = true;
                    $dbExists = true;
                }
            }
        }

        $conn->close();

        $msg = 'Database connection successful!';
        if ($res['host'] !== ($params['host'] ?? '')) {
            $msg .= " (Auto-resolved host to: {$res['host']})";
        }

        return [
            'success'        => true,
            'message'        => $msg,
            'server_version' => $serverVersion,
            'db_exists'      => $dbExists,
            'can_create'     => $canCreate,
            'resolved_host'  => $res['host'],
        ];
    }

    /**
     * Execute installation pipeline.
     */
    public static function executeInstallation(array $params): array
    {
        if (self::isInstalled()) {
            return [
                'success' => false,
                'message' => 'Installation is locked. If you wish to reinstall, delete install/installed.lock.',
            ];
        }

        $mode = $params['mode'] ?? 'saas'; // 'saas' or 'single'
        $host = trim($params['db_host'] ?? '127.0.0.1');
        $port = (int)($params['db_port'] ?? 3306);
        $user = trim($params['db_username'] ?? 'root');
        $pass = (string)($params['db_password'] ?? '');
        $masterDbName = trim($params['db_name'] ?? ($mode === 'saas' ? 'edumacflo_master' : 'edumacflo'));

        if ($port <= 0) $port = 3306;

        // Admin credentials
        $adminName  = trim($params['admin_name'] ?? 'System Administrator');
        $adminUser  = trim($params['admin_user'] ?? 'superadmin');
        $adminEmail = trim($params['admin_email'] ?? 'admin@edumacflo.com');
        $adminPass  = (string)($params['admin_pass'] ?? '');

        if (strlen($adminPass) < 8) {
            return ['success' => false, 'message' => 'Admin password must be at least 8 characters long.'];
        }

        // Connect to MySQL server using resilient auto-fallback
        $connRes = self::connectMySQL($host, $user, $pass, '', $port);
        if (!$connRes['conn']) {
            return ['success' => false, 'message' => 'Could not connect to database server: ' . $connRes['error']];
        }
        $conn = $connRes['conn'];
        $conn->set_charset('utf8mb4');

        $rootDir = dirname(__DIR__);
        $stepsExecuted = [];

        try {
            // 1. Select or Create Master / Main Database
            // Check select_db first! On cPanel, databases are pre-created and restricted users lack global CREATE privilege.
            $selected = @$conn->select_db($masterDbName);
            if (!$selected) {
                $safeDbName = '`' . $conn->real_escape_string($masterDbName) . '`';
                if (!$conn->query("CREATE DATABASE IF NOT EXISTS $safeDbName CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci")) {
                    throw new Exception("Could not select or create database `$masterDbName`: " . $conn->error . ". On cPanel/shared hosting, please create the database first in cPanel -> MySQL Databases and assign your user with All Privileges.");
                }
                if (!$conn->select_db($masterDbName)) {
                    throw new Exception("Database `$masterDbName` created but could not be selected: " . $conn->error);
                }
            }
            $stepsExecuted[] = "Connected to database `$masterDbName`";

            // 2. Import Schema
            if ($mode === 'saas') {
                $sqlPath = $rootDir . '/database/saas_master.sql';
                if (!file_exists($sqlPath)) {
                    throw new Exception("Missing schema file: database/saas_master.sql");
                }
                self::importSqlFile($conn, $sqlPath);
                $stepsExecuted[] = "Imported SaaS Master Control Plane schema (`database/saas_master.sql`)";

                // Seed or Update Super-Admin in `saas_admins`
                $hashedPass = password_hash($adminPass, PASSWORD_BCRYPT);
                $stmt = $conn->prepare("INSERT INTO `saas_admins` (`id`, `username`, `password_hash`, `email`, `full_name`, `role`, `status`) 
                                        VALUES (1, ?, ?, ?, ?, 'super_admin', 'active')
                                        ON DUPLICATE KEY UPDATE `username` = VALUES(`username`), `password_hash` = VALUES(`password_hash`), `email` = VALUES(`email`), `full_name` = VALUES(`full_name`)");
                $stmt->bind_param("ssss", $adminUser, $hashedPass, $adminEmail, $adminName);
                $stmt->execute();
                $stmt->close();
                $stepsExecuted[] = "Configured SaaS Super-Admin account (`$adminUser`)";

                // Provision Initial School if requested
                $initialSchoolName = trim($params['school_name'] ?? '');
                $initialSchoolSlug = preg_replace('/[^a-z0-9\-]/', '', strtolower(trim($params['school_slug'] ?? '')));
                if (!empty($initialSchoolName) && !empty($initialSchoolSlug)) {
                    $schoolDbName = "edumacflo_tenant_{$initialSchoolSlug}";
                    // On cPanel, if master database has a prefix (e.g. cpaneluser_...), prepend it to tenant db name
                    if (strpos($masterDbName, '_') !== false) {
                        $cpanelPrefix = substr($masterDbName, 0, strpos($masterDbName, '_') + 1);
                        if (strpos($schoolDbName, $cpanelPrefix) !== 0) {
                            $schoolDbName = $cpanelPrefix . "tenant_{$initialSchoolSlug}";
                        }
                    }

                    $safeTenantDb = '`' . $conn->real_escape_string($schoolDbName) . '`';
                    $canCreateTenantDb = @$conn->query("CREATE DATABASE IF NOT EXISTS $safeTenantDb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");

                    $tenantSqlPath = $rootDir . '/database/edumacflo.sql';
                    if (file_exists($tenantSqlPath) && $canCreateTenantDb) {
                        $tHost = $host;
                        $tRes = self::connectMySQL($tHost, $user, $pass, $schoolDbName, $port);
                        if ($tRes['conn']) {
                            $tenantConn = $tRes['conn'];
                            $tenantConn->set_charset('utf8mb4');
                            self::importSqlFile($tenantConn, $tenantSqlPath);

                            // Update school info in tenant DB
                            $tenantAdminEmail = trim($params['school_email'] ?? $adminEmail);
                            $tenantConn->query("UPDATE `administratives` SET `school_name` = '" . $tenantConn->real_escape_string($initialSchoolName) . "', `email` = '" . $tenantConn->real_escape_string($tenantAdminEmail) . "' LIMIT 1");

                            // Create Super Admin in school portal
                            $tenantAdminPass = trim($params['school_pass'] ?? $adminPass);
                            $tenantHashedPass = password_hash($tenantAdminPass, PASSWORD_BCRYPT);
                            $tenantConn->query("DELETE FROM `staff` WHERE `role` = 11");
                            $stmtSt = $tenantConn->prepare("INSERT INTO `staff` (`email`, `username`, `password`, `firstname`, `lastname`, `role`, `status`) VALUES (?, ?, ?, 'School', 'Administrator', 11, 'Active')");
                            $stmtSt->bind_param("sss", $tenantAdminEmail, $adminUser, $tenantHashedPass);
                            $stmtSt->execute();
                            $stmtSt->close();
                            $tenantConn->close();

                            // Register in tenants & tenant_domains in master DB
                            $uuid = sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0x0fff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000, mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff));
                            $stmtT = $conn->prepare("INSERT INTO `tenants` (`tenant_uuid`, `slug`, `school_name`, `contact_email`, `db_host`, `db_name`, `db_user`, `db_pass`, `status`, `plan_id`) 
                                                     VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'active', 2)
                                                     ON DUPLICATE KEY UPDATE `school_name` = VALUES(`school_name`), `contact_email` = VALUES(`contact_email`)");
                            $stmtT->bind_param("ssssssss", $uuid, $initialSchoolSlug, $initialSchoolName, $tenantAdminEmail, $host, $schoolDbName, $user, $pass);
                            $stmtT->execute();
                            $tenantId = $conn->insert_id ?: 1;
                            $stmtT->close();

                            // Register default domains
                            $primaryDomain = "{$initialSchoolSlug}.edumacflo.com";
                            $conn->query("INSERT IGNORE INTO `tenant_domains` (`tenant_id`, `domain`, `is_primary`, `dns_verified`, `ssl_active`) VALUES ($tenantId, '$primaryDomain', 1, 1, 1)");

                            // Create tenant upload isolation directories
                            $tenantUploadPath = $rootDir . "/uploads/tenants/{$initialSchoolSlug}";
                            $subDirs = ['school', 'students', 'staff', 'curriculums', 'admissions', 'others'];
                            foreach ($subDirs as $sd) {
                                @mkdir("{$tenantUploadPath}/{$sd}", 0755, true);
                            }
                            @file_put_contents("{$tenantUploadPath}/.htaccess", "Options -Indexes\n<FilesMatch \"\.(php|php3|php4|php5|phtml|pl|py|jsp|asp|sh|cgi)$\">\nOrder Deny,Allow\nDeny from all\n</FilesMatch>\n");
                            @file_put_contents("{$tenantUploadPath}/index.html", "");

                            $stepsExecuted[] = "Provisioned initial school tenant: `$initialSchoolName` (`$initialSchoolSlug`)";
                        }
                    } else {
                        $stepsExecuted[] = "Skipped isolated starter tenant DB (provision school databases via cPanel or SaaS Admin Portal)";
                    }
                }

                // 3. Write saas_master_config.php
                self::generateSaasConfigFile($rootDir, [
                    'host'     => $host,
                    'username' => $user,
                    'password' => $pass,
                    'dbname'   => $masterDbName,
                    'currency' => $params['currency'] ?? 'NGN',
                ]);
                $stepsExecuted[] = "Generated master configuration (`saas_master_config.php`)";

                // Also generate fallback db_config.php
                self::generateDbConfigFile($rootDir, [
                    'server'   => $host,
                    'username' => $user,
                    'password' => $pass,
                    'dbname'   => $masterDbName,
                ]);

            } else {
                // Single-Tenant Mode
                $sqlPath = $rootDir . '/database/edumacflo.sql';
                if (!file_exists($sqlPath)) {
                    throw new Exception("Missing schema file: database/edumacflo.sql");
                }
                self::importSqlFile($conn, $sqlPath);
                $stepsExecuted[] = "Imported standalone school database (`database/edumacflo.sql`)";

                // Update administrative school info
                $schoolName = trim($params['school_name'] ?? 'EdumacFlo Academy');
                $schoolEmail = trim($params['school_email'] ?? $adminEmail);
                $schoolPhone = trim($params['school_phone'] ?? '+2348000000000');
                $conn->query("UPDATE `administratives` SET 
                              `school_name` = '" . $conn->real_escape_string($schoolName) . "',
                              `email` = '" . $conn->real_escape_string($schoolEmail) . "',
                              `phone` = '" . $conn->real_escape_string($schoolPhone) . "' LIMIT 1");

                // Seed Super Admin
                $hashedPass = password_hash($adminPass, PASSWORD_BCRYPT);
                $conn->query("DELETE FROM `staff` WHERE `role` = 11");
                $stmt = $conn->prepare("INSERT INTO `staff` (`email`, `username`, `password`, `firstname`, `lastname`, `role`, `status`) 
                                        VALUES (?, ?, ?, 'System', 'SuperAdmin', 11, 'Active')");
                $stmt->bind_param("sss", $adminEmail, $adminUser, $hashedPass);
                $stmt->execute();
                $stmt->close();
                $stepsExecuted[] = "Configured school Super-Admin account (`$adminUser`)";

                // Write db_config.php
                self::generateDbConfigFile($rootDir, [
                    'server'   => $host,
                    'username' => $user,
                    'password' => $pass,
                    'dbname'   => $masterDbName,
                ]);
                $stepsExecuted[] = "Generated database configuration (`db_config.php`)";
            }

            // 4. Create Lock File
            $lockData = json_encode([
                'installed_at' => date('Y-m-d H:i:s'),
                'mode'         => $mode,
                'admin_user'   => $adminUser,
                'admin_email'  => $adminEmail,
                'php_version'  => PHP_VERSION,
                'server'       => $_SERVER['SERVER_SOFTWARE'] ?? 'Unknown',
            ], JSON_PRETTY_PRINT);
            file_put_contents(self::$lockFile, $lockData);
            $stepsExecuted[] = "Locked installer wizard (`install/installed.lock`)";

            $conn->close();

            $adminUrl = ($mode === 'saas') ? 'saas/admin/login.php' : 'login.php';

            return [
                'success'        => true,
                'message'        => 'Installation completed successfully!',
                'mode'           => $mode,
                'admin_user'     => $adminUser,
                'admin_url'      => $adminUrl,
                'steps_executed' => $stepsExecuted,
            ];

        } catch (Exception $e) {
            if ($conn) $conn->close();
            return [
                'success' => false,
                'message' => $e->getMessage(),
                'steps'   => $stepsExecuted,
            ];
        }
    }

    /**
     * Import an SQL file statement by statement.
     */
    private static function importSqlFile(mysqli $conn, string $filepath): void
    {
        $sqlContent = file_get_contents($filepath);
        if ($sqlContent === false) {
            throw new Exception("Could not read SQL file at: $filepath");
        }

        // Normalize line endings and strip comments
        $lines = explode("\n", str_replace(["\r\n", "\r"], "\n", $sqlContent));
        $query = '';

        $conn->query("SET FOREIGN_KEY_CHECKS = 0");
        $conn->query("SET SQL_MODE = 'NO_AUTO_VALUE_ON_ZERO'");

        foreach ($lines as $line) {
            $trimmed = trim($line);
            if ($trimmed === '' || strpos($trimmed, '--') === 0 || strpos($trimmed, '/*') === 0 || strpos($trimmed, '#') === 0) {
                continue;
            }

            // Skip CREATE DATABASE and USE directives so we do not override the chosen database
            if (preg_match('/^(CREATE\s+DATABASE|USE\s+[`a-zA-Z0-9_]+)/i', $trimmed)) {
                continue;
            }

            $query .= $line . "\n";
            if (substr($trimmed, -1) === ';') {
                if (!$conn->query($query)) {
                    // Ignore benign errors (e.g. table already exists or drop table warning)
                    $err = $conn->error;
                    if (strpos($err, 'already exists') === false && strpos($err, 'Unknown table') === false) {
                        // Log warning or throw if fatal
                    }
                }
                $query = '';
            }
        }

        if (trim($query) !== '') {
            $conn->query($query);
        }

        $conn->query("SET FOREIGN_KEY_CHECKS = 1");
    }

    /**
     * Generate saas_master_config.php.
     */
    private static function generateSaasConfigFile(string $rootDir, array $params): void
    {
        $host = addslashes($params['host']);
        $user = addslashes($params['username']);
        $pass = addslashes($params['password']);
        $dbname = addslashes($params['dbname']);
        $currency = addslashes($params['currency'] ?? 'NGN');

        $content = "<?php\n"
                 . "/**\n"
                 . " * EdumacFlo SaaS Master Control Plane Configuration\n"
                 . " * Generated automatically by the Web Installer Wizard on " . date('Y-m-d H:i:s') . "\n"
                 . " */\n\n"
                 . "return [\n"
                 . "    'enabled'  => true,\n"
                 . "    'host'     => '{$host}',\n"
                 . "    'username' => '{$user}',\n"
                 . "    'password' => '{$pass}',\n"
                 . "    'dbname'   => '{$dbname}',\n\n"
                 . "    // Tenant resolution cache\n"
                 . "    'cache_ttl_seconds' => 300,\n"
                 . "    'cache_dir'         => __DIR__ . '/public/cache/tenants/',\n"
                 . "    'default_tenant_slug' => 'default',\n\n"
                 . "    // Billing & Currency\n"
                 . "    'currency'           => '{$currency}',\n"
                 . "    'payment_simulation' => true,\n\n"
                 . "    // Payment Gateway API Keys (update in production)\n"
                 . "    'paystack' => [\n"
                 . "        'public_key' => 'pk_test_sample_public_key',\n"
                 . "        'secret_key' => 'sk_test_sample_secret_key',\n"
                 . "    ],\n"
                 . "    'flutterwave' => [\n"
                 . "        'public_key' => 'FLWPUBK_TEST-sample_public_key',\n"
                 . "        'secret_key' => 'FLWSECK_TEST-sample_secret_key',\n"
                 . "    ],\n"
                 . "    'bank_transfer' => [\n"
                 . "        'bank_name'      => 'Zenith Bank PLC',\n"
                 . "        'account_name'   => 'EdumacFlo Technologies Ltd',\n"
                 . "        'account_number' => '1012345678',\n"
                 . "        'instructions'   => 'Please use your school slug or domain as payment narration.',\n"
                 . "    ],\n"
                 . "];\n";

        file_put_contents($rootDir . '/saas_master_config.php', $content);
    }

    /**
     * Generate db_config.php.
     */
    private static function generateDbConfigFile(string $rootDir, array $params): void
    {
        $server = addslashes($params['server']);
        $user = addslashes($params['username']);
        $pass = addslashes($params['password']);
        $dbname = addslashes($params['dbname']);

        $content = "<?php\n"
                 . "/**\n"
                 . " * EdumacFlo Database Configuration\n"
                 . " * Generated automatically by the Web Installer Wizard on " . date('Y-m-d H:i:s') . "\n"
                 . " */\n\n"
                 . "return [\n"
                 . "    'server'   => '{$server}',\n"
                 . "    'username' => '{$user}',\n"
                 . "    'password' => '{$pass}',\n"
                 . "    'dbname'   => '{$dbname}',\n"
                 . "];\n";

        file_put_contents($rootDir . '/db_config.php', $content);
    }

    /**
     * Helper to parse size strings like '128M', '1G'.
     */
    private static function parseSize(string $size): int
    {
        $unit = preg_replace('/[^bkmgtpezy]/i', '', $size);
        $size = preg_replace('/[^0-9\.]/', '', $size);
        if ($unit) {
            return (int)round($size * pow(1024, stripos('bkmgtpezy', $unit[0])));
        }
        return (int)round($size);
    }
}
