#!/usr/bin/env node

require("dotenv").config();

const path = require("path");
const { execSync } = require("child_process");
const { PrismaClient } = require("../src/generated/client");

const BOOTSTRAP_USER_ID = "bootstrap-admin";
const DEFAULT_SYSTEM_CONFIG_ID = "default";
const backendRoot = path.resolve(__dirname, "..");

const resolveDatabaseUrl = (rawUrl) => {
  const backendRoot = path.resolve(__dirname, "..");
  const defaultDbPath = path.resolve(backendRoot, "prisma/dev.db");

  if (!rawUrl || String(rawUrl).trim().length === 0) {
    return `file:${defaultDbPath}`;
  }

  if (!String(rawUrl).startsWith("file:")) {
    return String(rawUrl);
  }

  const filePath = String(rawUrl).replace(/^file:/, "");
  const prismaDir = path.resolve(backendRoot, "prisma");
  const normalizedRelative = filePath.replace(/^\.\/?/, "");
  const hasLeadingPrismaDir =
    normalizedRelative === "prisma" || normalizedRelative.startsWith("prisma/");

  const absolutePath = path.isAbsolute(filePath)
    ? filePath
    : path.resolve(hasLeadingPrismaDir ? backendRoot : prismaDir, normalizedRelative);

  return `file:${absolutePath}`;
};

process.env.DATABASE_URL = resolveDatabaseUrl(process.env.DATABASE_URL);

const parseArgs = (argv) => {
  const parsed = {
    scenario: "",
    dryRun: false,
    allowProd: false,
  };

  for (let i = 0; i < argv.length; i += 1) {
    const token = argv[i];
    if (token === "--scenario") {
      parsed.scenario = String(argv[i + 1] || "").trim().toLowerCase();
      i += 1;
      continue;
    }
    if (token === "--dry-run") {
      parsed.dryRun = true;
      continue;
    }
    if (token === "--allow-production") {
      parsed.allowProd = true;
      continue;
    }
    if (token === "--help" || token === "-h") {
      parsed.help = true;
      continue;
    }
  }

  return parsed;
};

const usage = () => {
  console.log(`Usage:
  node scripts/simulate-auth-onboarding.cjs --scenario fresh
  node scripts/simulate-auth-onboarding.cjs --scenario migration

Options:
  --dry-run           Show what would change without modifying data
  --allow-production  Override production safety check (not recommended)
  --help, -h          Show this help
`);
};

const assertScenario = (scenario) => {
  if (scenario !== "fresh" && scenario !== "migration") {
    throw new Error("Invalid --scenario. Use 'fresh' or 'migration'.");
  }
};

const nowIso = () => new Date().toISOString();

const run = async () => {
  const args = parseArgs(process.argv.slice(2));
  if (args.help) {
    usage();
    return;
  }

  assertScenario(args.scenario);

const nodeEnv = process.env.NODE_ENV || "development";
  if (nodeEnv === "production" && !args.allowProd) {
    throw new Error(
      "Refusing to run in production. Pass --allow-production only if you explicitly intend this."
    );
  }

  // Keep migration history authoritative to avoid drift between db push and deploy.
  // Includes a self-heal path for the known duplicate-column failure on
  // 20260210153000_add_auth_onboarding_completed in local dev databases.
  if (nodeEnv !== "production") {
    const runDeploy = () =>
      execSync("npx prisma migrate deploy", {
        cwd: backendRoot,
        stdio: "pipe",
        env: {
          ...process.env,
          DATABASE_URL: process.env.DATABASE_URL,
        },
      });

    try {
      runDeploy();
    } catch (error) {
      const stdout =
        error && error.stdout
          ? Buffer.isBuffer(error.stdout)
            ? error.stdout.toString("utf8")
            : String(error.stdout)
          : "";
      const stderr =
        error && error.stderr
          ? Buffer.isBuffer(error.stderr)
            ? error.stderr.toString("utf8")
            : String(error.stderr)
          : "";
      const combined = `${stdout}\n${stderr}`;

      const canAutoResolve =
        combined.includes("Error: P3009") &&
        combined.includes("20260210153000_add_auth_onboarding_completed") &&
        combined.includes("duplicate column name: authOnboardingCompleted");

      if (!canAutoResolve) {
        throw error;
      }

      execSync(
        "npx prisma migrate resolve --applied 20260210153000_add_auth_onboarding_completed",
        {
          cwd: backendRoot,
          stdio: "pipe",
          env: {
            ...process.env,
            DATABASE_URL: process.env.DATABASE_URL,
          },
        }
      );
      runDeploy();
    }
  }

  const prisma = new PrismaClient();

  try {
    const before = {
      activeUsers: await prisma.user.count({ where: { isActive: true } }),
      users: await prisma.user.count(),
      drawings: await prisma.drawing.count(),
      collections: await prisma.collection.count(),
      auth: await prisma.systemConfig.findUnique({
        where: { id: DEFAULT_SYSTEM_CONFIG_ID },
        select: {
          authEnabled: true,
          authOnboardingCompleted: true,
          registrationEnabled: true,
        },
      }),
    };

    console.log(`[simulate-auth-onboarding] DATABASE_URL=${process.env.DATABASE_URL}`);
    console.log(`[simulate-auth-onboarding] NODE_ENV=${nodeEnv}`);
    console.log(`[simulate-auth-onboarding] scenario=${args.scenario}`);
    console.log("[simulate-auth-onboarding] before:", before);

    if (args.dryRun) {
      console.log("[simulate-auth-onboarding] dry-run only. No data changed.");
      return;
    }

    await prisma.$transaction(async (tx) => {
      await tx.systemConfig.upsert({
        where: { id: DEFAULT_SYSTEM_CONFIG_ID },
        update: {
          authEnabled: false,
          authOnboardingCompleted: false,
          registrationEnabled: false,
        },
        create: {
          id: DEFAULT_SYSTEM_CONFIG_ID,
          authEnabled: false,
          authOnboardingCompleted: false,
          registrationEnabled: false,
          authLoginRateLimitEnabled: true,
          authLoginRateLimitWindowMs: 15 * 60 * 1000,
          authLoginRateLimitMax: 20,
        },
      });

      await tx.user.updateMany({
        data: {
          isActive: false,
          mustResetPassword: true,
        },
      });

      await tx.user.upsert({
        where: { id: BOOTSTRAP_USER_ID },
        update: {
          email: "bootstrap@excalidash.local",
          username: null,
          passwordHash: "",
          name: "Bootstrap Admin",
          role: "ADMIN",
          mustResetPassword: true,
          isActive: false,
        },
        create: {
          id: BOOTSTRAP_USER_ID,
          email: "bootstrap@excalidash.local",
          username: null,
          passwordHash: "",
          name: "Bootstrap Admin",
          role: "ADMIN",
          mustResetPassword: true,
          isActive: false,
        },
      });

      if (args.scenario === "fresh") {
        await tx.drawing.deleteMany({});
        await tx.collection.deleteMany({});
        await tx.library.deleteMany({});
        await tx.user.deleteMany({
          where: {
            id: {
              not: BOOTSTRAP_USER_ID,
            },
          },
        });
        return;
      }

      // Migration simulation:
      // 1) Reassign existing data ownership to bootstrap user
      // 2) Ensure at least one drawing+collection exists so UI shows migration messaging
      await tx.collection.updateMany({
        data: { userId: BOOTSTRAP_USER_ID },
      });
      await tx.drawing.updateMany({
        data: { userId: BOOTSTRAP_USER_ID },
      });

      const collectionCount = await tx.collection.count();
      let targetCollectionId = null;

      if (collectionCount === 0) {
        targetCollectionId = `sim-migration-col-${Date.now()}`;
        await tx.collection.create({
          data: {
            id: targetCollectionId,
            name: "Migrated Collection",
            userId: BOOTSTRAP_USER_ID,
          },
        });
      } else {
        const existing = await tx.collection.findFirst({
          where: { userId: BOOTSTRAP_USER_ID },
          select: { id: true },
          orderBy: { createdAt: "asc" },
        });
        targetCollectionId = existing ? existing.id : null;
      }

      const drawingCount = await tx.drawing.count();
      if (drawingCount === 0) {
        await tx.drawing.create({
          data: {
            id: `sim-migration-draw-${Date.now()}`,
            name: "Migrated Drawing",
            elements: "[]",
            appState: "{}",
            files: "{}",
            preview: null,
            version: 1,
            userId: BOOTSTRAP_USER_ID,
            collectionId: targetCollectionId,
          },
        });
      }
    });

    const after = {
      activeUsers: await prisma.user.count({ where: { isActive: true } }),
      users: await prisma.user.count(),
      drawings: await prisma.drawing.count(),
      collections: await prisma.collection.count(),
      auth: await prisma.systemConfig.findUnique({
        where: { id: DEFAULT_SYSTEM_CONFIG_ID },
        select: {
          authEnabled: true,
          authOnboardingCompleted: true,
          registrationEnabled: true,
        },
      }),
    };

    console.log("[simulate-auth-onboarding] after:", after);
    console.log(`[simulate-auth-onboarding] completed at ${nowIso()}`);
    console.log(
      "[simulate-auth-onboarding] If your backend is already running, wait ~5 seconds (auth cache TTL) or restart before refreshing the UI."
    );
  } finally {
    await prisma.$disconnect().catch(() => {});
  }
};

run().catch((error) => {
  console.error("simulate-auth-onboarding failed:", error.message || error);
  process.exitCode = 1;
});
