<?php
/* ============================================================================
   WBMCZ — ACV MIGRATION   (Activity & Task  ·  Subscription Management)
   Run this ONCE on the live server:   https://wbmcz.online/acvmigration.php

   What it does
     1. tasks                     the Activity & Task board
     2. task_activities           per-task log (who did what, when, from where)
     3. task_categories           the editable task-type catalogue, seeded with
                                  every module of the panel (Lead, User, KYC,
                                  Product, Service, Subscription, Order, Wallet,
                                  Payout, Refer, Support, Website/Carousel,
                                  Notification, Staff, Report, General)
     4. subscription_plans        many plans, each with its own price
     5. subscription_plan_items   which products belong to which plan
     6. subscription_plan_history price-up / price-down + product add/remove log
     7. user_subscriptions        which customer is on which plan, till when
     8. users                     subscription_plan_id / subscription_expires_at
     9. seller_services           product_group  (government | agency)
    10. roles                     the new modules 'manage_tasks' and
                                  'manage_subscriptions' are added to every role
                                  that already holds 'all'

   Safe to run more than once — every step checks before it changes anything.
   DELETE THIS FILE after a successful run.
   ============================================================================ */

require_once __DIR__ . '/config.php';
require_once __DIR__ . '/db.php';

$conn = $db->getConnection();
$log  = [];

function acv_table_exists($conn, $table) {
    try { $r = $conn->query("SHOW TABLES LIKE '$table'"); return $r && $r->num_rows > 0; }
    catch (\Throwable $e) { return false; }
}
function acv_col_exists($conn, $table, $col) {
    try { $r = $conn->query("SHOW COLUMNS FROM `$table` LIKE '$col'"); return $r && $r->num_rows > 0; }
    catch (\Throwable $e) { return false; }
}
function acv_index_exists($conn, $table, $index) {
    try { $r = $conn->query("SHOW INDEX FROM `$table` WHERE Key_name = '$index'"); return $r && $r->num_rows > 0; }
    catch (\Throwable $e) { return false; }
}
function acv_run(&$log, $conn, $label, $sql) {
    try { $conn->query($sql); $log[] = ["ok", $label, "executed"]; }
    catch (\Throwable $e) { $log[] = ["fail", $label, $e->getMessage()]; }
}
function acv_create(&$log, $conn, $table, $sql) {
    if (acv_table_exists($conn, $table)) { $log[] = ["ok", $table, "table already exists"]; return; }
    try { $conn->query($sql); $log[] = ["add", $table, "table created"]; }
    catch (\Throwable $e) { $log[] = ["fail", $table, $e->getMessage()]; }
}
function acv_add_col(&$log, $conn, $table, $col, $def) {
    if (!acv_table_exists($conn, $table))    { $log[] = ["skip", "$table.$col", "table does not exist"]; return; }
    if (acv_col_exists($conn, $table, $col)) { $log[] = ["ok",   "$table.$col", "already present"];      return; }
    try { $conn->query("ALTER TABLE `$table` ADD COLUMN `$col` $def");
          $log[] = ["add", "$table.$col", $def]; }
    catch (\Throwable $e) { $log[] = ["fail", "$table.$col", $e->getMessage()]; }
}
function acv_add_index(&$log, $conn, $table, $index, $sql) {
    if (!acv_table_exists($conn, $table))        { $log[] = ["skip", "$table.$index", "table does not exist"]; return; }
    if (acv_index_exists($conn, $table, $index)) { $log[] = ["ok",   "$table.$index", "already present"];      return; }
    try { $conn->query("ALTER TABLE `$table` ADD $sql"); $log[] = ["add", "$table.$index", $sql]; }
    catch (\Throwable $e) { $log[] = ["fail", "$table.$index", $e->getMessage()]; }
}

/* ---------------------------------------------------------------------------
   1. tasks — one row per piece of work handed to a staff member
   --------------------------------------------------------------------------- */
acv_create($log, $conn, 'tasks', "
    CREATE TABLE IF NOT EXISTS tasks (
        id INT AUTO_INCREMENT PRIMARY KEY,
        task_code VARCHAR(40) NULL,

        scope_role VARCHAR(20) NOT NULL DEFAULT 'user',
        module_key VARCHAR(40) NOT NULL DEFAULT 'general',
        category_key VARCHAR(60) NOT NULL DEFAULT 'general_other',
        category_label VARCHAR(160) NULL,

        title VARCHAR(200) NOT NULL,
        description TEXT NULL,

        target_user_id INT NULL,
        target_name VARCHAR(150) NULL,
        target_mobile VARCHAR(25) NULL,
        target_ref_type VARCHAR(40) NULL,
        target_ref_id INT NULL,

        assigned_to INT NULL,
        assigned_name VARCHAR(150) NULL,
        assigned_role VARCHAR(20) NULL,
        assigned_code VARCHAR(40) NULL,
        assigned_at DATETIME NULL,
        assigned_by INT NULL,
        assigned_by_name VARCHAR(150) NULL,

        priority VARCHAR(10) NOT NULL DEFAULT 'medium',
        status VARCHAR(20) NOT NULL DEFAULT 'pending',
        progress TINYINT NOT NULL DEFAULT 0,

        due_date DATETIME NULL,
        started_at DATETIME NULL,
        completed_at DATETIME NULL,
        next_follow_up DATE NULL,

        remark TEXT NULL,
        reject_reason VARCHAR(500) NULL,
        attachment VARCHAR(255) NULL,
        reassign_count INT NOT NULL DEFAULT 0,

        created_by INT NULL,
        created_by_name VARCHAR(150) NULL,
        created_by_role VARCHAR(20) NULL,
        created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP NULL DEFAULT NULL,

        KEY idx_tasks_scope (scope_role, module_key),
        KEY idx_tasks_assigned (assigned_to, status),
        KEY idx_tasks_status (status),
        KEY idx_tasks_due (due_date),
        KEY idx_tasks_created (created_at),
        KEY idx_tasks_target (target_user_id),
        UNIQUE KEY uniq_tasks_code (task_code)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
");

/* columns for databases that already had an older tasks table */
acv_add_col($log, $conn, 'tasks', 'task_code',       "VARCHAR(40) NULL");
acv_add_col($log, $conn, 'tasks', 'scope_role',      "VARCHAR(20) NOT NULL DEFAULT 'user'");
acv_add_col($log, $conn, 'tasks', 'module_key',      "VARCHAR(40) NOT NULL DEFAULT 'general'");
acv_add_col($log, $conn, 'tasks', 'category_key',    "VARCHAR(60) NOT NULL DEFAULT 'general_other'");
acv_add_col($log, $conn, 'tasks', 'category_label',  "VARCHAR(160) NULL");
acv_add_col($log, $conn, 'tasks', 'target_user_id',  "INT NULL");
acv_add_col($log, $conn, 'tasks', 'target_name',     "VARCHAR(150) NULL");
acv_add_col($log, $conn, 'tasks', 'target_mobile',   "VARCHAR(25) NULL");
acv_add_col($log, $conn, 'tasks', 'target_ref_type', "VARCHAR(40) NULL");
acv_add_col($log, $conn, 'tasks', 'target_ref_id',   "INT NULL");
acv_add_col($log, $conn, 'tasks', 'assigned_code',   "VARCHAR(40) NULL");
acv_add_col($log, $conn, 'tasks', 'assigned_role',   "VARCHAR(20) NULL");
acv_add_col($log, $conn, 'tasks', 'assigned_by',     "INT NULL");
acv_add_col($log, $conn, 'tasks', 'assigned_by_name',"VARCHAR(150) NULL");
acv_add_col($log, $conn, 'tasks', 'progress',        "TINYINT NOT NULL DEFAULT 0");
acv_add_col($log, $conn, 'tasks', 'next_follow_up',  "DATE NULL");
acv_add_col($log, $conn, 'tasks', 'reject_reason',   "VARCHAR(500) NULL");
acv_add_col($log, $conn, 'tasks', 'attachment',      "VARCHAR(255) NULL");
acv_add_col($log, $conn, 'tasks', 'reassign_count',  "INT NOT NULL DEFAULT 0");
acv_add_col($log, $conn, 'tasks', 'created_by_role', "VARCHAR(20) NULL");
acv_add_col($log, $conn, 'tasks', 'updated_at',      "TIMESTAMP NULL DEFAULT NULL");

/* ---------------------------------------------------------------------------
   2. task_activities — the log every task carries with it
   --------------------------------------------------------------------------- */
acv_create($log, $conn, 'task_activities', "
    CREATE TABLE IF NOT EXISTS task_activities (
        id BIGINT AUTO_INCREMENT PRIMARY KEY,
        task_id INT NOT NULL,
        task_code VARCHAR(40) NULL,
        action VARCHAR(30) NOT NULL DEFAULT 'note',
        field_label VARCHAR(120) NULL,
        old_value VARCHAR(255) NULL,
        new_value VARCHAR(255) NULL,
        remark TEXT NULL,
        done_by INT NULL,
        done_by_name VARCHAR(150) NULL,
        done_by_role VARCHAR(20) NULL,
        ip_address VARCHAR(45) NULL,
        created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
        KEY idx_ta_task (task_id, created_at),
        KEY idx_ta_actor (done_by, created_at),
        KEY idx_ta_action (action)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
");

/* ---------------------------------------------------------------------------
   3. task_categories — the catalogue, editable from the admin panel
   --------------------------------------------------------------------------- */
acv_create($log, $conn, 'task_categories', "
    CREATE TABLE IF NOT EXISTS task_categories (
        id INT AUTO_INCREMENT PRIMARY KEY,
        module_key VARCHAR(40) NOT NULL,
        category_key VARCHAR(60) NOT NULL,
        label VARCHAR(160) NOT NULL,
        scope_role VARCHAR(20) NOT NULL DEFAULT 'all',
        icon VARCHAR(40) NULL,
        sort_order INT NOT NULL DEFAULT 0,
        is_system TINYINT(1) NOT NULL DEFAULT 0,
        status TINYINT(1) NOT NULL DEFAULT 1,
        created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
        UNIQUE KEY uniq_tc (module_key, category_key),
        KEY idx_tc_module (module_key, status)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
");

/* ---------------------------------------------------------------------------
   4. subscription_plans — many plans, each with its own price
   --------------------------------------------------------------------------- */
acv_create($log, $conn, 'subscription_plans', "
    CREATE TABLE IF NOT EXISTS subscription_plans (
        id INT AUTO_INCREMENT PRIMARY KEY,
        name VARCHAR(120) NOT NULL,
        plan_code VARCHAR(40) NULL,
        tagline VARCHAR(200) NULL,
        description TEXT NULL,
        mrp DECIMAL(10,2) NOT NULL DEFAULT 0.00,
        price DECIMAL(10,2) NOT NULL DEFAULT 0.00,
        duration_days INT NOT NULL DEFAULT 365,
        discount_pct DECIMAL(5,2) NOT NULL DEFAULT 0.00,
        product_scope VARCHAR(20) NOT NULL DEFAULT 'selected',
        badge VARCHAR(60) NULL,
        color VARCHAR(30) NOT NULL DEFAULT 'indigo',
        features TEXT NULL,
        is_default TINYINT(1) NOT NULL DEFAULT 0,
        is_popular TINYINT(1) NOT NULL DEFAULT 0,
        status TINYINT(1) NOT NULL DEFAULT 1,
        sort_order INT NOT NULL DEFAULT 0,
        created_by INT NULL,
        created_by_name VARCHAR(150) NULL,
        created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP NULL DEFAULT NULL,
        UNIQUE KEY uniq_sp_code (plan_code),
        KEY idx_sp_status (status, sort_order)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
");

/* ---------------------------------------------------------------------------
   5. subscription_plan_items — which product sits inside which plan
   --------------------------------------------------------------------------- */
acv_create($log, $conn, 'subscription_plan_items', "
    CREATE TABLE IF NOT EXISTS subscription_plan_items (
        id INT AUTO_INCREMENT PRIMARY KEY,
        plan_id INT NOT NULL,
        service_id INT NOT NULL,
        service_type VARCHAR(20) NOT NULL DEFAULT 'seller',
        service_title VARCHAR(255) NULL,
        discount_pct DECIMAL(5,2) NULL,
        discount_amount DECIMAL(10,2) NULL,
        is_free TINYINT(1) NOT NULL DEFAULT 0,
        added_by INT NULL,
        added_by_name VARCHAR(150) NULL,
        created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
        UNIQUE KEY uniq_spi (plan_id, service_id, service_type),
        KEY idx_spi_plan (plan_id),
        KEY idx_spi_service (service_id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
");

/* ---------------------------------------------------------------------------
   6. subscription_plan_history — every price move and product change
   --------------------------------------------------------------------------- */
acv_create($log, $conn, 'subscription_plan_history', "
    CREATE TABLE IF NOT EXISTS subscription_plan_history (
        id BIGINT AUTO_INCREMENT PRIMARY KEY,
        plan_id INT NOT NULL,
        plan_name VARCHAR(120) NULL,
        action VARCHAR(30) NOT NULL DEFAULT 'update',
        field_label VARCHAR(120) NULL,
        old_value VARCHAR(255) NULL,
        new_value VARCHAR(255) NULL,
        remark VARCHAR(500) NULL,
        done_by INT NULL,
        done_by_name VARCHAR(150) NULL,
        created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
        KEY idx_sph_plan (plan_id, created_at)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
");

/* ---------------------------------------------------------------------------
   7. user_subscriptions — who is on which plan, and until when
   --------------------------------------------------------------------------- */
acv_create($log, $conn, 'user_subscriptions', "
    CREATE TABLE IF NOT EXISTS user_subscriptions (
        id INT AUTO_INCREMENT PRIMARY KEY,
        user_id INT NOT NULL,
        plan_id INT NULL,
        plan_name VARCHAR(120) NULL,
        amount DECIMAL(10,2) NOT NULL DEFAULT 0.00,
        payment_mode VARCHAR(30) NULL,
        payment_ref VARCHAR(120) NULL,
        starts_at DATETIME NULL,
        expires_at DATETIME NULL,
        status VARCHAR(20) NOT NULL DEFAULT 'active',
        created_by INT NULL,
        created_by_name VARCHAR(150) NULL,
        created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
        KEY idx_us_user (user_id, status),
        KEY idx_us_plan (plan_id),
        KEY idx_us_expiry (expires_at)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
");

/* ---------------------------------------------------------------------------
   8. users — which plan the customer holds
   --------------------------------------------------------------------------- */
acv_add_col($log, $conn, 'users', 'is_subscribed',           "TINYINT(1) NOT NULL DEFAULT 0");
acv_add_col($log, $conn, 'users', 'subscription_plan_id',    "INT NULL");
acv_add_col($log, $conn, 'users', 'subscription_started_at', "DATETIME NULL");
acv_add_col($log, $conn, 'users', 'subscription_expires_at', "DATETIME NULL");
acv_add_index($log, $conn, 'users', 'idx_users_plan', "INDEX idx_users_plan (subscription_plan_id)");

/* ---------------------------------------------------------------------------
   9. seller_services — government vs agency product group
       Category 1 = Government Portals. Everything else is agency / software.
   --------------------------------------------------------------------------- */
acv_add_col($log, $conn, 'seller_services', 'product_group', "VARCHAR(20) NOT NULL DEFAULT 'agency'");
acv_add_index($log, $conn, 'seller_services', 'idx_ss_group', "INDEX idx_ss_group (product_group)");
if (acv_col_exists($conn, 'seller_services', 'product_group')) {
    try {
        $conn->query("UPDATE seller_services SET product_group = 'government' WHERE category_id = 1");
        $g = $conn->affected_rows;
        $conn->query("UPDATE seller_services SET product_group = 'agency' WHERE category_id <> 1");
        $log[] = ["add", "seller_services.product_group", "$g product(s) tagged as government portals"];
    } catch (\Throwable $e) { $log[] = ["fail", "seller_services.product_group", $e->getMessage()]; }
}

/* ---------------------------------------------------------------------------
   10. roles — the two new modules join every full-access role
   --------------------------------------------------------------------------- */
if (acv_table_exists($conn, 'roles')) {
    try {
        $rs = $conn->query("SELECT id, name, permissions FROM roles");
        $touched = 0;
        while ($rs && ($r = $rs->fetch_assoc())) {
            $p = json_decode((string)$r['permissions'], true);
            if (!is_array($p)) continue;
            if (!in_array('all', $p, true)) continue;      // only full-access roles
            $before = $p;
            foreach (['manage_tasks', 'manage_subscriptions'] as $need) {
                if (!in_array($need, $p, true)) { $p[] = $need; }
            }
            if ($p !== $before) {
                $st = $conn->prepare("UPDATE roles SET permissions = ? WHERE id = ?");
                $j  = json_encode(array_values($p));
                $st->bind_param('si', $j, $r['id']);
                $st->execute(); $st->close();
                $touched++;
            }
        }
        $log[] = ["add", "roles", $touched > 0
            ? "$touched full-access role(s) now hold manage_tasks + manage_subscriptions"
            : "no role needed changing"];
    } catch (\Throwable $e) { $log[] = ["fail", "roles", $e->getMessage()]; }
}

/* ---------------------------------------------------------------------------
   11. Seed the task catalogue and the first subscription plan
   --------------------------------------------------------------------------- */
$seeded_cats = 0;
if (@is_file(__DIR__ . '/includes/tasks.php')) {
    require_once __DIR__ . '/includes/tasks.php';
    if (function_exists('tasks_seed_categories')) {
        try { $seeded_cats = tasks_seed_categories($db); $log[] = ["add", "task_categories", "$seeded_cats task type(s) seeded"]; }
        catch (\Throwable $e) { $log[] = ["fail", "task_categories seed", $e->getMessage()]; }
    }
} else {
    $log[] = ["skip", "task_categories seed", "upload includes/tasks.php first, then re-run this page"];
}

/* The single old subscription_price setting becomes the first real plan. */
if (acv_table_exists($conn, 'subscription_plans')) {
    try {
        $have = $conn->query("SELECT COUNT(*) c FROM subscription_plans")->fetch_assoc();
        if ((int)$have['c'] === 0) {
            $old = 999.00;
            try {
                $s = $conn->query("SELECT setting_value FROM settings WHERE setting_key = 'subscription_price' LIMIT 1");
                if ($s && $s->num_rows) { $old = (float)$s->fetch_assoc()['setting_value']; }
            } catch (\Throwable $e) {}
            if ($old <= 0) { $old = 999.00; }

            $st = $conn->prepare(
                "INSERT INTO subscription_plans
                    (name, plan_code, tagline, description, mrp, price, duration_days, discount_pct,
                     product_scope, badge, color, features, is_default, is_popular, status, sort_order)
                 VALUES (?,?,?,?,?,?,?,?,?,?,?,?,1,1,1,1)");
            $name  = 'Standard Plan';
            $code  = 'STANDARD';
            $tag   = 'The plan your members are on today';
            $desc  = 'Created automatically from the old single subscription price so nothing breaks. Rename it, change the price, or add more plans beside it.';
            $mrp   = $old;
            $price = $old;
            $days  = 365;
            $disc  = 0.00;
            $scope = 'all';
            $badge = 'Popular';
            $color = 'indigo';
            $feat  = "Discount on every listed product\nReferral program unlocked\nPriority support";
            $st->bind_param('ssssddidssss', $name, $code, $tag, $desc, $mrp, $price, $days, $disc, $scope, $badge, $color, $feat);
            $st->execute(); $pid = $st->insert_id; $st->close();

            $conn->query("UPDATE users SET subscription_plan_id = $pid WHERE is_subscribed = 1 AND (subscription_plan_id IS NULL OR subscription_plan_id = 0)");
            $log[] = ["add", "subscription_plans", "Standard Plan created at Rs " . number_format($old, 2) . " and given to existing subscribers"];
        } else {
            $log[] = ["ok", "subscription_plans", "plans already exist — left untouched"];
        }
    } catch (\Throwable $e) { $log[] = ["fail", "subscription_plans seed", $e->getMessage()]; }
}

/* Keep the old setting in step with the default plan so the existing
   subscription.php page carries on working unchanged. */
if (acv_table_exists($conn, 'settings') && acv_table_exists($conn, 'subscription_plans')) {
    try {
        $d = $conn->query("SELECT price FROM subscription_plans WHERE is_default = 1 AND status = 1 ORDER BY sort_order ASC LIMIT 1");
        if ($d && $d->num_rows) {
            $p = (float)$d->fetch_assoc()['price'];
            $ex = $conn->query("SELECT id FROM settings WHERE setting_key = 'subscription_price' LIMIT 1");
            if ($ex && $ex->num_rows) { $conn->query("UPDATE settings SET setting_value = '$p' WHERE setting_key = 'subscription_price'"); }
            else { $conn->query("INSERT INTO settings (setting_key, setting_value) VALUES ('subscription_price', '$p')"); }
            $log[] = ["ok", "settings.subscription_price", "kept in step with the default plan (Rs " . number_format($p, 2) . ")"];
        }
    } catch (\Throwable $e) { $log[] = ["skip", "settings.subscription_price", $e->getMessage()]; }
}

$fails = 0; $adds = 0;
foreach ($log as $l) { if ($l[0] === 'fail') $fails++; if ($l[0] === 'add') $adds++; }
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ACV Migration — Activity &amp; Task · Subscription</title>
    <script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-slate-100 p-6 font-sans">
    <div class="max-w-3xl mx-auto bg-white rounded-2xl shadow p-6 border border-slate-200">
        <h1 class="text-2xl font-extrabold text-slate-800 mb-1">ACV Migration</h1>
        <p class="text-sm text-slate-500 mb-5">
            Database: <b><?php echo DB_NAME; ?></b> &middot; Activity &amp; Task board, task log,
            task catalogue, subscription plans, plan products, government / agency product split
        </p>

        <div class="mb-5 rounded-xl px-4 py-3 <?php echo $fails ? 'bg-rose-50 text-rose-700 border border-rose-200' : 'bg-emerald-50 text-emerald-700 border border-emerald-200'; ?>">
            <?php echo $fails
                ? "Finished with $fails error(s) — see the rows marked FAIL."
                : "Migration completed successfully — $adds change(s) applied."; ?>
        </div>

        <table class="w-full text-sm border-collapse">
            <thead>
                <tr class="bg-slate-50 text-slate-500 text-xs uppercase tracking-wider">
                    <th class="text-left py-2 px-3">Result</th>
                    <th class="text-left py-2 px-3">Target</th>
                    <th class="text-left py-2 px-3">Detail</th>
                </tr>
            </thead>
            <tbody class="divide-y divide-slate-100">
            <?php foreach ($log as $l):
                $cls = ['ok' => 'text-slate-500', 'add' => 'text-emerald-600', 'skip' => 'text-amber-600', 'fail' => 'text-rose-600'][$l[0]] ?? '';
            ?>
                <tr>
                    <td class="py-2 px-3 font-bold uppercase <?php echo $cls; ?>"><?php echo $l[0]; ?></td>
                    <td class="py-2 px-3 font-mono text-slate-700 text-xs"><?php echo htmlspecialchars($l[1]); ?></td>
                    <td class="py-2 px-3 text-slate-500 text-xs"><?php echo htmlspecialchars($l[2]); ?></td>
                </tr>
            <?php endforeach; ?>
            </tbody>
        </table>

        <div class="mt-6 text-xs text-slate-600 space-y-2 bg-slate-50 border border-slate-200 rounded-xl p-4">
            <p class="font-bold text-slate-700 text-sm">Where to go next</p>
            <p><b>Admin &rarr; Activity &amp; Task</b> — hand work to your staff, watch the status change, and read the log of every task.</p>
            <p><b>Admin &rarr; Subscription Management</b> — make as many plans as you like, move the price up or down, and pick the products each plan carries.</p>
            <p><b>Admin &rarr; Service Management &rarr; Government Portals</b> — the government product list, without the price and share columns it never needed.</p>
            <p><b>Admin &rarr; Service Management &rarr; Product Management</b> — now agency &amp; software products only, with the full share breakdown.</p>
        </div>

        <p class="mt-4 text-xs text-rose-600 font-bold">Delete acvmigration.php from the server once this page shows &ldquo;completed successfully&rdquo;.</p>
    </div>
</body>
</html>
