#!/usr/bin/env node

/**
 * Migration Test Script
 *
 * Tests that all migrations can run successfully up and down.
 * This script:
 * 1. Connects to a test database
 * 2. Runs all migrations down (clean slate)
 * 3. Runs all migrations up
 * 4. Verifies tables were created
 * 5. Runs all migrations down (test rollback)
 * 6. Runs all migrations up again (test idempotency)
 * 7. Reports results
 *
 * Usage:
 *   NODE_ENV=test npm run test:migrations
 *
 * Requires:
 *   - Test database to exist (create with: npm run db:create)
 *   - Environment variables set for test database connection
 */

const { execSync } = require("child_process");
const path = require("path");

// Colors for console output
const colors = {
  reset: "\x1b[0m",
  green: "\x1b[32m",
  red: "\x1b[31m",
  yellow: "\x1b[33m",
  blue: "\x1b[34m",
};

function log(message, color = colors.reset) {
  console.log(`${color}${message}${colors.reset}`);
}

function logStep(step, message) {
  log(`\n[${step}] ${message}`, colors.blue);
}

function logSuccess(message) {
  log(`  ✓ ${message}`, colors.green);
}

function logError(message) {
  log(`  ✗ ${message}`, colors.red);
}

function logWarning(message) {
  log(`  ⚠ ${message}`, colors.yellow);
}

function runCommand(command, description) {
  try {
    log(`  Running: ${command}`, colors.yellow);
    const output = execSync(command, {
      cwd: path.resolve(__dirname, ".."),
      encoding: "utf-8",
      stdio: ["pipe", "pipe", "pipe"],
      env: { ...process.env, NODE_ENV: process.env.NODE_ENV || "test" },
    });
    if (output.trim()) {
      console.log(output);
    }
    logSuccess(description);
    return { success: true, output };
  } catch (error) {
    logError(`${description} failed`);
    console.error(error.stderr || error.message);
    return { success: false, error };
  }
}

async function main() {
  log("\n========================================", colors.blue);
  log("  Migration Test Suite", colors.blue);
  log("========================================\n", colors.blue);

  const env = process.env.NODE_ENV;

  // Safety checks - only allow running against test database
  if (!env) {
    logError("NODE_ENV is not set!");
    logError("This script will DELETE ALL DATA in the target database.");
    logError("You must explicitly set NODE_ENV=test to run this script.");
    log("\nUsage: NODE_ENV=test npm run test:migrations\n");
    process.exit(1);
  }

  if (env.toLowerCase() !== "test") {
    logWarning(`Unrecognized NODE_ENV: ${env}`);
    logWarning("This script will DELETE ALL DATA in the target database.");
    logWarning("Recommended: NODE_ENV=test npm run test:migrations");
    log("");
  }

  log(`Environment: ${env}`);

  const results = {
    steps: [],
    passed: 0,
    failed: 0,
  };

  function recordResult(step, success) {
    results.steps.push({ step, success });
    if (success) {
      results.passed++;
    } else {
      results.failed++;
    }
  }

  // Step 1: Check migration status
  logStep(1, "Checking current migration status");
  const statusResult = runCommand(
    "npx sequelize-cli db:migrate:status",
    "Migration status check"
  );
  recordResult("Status check", statusResult.success);

  // Step 2: Undo all migrations (clean slate)
  logStep(2, "Undoing all migrations (clean slate)");
  const undoAllResult = runCommand(
    "npx sequelize-cli db:migrate:undo:all",
    "Undo all migrations"
  );
  recordResult("Undo all migrations", undoAllResult.success);

  if (!undoAllResult.success) {
    logWarning("Undo failed - database may already be empty, continuing...");
  }

  // Step 3: Run all migrations up
  logStep(3, "Running all migrations up");
  const migrateUpResult = runCommand(
    "npx sequelize-cli db:migrate",
    "Run all migrations"
  );
  recordResult("Migrate up", migrateUpResult.success);

  if (!migrateUpResult.success) {
    logError("Migration up failed - cannot continue");
    printSummary(results);
    process.exit(1);
  }

  // Step 4: Verify migration status shows all executed
  logStep(4, "Verifying all migrations executed");
  const verifyResult = runCommand(
    "npx sequelize-cli db:migrate:status",
    "Verify migration status"
  );
  recordResult("Verify status", verifyResult.success);

  // Step 5: Test rollback - undo all migrations
  logStep(5, "Testing rollback - undoing all migrations");
  const rollbackResult = runCommand(
    "npx sequelize-cli db:migrate:undo:all",
    "Rollback all migrations"
  );
  recordResult("Rollback", rollbackResult.success);

  if (!rollbackResult.success) {
    logError("Rollback failed - down migrations have issues");
    printSummary(results);
    process.exit(1);
  }

  // Step 6: Test idempotency - run migrations up again
  logStep(6, "Testing idempotency - running migrations up again");
  const idempotencyResult = runCommand(
    "npx sequelize-cli db:migrate",
    "Re-run all migrations"
  );
  recordResult("Idempotency test", idempotencyResult.success);

  if (!idempotencyResult.success) {
    logError("Idempotency test failed - migrations may not be repeatable");
    printSummary(results);
    process.exit(1);
  }

  // Step 7: Final status check
  logStep(7, "Final migration status");
  const finalStatusResult = runCommand(
    "npx sequelize-cli db:migrate:status",
    "Final status check"
  );
  recordResult("Final status", finalStatusResult.success);

  printSummary(results);

  if (results.failed > 0) {
    process.exit(1);
  }

  log("\nMigration tests completed successfully!", colors.green);
  process.exit(0);
}

function printSummary(results) {
  log("\n========================================", colors.blue);
  log("  Test Summary", colors.blue);
  log("========================================\n", colors.blue);

  results.steps.forEach(({ step, success }) => {
    if (success) {
      logSuccess(step);
    } else {
      logError(step);
    }
  });

  log(`\nTotal: ${results.passed} passed, ${results.failed} failed`);
}

main().catch((error) => {
  logError("Unexpected error:");
  console.error(error);
  process.exit(1);
});
