<?php
// archive_logs.php - Move rows older than N days from activity_logs and
// stock_activity_logs into *_archive tables. Read-add, no deletion: rows
// are INSERTed into the archive table, then DELETEd from the live table
// inside a transaction, so a crash mid-flight leaves both halves intact.
//
// Modes:
//   - Browser (admin)   : POST + CSRF token (a form is rendered on GET)
//   - CLI               : php archive_logs.php [--days=365] [--dry-run]
//   - Cron (token-gated): archive_logs.php?cron=1&token=<cron_key>[&days=365]
//
// Safe to re-run. Idempotent.

require 'db.php';
require_once 'helpers.php';

$isCli  = (php_sapi_name() === 'cli');
$isCron = isset($_GET['cron']);

if ($isCron) {
    $expected = (string) getConfig('backup_sync.cron_key', '');
    $provided = (string) ($_GET['token'] ?? '');
    if ($expected === '' || !hash_equals($expected, $provided)) {
        http_response_code(403);
        header('Content-Type: text/plain');
        die("Forbidden.");
    }
} elseif (!$isCli) {
    if (!isset($_SESSION['loggedin']) || $_SESSION['loggedin'] !== true) {
        http_response_code(401);
        header('Content-Type: text/plain');
        die("Authentication required.");
    }
    $username = strtolower((string)($_SESSION['user'] ?? ''));
    $role     = strtolower((string)($_SESSION['role'] ?? ''));
    if ($username !== 'endie' && $role !== 'master') {
        http_response_code(403);
        header('Content-Type: text/plain');
        die("Master/Endie access only.");
    }
}

// Resolve days + dry-run flag
$days = 365;
$dryRun = false;
if ($isCli) {
    foreach ($argv as $a) {
        if (preg_match('/^--days=(\d+)$/', $a, $m)) { $days = (int)$m[1]; }
        if ($a === '--dry-run') { $dryRun = true; }
    }
} else {
    if (isset($_GET['days']))      { $days   = max(30, (int)$_GET['days']); }
    if (isset($_POST['days']))     { $days   = max(30, (int)$_POST['days']); }
    if (isset($_GET['dry_run']))   { $dryRun = $_GET['dry_run'] === '1'; }
    if (isset($_POST['dry_run']))  { $dryRun = $_POST['dry_run'] === '1'; }
}

// Side-effecting confirmation: only proceed on POST (with CSRF) or cron/CLI.
$proceed = false;
if ($isCli || $isCron) {
    $proceed = true;
} elseif ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $csrf = (string)($_POST['csrf_token'] ?? '');
    if (!empty($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $csrf)) {
        $proceed = true;
    }
}

$liveTables = [
    'activity_logs'       => ['archive' => 'activity_logs_archive',       'ts' => 'created_at'],
    'stock_activity_logs' => ['archive' => 'stock_activity_logs_archive', 'ts' => 'created_at'],
];

$results = [];

if ($proceed) {
    foreach ($liveTables as $live => $info) {
        $arc = $info['archive'];
        $ts  = $info['ts'];

        // Skip silently if the live table doesn't exist (fresh install)
        $check = $pdo->query("SHOW TABLES LIKE " . $pdo->quote($live));
        if (!$check || $check->rowCount() === 0) {
            $results[$live] = ['skipped' => 'table missing'];
            continue;
        }

        try {
            // Create archive table by cloning live structure (idempotent)
            $pdo->exec("CREATE TABLE IF NOT EXISTS `$arc` LIKE `$live`");

            // Count first (for dry run + reporting)
            $stmt = $pdo->prepare("SELECT COUNT(*) FROM `$live` WHERE `$ts` < DATE_SUB(NOW(), INTERVAL ? DAY)");
            $stmt->execute([$days]);
            $count = (int) $stmt->fetchColumn();

            if ($count === 0) {
                $results[$live] = ['rows' => 0, 'action' => 'nothing-to-archive'];
                continue;
            }

            if ($dryRun) {
                $results[$live] = ['rows' => $count, 'action' => 'dry-run-only'];
                continue;
            }

            // Transactional move: INSERT into archive, then DELETE from live.
            $pdo->beginTransaction();
            $pdo->prepare("INSERT INTO `$arc` SELECT * FROM `$live` WHERE `$ts` < DATE_SUB(NOW(), INTERVAL ? DAY)")
                ->execute([$days]);
            $pdo->prepare("DELETE FROM `$live` WHERE `$ts` < DATE_SUB(NOW(), INTERVAL ? DAY)")
                ->execute([$days]);
            $pdo->commit();
            $results[$live] = ['rows' => $count, 'action' => 'archived'];
        } catch (Throwable $e) {
            if ($pdo->inTransaction()) { $pdo->rollBack(); }
            $results[$live] = ['error' => $e->getMessage()];
        }
    }
}

// ---------------------------------------------------------------------------
// Output
// ---------------------------------------------------------------------------
if ($isCli || $isCron) {
    if (!$isCli) { header('Content-Type: text/plain; charset=utf-8'); }
    echo "archive_logs.php @ " . date('c') . "  days=$days  dry-run=" . ($dryRun ? 'yes' : 'no') . "\n";
    if (!$proceed) {
        echo "ABORTED: no confirmation\n";
        exit;
    }
    foreach ($results as $tbl => $r) {
        echo "  $tbl: " . json_encode($r) . "\n";
    }
    exit;
}

header('Content-Type: text/html; charset=utf-8');
$csrfToken = $_SESSION['csrf_token'] ?? '';
?>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>Archive Old Logs</title>
<style>
body{font-family:Arial,sans-serif;background:#f5f6fa;margin:20px;color:#222}
.box{max-width:780px;margin:0 auto;background:#fff;padding:24px;border-radius:8px;box-shadow:0 2px 10px rgba(0,0,0,0.08)}
h1{margin-top:0}
.warn{background:#fff3cd;border-left:6px solid #ffc107;padding:12px;border-radius:6px;margin:12px 0}
.ok{background:#d4edda;border-left:6px solid #28a745;padding:12px;border-radius:6px;margin:12px 0}
.btn{padding:12px 24px;background:#28a745;color:#fff;border:none;border-radius:6px;font-weight:bold;cursor:pointer}
table{width:100%;border-collapse:collapse;margin:10px 0}
th,td{padding:8px;border-bottom:1px solid #e1e5e9;text-align:left}
th{background:#34495e;color:#fff}
input[type=number]{padding:6px;border:1px solid #ccc;border-radius:4px;width:80px}
label{margin-right:12px}
</style></head><body><div class="box">
<h1>Archive Old Logs</h1>
<?php if ($proceed && !empty($results)): ?>
    <div class="ok"><strong>Done.</strong> Below are the archive results.</div>
    <table><tr><th>Table</th><th>Result</th></tr>
    <?php foreach ($results as $tbl => $r): ?>
        <tr><td><?= htmlspecialchars($tbl) ?></td><td><?= htmlspecialchars(json_encode($r, JSON_UNESCAPED_SLASHES)) ?></td></tr>
    <?php endforeach; ?>
    </table>
    <p><a href="dashboard.php">&larr; Dashboard</a></p>
<?php else: ?>
    <div class="warn"><strong>Safe operation:</strong> rows older than N days are MOVED from <code>activity_logs</code> and <code>stock_activity_logs</code> into <code>*_archive</code> tables. Nothing is deleted; only relocated. Dashboard log view continues to read the live tables, which stay fast.</div>
    <form method="POST">
        <input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrfToken) ?>">
        <label>Archive rows older than <input type="number" name="days" value="365" min="30" max="3650"> days</label>
        <label><input type="checkbox" name="dry_run" value="1"> Dry run (count only, no changes)</label>
        <br><br>
        <button class="btn" type="submit">Archive Now</button>
        <a href="dashboard.php" style="margin-left:16px">Cancel</a>
    </form>
<?php endif; ?>
</div></body></html>
