<?php
/**
 * ╔══════════════════════════════════════════════════════════════════════════╗
 *  Savit Unified SEO Suite — One-Shot Setup Installer
 *  ─────────────────────────────────────────────────────────────────────────
 *  Drop this file into htdocs/Savit/, start Apache + MySQL, open in browser.
 *  It will create the database, run all migrations, and verify every engine.
 *
 *  Usage:
 *    Normal (non-destructive): http://localhost/Savit/setup.php
 *    Fresh install (drops DB): http://localhost/Savit/setup.php?fresh=1&confirm=YES
 * ╚══════════════════════════════════════════════════════════════════════════╝
 */
declare(strict_types=1);

define('SAVIT_ROOT', __DIR__);
define('SETUP_VERSION', '1.0.0');

// ── Load .env ────────────────────────────────────────────────────────────────
function setup_load_env(string $path): void {
    if (!is_file($path)) return;
    foreach (file($path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: [] as $line) {
        $line = trim($line);
        if (!$line || $line[0] === '#') continue;
        $parts = explode('=', $line, 2);
        if (count($parts) !== 2) continue;
        $k = trim($parts[0]);
        $v = trim($parts[1]);
        if (strlen($v) >= 2 && (($v[0] === '"' && $v[-1] === '"') || ($v[0] === "'" && $v[-1] === "'"))) {
            $v = substr($v, 1, -1);
        }
        $_ENV[$k] = $v;
    }
}

setup_load_env(SAVIT_ROOT . '/.env');

$cfg = [
    'host'   => $_ENV['DB_HOST']    ?? '127.0.0.1',
    'port'   => (int)($_ENV['DB_PORT'] ?? 3306),
    'dbname' => $_ENV['DB_NAME']    ?? 'savit_platform',
    'user'   => $_ENV['DB_USER']    ?? 'root',
    'pass'   => $_ENV['DB_PASS']    ?? '',
];

$isFresh  = ($_GET['fresh'] ?? '') === '1' && ($_GET['confirm'] ?? '') === 'YES';
$migDirs  = [
    SAVIT_ROOT . '/Common/database/migrations',
    SAVIT_ROOT . '/Audit/database/migrations',
    SAVIT_ROOT . '/Analytics/database/migrations',
];
$results  = [];
$hasError = false;
$pdo      = null;

// ── ACTION: export project + analytics data ───────────────────────────────────
$action = $_GET['action'] ?? '';
if ($action === 'export' && $pdo === null) {
    // We need a DB connection first — skip to after DB setup
}
if ($action === 'export') {
    try {
        $exportPdo = new PDO("mysql:host={$cfg['host']};port={$cfg['port']};dbname={$cfg['dbname']};charset=utf8mb4", $cfg['user'], $cfg['pass'], [PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]);
        $tables = ['projects','project_oauth_tokens','page_categories','analytics_snapshots','analytics_event_data','analytics_page_data','analytics_query_data','schema_migrations'];
        $export = ['version'=>'1.0','exported_at'=>date('c'),'db_name'=>$cfg['dbname'],'tables'=>[]];
        foreach ($tables as $t) {
            try { $export['tables'][$t] = $exportPdo->query("SELECT * FROM `{$t}`")->fetchAll(PDO::FETCH_ASSOC); }
            catch (\Throwable $e) { $export['tables'][$t] = []; }
        }
        header('Content-Type: application/json');
        header('Content-Disposition: attachment; filename="savit-export-'.date('Y-m-d').'.json"');
        echo json_encode($export, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE);
        exit;
    } catch (\Throwable $e) { http_response_code(500); die(json_encode(['error'=>$e->getMessage()])); }
}
if ($action === 'import' && $_SERVER['REQUEST_METHOD'] === 'POST') {
    try {
        $importPdo = new PDO("mysql:host={$cfg['host']};port={$cfg['port']};dbname={$cfg['dbname']};charset=utf8mb4", $cfg['user'], $cfg['pass'], [PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]);
        $body = json_decode(file_get_contents('php://input'), true);
        $res = [];
        $importOrder = ['projects','project_oauth_tokens','page_categories','analytics_snapshots','analytics_event_data','analytics_page_data','analytics_query_data'];
        foreach ($importOrder as $table) {
            $rows = $body['tables'][$table] ?? [];
            if (empty($rows)) { $res[$table]='skipped'; continue; }
            $cols  = array_keys($rows[0]);
            $colSql= implode(',', array_map(fn($c)=>"`{$c}`",$cols));
            $ph    = '('.implode(',',array_fill(0,count($cols),'?')).')';
            $stmt  = $importPdo->prepare("INSERT IGNORE INTO `{$table}` ({$colSql}) VALUES {$ph}");
            $n = 0; foreach ($rows as $r) { try { $stmt->execute(array_values($r)); $n++; } catch(\Throwable){} }
            $res[$table] = "{$n}/".count($rows)." rows";
        }
        header('Content-Type: application/json');
        echo json_encode(['success'=>true,'results'=>$res]);
        exit;
    } catch (\Throwable $e) { http_response_code(500); echo json_encode(['success'=>false,'message'=>$e->getMessage()]); exit; }
}

// ── Helper ───────────────────────────────────────────────────────────────────
function ok(string $msg): array  { return ['status' => 'ok',   'msg' => $msg]; }
function err(string $msg): array { return ['status' => 'err',  'msg' => $msg]; }
function warn(string $msg): array{ return ['status' => 'warn', 'msg' => $msg]; }

// ── Step 1: Connect without selecting a DB ───────────────────────────────────
try {
    $pdo = new PDO(
        "mysql:host={$cfg['host']};port={$cfg['port']};charset=utf8mb4",
        $cfg['user'], $cfg['pass'],
        [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
    );
    $results[] = ok("Connected to MySQL at {$cfg['host']}:{$cfg['port']} as `{$cfg['user']}`");
} catch (PDOException $e) {
    $results[] = err("Cannot connect to MySQL: " . $e->getMessage());
    $hasError  = true;
}

// ── Step 2: Drop DB if fresh mode ────────────────────────────────────────────
if ($pdo && $isFresh) {
    try {
        $pdo->exec("DROP DATABASE IF EXISTS `{$cfg['dbname']}`");
        $results[] = warn("Dropped database `{$cfg['dbname']}` (fresh install mode)");
    } catch (PDOException $e) {
        $results[] = err("Could not drop database: " . $e->getMessage());
        $hasError  = true;
    }
}

// ── Step 3: Create DB if it doesn't exist ───────────────────────────────────
if ($pdo && !$hasError) {
    try {
        $pdo->exec("CREATE DATABASE IF NOT EXISTS `{$cfg['dbname']}` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
        $results[] = ok("Database `{$cfg['dbname']}` ready");
        $pdo->exec("USE `{$cfg['dbname']}`");
    } catch (PDOException $e) {
        $results[] = err("Could not create database: " . $e->getMessage());
        $hasError  = true;
    }
}

// ── Step 4: Run migrations (all three engines) ───────────────────────────────
if ($pdo && !$hasError) {
    // Ensure schema_migrations tracking table exists (supports both 'migration' and 'filename' column schemas)
    $pdo->exec("CREATE TABLE IF NOT EXISTS schema_migrations (migration VARCHAR(255) NOT NULL PRIMARY KEY, applied_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP)");
    // Add filename column if missing (added for Audit/Analytics engine compatibility)
    try { $pdo->exec("ALTER TABLE schema_migrations ADD COLUMN IF NOT EXISTS filename VARCHAR(200) AFTER migration"); } catch (\Throwable) {}
    // Sync filename from migration column for existing rows
    try { $pdo->exec("UPDATE schema_migrations SET filename = migration WHERE filename IS NULL OR filename = ''"); } catch (\Throwable) {}
    $appliedMigs = $pdo->query("SELECT COALESCE(filename, migration) AS f FROM schema_migrations")->fetchAll(PDO::FETCH_COLUMN);

    // Collect all migration files from all engines
    $allFiles = [];
    foreach ($migDirs as $migDir) {
        if (!is_dir($migDir)) continue;
        foreach (glob($migDir . '/*.sql') ?: [] as $f) {
            $allFiles[basename($f)] = $f; // basename as key deduplicates
        }
    }
    ksort($allFiles);

    if (empty($allFiles)) {
        $results[] = warn("No migration files found in any engine directory.");
    }

    foreach ($allFiles as $name => $file) {
        if (in_array($name, $appliedMigs, true)) {
            $results[] = warn("Skipped (already applied): <code>{$name}</code>");
            continue;
        }
        try {
            $sql = file_get_contents($file);
            $stmts = preg_split('/;\s*(?=\n|$)/m', str_replace(["\r\n", "\r"], "\n", $sql));
            foreach ($stmts as $stmt) {
                $stmt = trim($stmt);
                if ($stmt === '' || str_starts_with($stmt, '--')) continue;
                $pdo->exec($stmt);
            }
            $pdo->exec("INSERT IGNORE INTO schema_migrations (migration, filename) VALUES ('{$name}','{$name}')");
            $results[] = ok("Migration applied: <code>{$name}</code>");
        } catch (PDOException $e) {
            $msg = $e->getMessage();
            if (str_contains($msg, 'Duplicate column') || str_contains($msg, 'already exists') || str_contains($msg, '1060')) {
                $pdo->exec("INSERT IGNORE INTO schema_migrations (migration, filename) VALUES ('{$name}','{$name}')");
                $results[] = warn("Skipped (already exists): <code>{$name}</code>");
            } else {
                $results[] = err("Migration failed [{$name}]: " . htmlspecialchars($msg));
                $hasError  = true;
            }
        }
    }
}

// ── Step 5: Verify engine configs ────────────────────────────────────────────
$envFile = SAVIT_ROOT . '/.env';
$results[] = is_file($envFile) ? ok(".env found at Savit/.env") : err(".env NOT found — copy .env.example to .env");

$commonBoot = SAVIT_ROOT . '/Common/bootstrap.php';
$results[] = is_file($commonBoot) ? ok("Common/bootstrap.php present") : err("Common/bootstrap.php missing");

foreach (['Audit', 'Analytics', 'Content'] as $engine) {
    $boot = SAVIT_ROOT . "/{$engine}/bootstrap.php";
    $results[] = is_file($boot) ? ok("{$engine} bootstrap.php present") : err("{$engine}/bootstrap.php missing");
}

// ── Step 6: Verify table counts ──────────────────────────────────────────────
if ($pdo && !$hasError) {
    try {
        $tables = $pdo->query("SHOW TABLES")->fetchAll(PDO::FETCH_COLUMN);
        $cnt    = count($tables);
        $results[] = ok("Database has {$cnt} table(s): " . implode(', ', array_slice($tables, 0, 10)) . ($cnt > 10 ? '…' : ''));
    } catch (PDOException $e) {
        $results[] = warn("Could not list tables: " . $e->getMessage());
    }
}

// ── Step 7: Verify URL reachability (relative paths) ────────────────────────
$scriptDir = rtrim(str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'] ?? '')), '/');
$engines = [
    'Dashboard'        => $scriptDir . '/',
    'Audit Engine'     => $scriptDir . '/Audit/public/',
    'Analytics Engine' => $scriptDir . '/Analytics/public/',
    'Content Engine'   => $scriptDir . '/Content/',
];

?><!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Savit Setup — v<?= SETUP_VERSION ?></title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
  <style>
    body { background: #0f172a; color: #e2e8f0; font-family: 'Inter', system-ui, sans-serif; }
    .setup-card { background: #1e293b; border: 1px solid #334155; border-radius: 16px; }
    .step-ok   { color: #22c55e; }
    .step-err  { color: #ef4444; }
    .step-warn { color: #f59e0b; }
    .icon-ok   { font-size: 1.1rem; }
    .engine-link { text-decoration: none; display: flex; align-items: center; gap: 10px;
                   padding: 12px 18px; border-radius: 10px; border: 1px solid #334155;
                   background: #0f172a; color: #e2e8f0; transition: all .2s; }
    .engine-link:hover { border-color: #6366f1; background: #1e1b4b; color: #a5b4fc; }
    code { background: #0f172a; padding: 1px 6px; border-radius: 4px; font-size: .85em; color: #a5b4fc; }
    .savit-logo { width: 48px; height: 48px; background: linear-gradient(135deg, #6366f1, #a78bfa);
                  border-radius: 14px; display: flex; align-items: center; justify-content: center;
                  font-size: 1.5rem; font-weight: 900; color: #fff; }
  </style>
</head>
<body>
<div class="container py-5" style="max-width:760px;">

  <div class="d-flex align-items-center gap-3 mb-5">
    <div class="savit-logo">S</div>
    <div>
      <h1 class="mb-0 fs-3 fw-bold">Savit Platform Setup</h1>
      <div class="text-muted small">v<?= SETUP_VERSION ?> &middot; One-shot installer</div>
    </div>
  </div>

  <!-- Setup Results -->
  <div class="setup-card p-4 mb-4">
    <h5 class="fw-semibold mb-3"><i class="bi bi-gear-fill me-2 text-primary"></i>Setup Results</h5>
    <div class="d-flex flex-column gap-2">
    <?php foreach ($results as $r): ?>
      <?php
        $icon  = match($r['status']) { 'ok' => 'check-circle-fill step-ok', 'err' => 'x-circle-fill step-err', default => 'exclamation-triangle-fill step-warn' };
        $cls   = match($r['status']) { 'ok' => 'step-ok', 'err' => 'step-err', default => 'step-warn' };
      ?>
      <div class="d-flex align-items-start gap-2">
        <i class="bi bi-<?= $icon ?> icon-ok mt-1 flex-shrink-0"></i>
        <span class="<?= $cls ?>"><?= $r['msg'] ?></span>
      </div>
    <?php endforeach; ?>
    </div>
  </div>

  <!-- Overall Status -->
  <?php if ($hasError): ?>
  <div class="alert alert-danger d-flex align-items-center gap-2">
    <i class="bi bi-x-octagon-fill fs-5"></i>
    <div><strong>Setup failed.</strong> Fix the errors above and refresh this page.</div>
  </div>
  <?php else: ?>
  <div class="alert alert-success d-flex align-items-center gap-2">
    <i class="bi bi-check-circle-fill fs-5"></i>
    <div><strong>Setup complete!</strong> All engines are ready. You can delete this file for security.</div>
  </div>
  <?php endif; ?>

  <!-- Engine Links -->
  <div class="setup-card p-4 mb-4">
    <h5 class="fw-semibold mb-3"><i class="bi bi-grid-3x3-gap me-2 text-info"></i>Open Engines</h5>
    <div class="d-grid gap-2">
    <?php foreach ($engines as $label => $path): ?>
      <a href="<?= htmlspecialchars($path) ?>" class="engine-link" target="_blank">
        <?php $icon = match(true) {
          str_contains($label, 'Dashboard')  => 'grid-3x3-gap-fill',
          str_contains($label, 'Audit')      => 'search',
          str_contains($label, 'Analytics')  => 'bar-chart-line-fill',
          str_contains($label, 'Content')    => 'lightning-fill',
          default => 'arrow-right'
        }; ?>
        <i class="bi bi-<?= $icon ?>"></i>
        <span><?= htmlspecialchars($label) ?></span>
        <i class="bi bi-box-arrow-up-right ms-auto text-muted"></i>
      </a>
    <?php endforeach; ?>
    </div>
  </div>

  <!-- Config Summary -->
  <div class="setup-card p-4 mb-4">
    <h5 class="fw-semibold mb-3"><i class="bi bi-sliders me-2 text-warning"></i>Active Configuration</h5>
    <table class="table table-sm table-dark mb-0" style="background:transparent;">
      <tbody>
        <tr><td class="text-muted" style="width:180px;">App URL</td><td><code><?= htmlspecialchars($_ENV['APP_URL'] ?? '—') ?></code></td></tr>
        <tr><td class="text-muted">Database</td><td><code><?= htmlspecialchars($cfg['dbname']) ?></code> @ <code><?= htmlspecialchars($cfg['host']) ?>:<?= $cfg['port'] ?></code></td></tr>
        <tr><td class="text-muted">DB User</td><td><code><?= htmlspecialchars($cfg['user']) ?></code></td></tr>
        <tr><td class="text-muted">Session Name</td><td><code><?= htmlspecialchars($_ENV['SESSION_NAME'] ?? 'savit_session') ?></code></td></tr>
        <tr><td class="text-muted">Timezone</td><td><code><?= htmlspecialchars($_ENV['APP_TIMEZONE'] ?? 'UTC') ?></code></td></tr>
        <tr><td class="text-muted">PageSpeed Key</td><td><code><?= ($_ENV['PAGESPEED_API_KEY'] ?? '') ? '✓ configured' : '✗ missing' ?></code></td></tr>
        <tr><td class="text-muted">Google OAuth</td><td><code><?= ($_ENV['GOOGLE_CLIENT_ID'] ?? '') ? '✓ configured' : '✗ missing' ?></code></td></tr>
        <tr><td class="text-muted">OpenAI Key</td><td><code><?= ($_ENV['OPENAI_API_KEY'] ?? '') ? '✓ configured' : '✗ missing' ?></code></td></tr>
      </tbody>
    </table>
  </div>

  <!-- Export / Import -->
  <div class="setup-card p-4 mb-4">
    <h5 class="fw-semibold mb-3"><i class="bi bi-arrow-left-right me-2 text-info"></i>Data Portability</h5>
    <div class="row g-3">
      <div class="col-md-6">
        <div class="border border-secondary rounded p-3 h-100">
          <h6 class="fw-semibold text-success"><i class="bi bi-download me-1"></i>Export</h6>
          <p class="text-muted small mb-2">Download all project data, OAuth tokens, page categories, and analytics snapshots as a JSON file.</p>
          <a href="?action=export" class="btn btn-sm btn-outline-success">
            <i class="bi bi-file-earmark-arrow-down me-1"></i>Download Export JSON
          </a>
        </div>
      </div>
      <div class="col-md-6">
        <div class="border border-secondary rounded p-3 h-100">
          <h6 class="fw-semibold text-warning"><i class="bi bi-upload me-1"></i>Import</h6>
          <p class="text-muted small mb-2">Paste the exported JSON to import data onto a new system. Uses INSERT IGNORE — safe to re-run.</p>
          <textarea id="import-json-in" class="form-control form-control-sm font-monospace mb-2" rows="3"
                    style="background:#0f172a;color:#e2e8f0;border-color:#334155;"
                    placeholder='Paste export JSON here…'></textarea>
          <button class="btn btn-sm btn-outline-warning" id="import-btn-ui">
            <i class="bi bi-upload me-1"></i>Import
          </button>
          <div id="import-result" class="small mt-2"></div>
        </div>
      </div>
    </div>
  </div>
  <script>
  document.getElementById('import-btn-ui')?.addEventListener('click', async () => {
    const json = document.getElementById('import-json-in').value.trim();
    const result = document.getElementById('import-result');
    if (!json) { result.innerHTML = '<span class="text-danger">Paste JSON first.</span>'; return; }
    let parsed; try { parsed = JSON.parse(json); } catch { result.innerHTML = '<span class="text-danger">Invalid JSON.</span>'; return; }
    result.innerHTML = '<span class="text-muted"><span class="spinner-border spinner-border-sm me-1"></span>Importing…</span>';
    try {
      const r = await fetch('?action=import', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify(parsed) });
      const j = await r.json();
      if (j.success) {
        result.innerHTML = '<span class="text-success">✅ Done: ' + Object.entries(j.results).map(([t,v])=>t+': '+v).join(' · ') + '</span>';
      } else {
        result.innerHTML = '<span class="text-danger">❌ ' + (j.message||'Failed') + '</span>';
      }
    } catch (e) { result.innerHTML = '<span class="text-danger">❌ ' + e.message + '</span>'; }
  });
  </script>

  <!-- Danger Zone -->
  <div class="setup-card p-4 border-danger" style="border-color:#7f1d1d !important;">
    <h5 class="fw-semibold mb-2 text-danger"><i class="bi bi-exclamation-triangle me-2"></i>Fresh Install (Danger Zone)</h5>
    <p class="text-muted small mb-3">Drops and recreates the entire database. <strong class="text-danger">All data will be lost.</strong></p>
    <a href="?fresh=1&confirm=YES" class="btn btn-sm btn-outline-danger"
       onclick="return confirm('This will DELETE ALL DATA. Are you absolutely sure?')">
      <i class="bi bi-trash me-1"></i>Drop & Recreate Database
    </a>
  </div>

  <p class="text-muted small text-center mt-4">
    <i class="bi bi-shield-lock me-1"></i>Delete <code>setup.php</code> after setup is complete for security.
  </p>
</div>
</body>
</html>
