<?php
/**
 * EdumacFlo Tenant Provisioner
 * ----------------------------
 * Automates the creation of a fully isolated school tenant:
 * 1. Creates a dedicated MySQL database
 * 2. Imports the clean seed schema
 * 3. Configures school profile and super-admin
 * 4. Creates isolated upload directories
 * 5. Registers the tenant in edumacflo_master
 */

class TenantProvisioner
{
    private $master;          // mysqli connection to edumacflo_master
    private $config;          // master config array
    private $seed_sql_path;   // absolute path to database/edumacflo.sql
    private $uploads_base;    // absolute path to uploads/tenants/

    public function __construct()
    {
        $this->seed_sql_path = realpath(__DIR__ . '/../../database/edumacflo.sql');
        $this->uploads_base  = realpath(__DIR__ . '/../../uploads') . '/tenants/';

        // Load SaaS master config
        $config = $this->loadMasterConfig();
        if (!$config) {
            throw new RuntimeException("saas_master_config.php not found or SaaS mode is disabled.");
        }
        $this->config = $config;

        $this->master = @mysqli_connect(
            $config['host'] ?? '127.0.0.1',
            $config['username'] ?? 'root',
            $config['password'] ?? '',
            $config['dbname'] ?? 'edumacflo_master'
        );

        if (!$this->master) {
            throw new RuntimeException("Cannot connect to edumacflo_master: " . mysqli_connect_error());
        }
        mysqli_set_charset($this->master, 'utf8mb4');
    }

    /**
     * Main provisioning method.
     */
    public function provision(array $params): array
    {
        $slug         = strtolower(trim($params['slug'] ?? ''));
        $school_name  = trim($params['school_name'] ?? '');
        $email        = trim($params['email'] ?? '');
        $phone        = trim($params['phone'] ?? '');
        $plan_id      = (int)($params['plan_id'] ?? 1);
        $password     = $params['admin_password'] ?? 'ChangeMe123';

        // Validate required params
        if (empty($slug) || empty($school_name) || empty($email)) {
            return ['status' => 'error', 'message' => 'slug, school_name, and email are required.'];
        }

        // Slugs: lowercase letters, digits, hyphens only
        if (!preg_match('/^[a-z0-9\-]+$/', $slug)) {
            return ['status' => 'error', 'message' => "Slug '$slug' is invalid. Use lowercase letters, digits, and hyphens only."];
        }

        $db_name = 'edumacflo_tenant_' . str_replace('-', '_', $slug);
        $domain  = $slug . '.edumacflo.com';

        $log_id = $this->log('Provisioning started', 'pending', null, "School: $school_name, DB: $db_name");

        // ── Step 1: Validate slug uniqueness ──────────────────────────
        $this->step("Validating slug uniqueness...");
        $stmt = $this->master->prepare("SELECT id FROM tenants WHERE slug = ? LIMIT 1");
        $stmt->bind_param("s", $slug);
        $stmt->execute();
        $stmt->store_result();
        if ($stmt->num_rows > 0) {
            $stmt->close();
            $this->updateLog($log_id, 'failed', "Slug '$slug' already exists.");
            return ['status' => 'error', 'message' => "Slug '$slug' is already taken."];
        }
        $stmt->close();
        $this->ok("Slug '$slug' is available.");

        // ── Step 2: Create dedicated database ─────────────────────────
        $this->step("Creating database `$db_name`...");
        if (!mysqli_query($this->master, "CREATE DATABASE IF NOT EXISTS `$db_name` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci")) {
            $err = "Failed to create database: " . mysqli_error($this->master);
            $this->updateLog($log_id, 'failed', $err);
            return ['status' => 'error', 'message' => $err];
        }
        $this->ok("Database `$db_name` created.");

        // ── Step 3: Connect to tenant database & import seed ──────────
        $this->step("Connecting to `$db_name` and importing seed schema...");
        $tHost = $this->config['host'] ?? '127.0.0.1';
        $tUser = $this->config['username'] ?? 'root';
        $tPass = $this->config['password'] ?? '';
        $tenant_conn = @mysqli_connect($tHost, $tUser, $tPass, $db_name);
        if (!$tenant_conn) {
            $err = "Cannot connect to `$db_name`: " . mysqli_connect_error();
            $this->updateLog($log_id, 'failed', $err);
            return ['status' => 'error', 'message' => $err];
        }
        mysqli_set_charset($tenant_conn, 'utf8mb4');

        if (!file_exists($this->seed_sql_path)) {
            $err = "Seed SQL not found at: " . $this->seed_sql_path;
            $this->updateLog($log_id, 'failed', $err);
            return ['status' => 'error', 'message' => $err];
        }

        $seed_sql = file_get_contents($this->seed_sql_path);
        // Remove the CREATE/USE DATABASE directives since we're already in the tenant DB
        $seed_sql = preg_replace('/^(CREATE|USE)\s+DATABASE[^;]+;\s*/im', '', $seed_sql);

        mysqli_query($tenant_conn, "SET FOREIGN_KEY_CHECKS=0");
        if (!mysqli_multi_query($tenant_conn, $seed_sql)) {
            $err = "Seed import error: " . mysqli_error($tenant_conn);
            $this->updateLog($log_id, 'failed', $err);
            return ['status' => 'error', 'message' => $err];
        }
        // Consume all result sets
        do {
            if ($res = mysqli_store_result($tenant_conn)) {
                mysqli_free_result($res);
            }
        } while (mysqli_more_results($tenant_conn) && mysqli_next_result($tenant_conn));
        mysqli_query($tenant_conn, "SET FOREIGN_KEY_CHECKS=1");
        // Seed SQL sets AUTOCOMMIT=0 — commit and re-enable before running further queries
        mysqli_query($tenant_conn, "COMMIT");
        mysqli_query($tenant_conn, "SET AUTOCOMMIT=1");
        $this->ok("Seed schema imported (75 tables).");

        // ── Step 4: Configure school profile in administratives ────────
        $this->step("Configuring school profile...");
        $stmt = $tenant_conn->prepare("UPDATE `administratives` SET `school_name`=?, `school_mail`=?, `school_phone`=?, `school_short_name`=? WHERE id=1");
        $short_name = strlen($school_name) > 30 ? substr($school_name, 0, 30) : $school_name;
        $stmt->bind_param("ssss", $school_name, $email, $phone, $short_name);
        $stmt->execute();
        $stmt->close();
        $this->ok("School profile configured: $school_name");

        // ── Step 5: Create Super Admin account ────────────────────────
        $this->step("Creating Super Administrator account...");
        $admin_hash = password_hash($password, PASSWORD_BCRYPT);
        $admin_name = 'System Administrator';
        $admin_user = 'admin';
        $reg_date   = date('Y-m-d');
        $role_id    = 11; // Super Admin role
        $status     = 'Active';

        // Clear any seed admin first, then insert clean one
        mysqli_query($tenant_conn, "DELETE FROM `staff`");
        $stmt = $tenant_conn->prepare("INSERT INTO `staff` (`id`,`username`,`password`,`name`,`dob`,`lga`,`state`,`country`,`passport`,`address`,`sex`,`phone`,`email`,`status`,`date_registered`,`role`) VALUES (1,?,?,?,'1990-01-01','Headquarters','Federal','Nigeria','none.jpg','School Campus','Male',?,?,'Active',?,?)");
        $stmt->bind_param("ssssssi", $admin_user, $admin_hash, $admin_name, $phone, $email, $reg_date, $role_id);
        $stmt->execute();
        $stmt->close();
        $this->ok("Super Admin created. Username: admin / Password: [as provided]");

        // ── Step 6: Create isolated upload directories ─────────────────
        $this->step("Creating isolated upload directories...");
        $subdirs = ['school', 'students', 'staff', 'curriculums', 'admissions', 'others'];
        $tenant_upload_root = rtrim($this->uploads_base, '/\\') . '/' . $slug . '/';

        foreach ($subdirs as $dir) {
            $full_path = $tenant_upload_root . $dir . '/';
            if (!is_dir($full_path)) {
                mkdir($full_path, 0755, true);
            }
            // Copy none.jpg placeholder for students
            if ($dir === 'students' && file_exists(realpath(__DIR__ . '/../../uploads/students/none.jpg'))) {
                @copy(realpath(__DIR__ . '/../../uploads/students/none.jpg'), $full_path . 'none.jpg');
            }
        }

        // Write root upload security files
        $this->writeSecurityFiles($tenant_upload_root);
        $this->ok("Upload directories created at uploads/tenants/$slug/");

        // ── Step 7: Register tenant in edumacflo_master ───────────────
        $this->step("Registering tenant in edumacflo_master...");
        $tenant_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)
        );
        $trial_ends = date('Y-m-d H:i:s', strtotime('+30 days'));
        $sub_expires = date('Y-m-d H:i:s', strtotime('+30 days'));
        $tHost = $this->config['host'] ?? '127.0.0.1';
        $tUser = $this->config['username'] ?? 'root';
        $tPass = $this->config['password'] ?? '';

        $stmt = $this->master->prepare("
            INSERT INTO `tenants` 
            (`tenant_uuid`,`slug`,`school_name`,`contact_email`,`contact_phone`,`db_host`,`db_name`,`db_user`,`db_pass`,`status`,`plan_id`,`trial_ends_at`,`subscription_expires_at`)
            VALUES (?,?,?,?,?,?,?,?,?,'trial',?,?,?)
        ");
        $stmt->bind_param("sssssssssiss", $tenant_uuid, $slug, $school_name, $email, $phone, $tHost, $db_name, $tUser, $tPass, $plan_id, $trial_ends, $sub_expires);
        $stmt->execute();
        $tenant_id = $this->master->insert_id;
        $stmt->close();

        // Register primary subdomain
        $stmt = $this->master->prepare("INSERT INTO `tenant_domains` (`tenant_id`,`domain`,`is_primary`,`is_verified`) VALUES (?,?,1,1)");
        $stmt->bind_param("is", $tenant_id, $domain);
        $stmt->execute();
        $stmt->close();

        $this->ok("Tenant registered (ID: $tenant_id, UUID: $tenant_uuid).");

        // ── Step 8: Finalize audit log ─────────────────────────────────
        $this->updateLog($log_id, 'success', "Tenant $slug provisioned successfully. DB: $db_name", $tenant_id);
        $this->ok("Provisioning complete!");

        mysqli_close($tenant_conn);

        return [
            'status'     => 'success',
            'tenant_id'  => $tenant_id,
            'slug'       => $slug,
            'db_name'    => $db_name,
            'portal_url' => "https://$domain/login.php",
            'admin_user' => 'admin',
        ];
    }

    // ──────────────────────────────────────────────────────────────────
    // Private Helpers
    // ──────────────────────────────────────────────────────────────────

    private function loadMasterConfig(): ?array
    {
        $candidates = [
            dirname(__DIR__, 2) . '/saas_master_config.php',
            dirname(__DIR__, 1) . '/saas_master_config.php',
            __DIR__ . '/saas_master_config.php',
        ];
        foreach ($candidates as $path) {
            if (file_exists($path)) {
                $cfg = require $path;
                if (is_array($cfg) && !empty($cfg['enabled'])) {
                    return $cfg;
                }
            }
        }
        return null;
    }

    private function writeSecurityFiles(string $dir): void
    {
        $htaccess = "<IfModule mod_authz_core.c>\n    Options -Indexes\n</IfModule>\n<FilesMatch \"\\.(php|php5|phtml)\$\">\n    Require all denied\n</FilesMatch>\n";
        $index    = "<!DOCTYPE html><html><head><title>403</title></head><body></body></html>";
        if (!file_exists($dir . '.htaccess')) {
            file_put_contents($dir . '.htaccess', $htaccess);
        }
        if (!file_exists($dir . 'index.html')) {
            file_put_contents($dir . 'index.html', $index);
        }
    }

    private function log(string $action, string $status, ?int $tenant_id, string $message = ''): int
    {
        $stmt = $this->master->prepare("INSERT INTO `tenant_provisioning_logs` (`tenant_id`,`action`,`status`,`message`) VALUES (?,?,?,?)");
        $stmt->bind_param("isss", $tenant_id, $action, $status, $message);
        $stmt->execute();
        $id = $this->master->insert_id;
        $stmt->close();
        return (int)$id;
    }

    private function updateLog(int $log_id, string $status, string $message, ?int $tenant_id = null): void
    {
        $stmt = $this->master->prepare("UPDATE `tenant_provisioning_logs` SET `status`=?, `message`=?, `tenant_id`=? WHERE id=?");
        $stmt->bind_param("ssii", $status, $message, $tenant_id, $log_id);
        $stmt->execute();
        $stmt->close();
    }

    private function step(string $msg): void
    {
        echo "\n  → " . $msg;
    }

    private function ok(string $msg): void
    {
        echo " ✓ " . $msg . "\n";
    }
}
