#!/usr/bin/env node
/**
 * ensureExerciseLibrary — runs at every container boot from
 * docker_entrypoint.sh. Inserts every exercise from
 * /app/prisma/exercises.seed.json into the Exercise table for every
 * existing user, using `INSERT OR IGNORE` keyed on (userId, name).
 *
 * Properties:
 *   - Multi-user-aware. Iterates all rows in `User` so every user on the
 *     instance gets the same curated library.
 *   - Idempotent. Re-running is a no-op for exercises that already exist.
 *   - Additive only. Never deletes or updates existing rows. Users keep
 *     their own custom exercises (isCustom=true) untouched, and existing
 *     library entries are not reshaped if the maintainer changed the
 *     description/inputFields/etc. for them downstream.
 *   - Cheap. Wrapped in a single transaction; ~164 rows x N users runs in
 *     well under a second.
 *
 * Invoked from docker_entrypoint.sh after the schema-compat ALTERs:
 *   node /app/prisma/ensureExerciseLibrary.cjs --db /data/app.db --json /app/prisma/exercises.seed.json
 *
 * Uses the sqlite3 CLI (already installed in the runner image) instead of a
 * Node SQLite binding so we don't have to ship a native dep.
 */

const fs = require('fs');
const crypto = require('crypto');
const { execFileSync } = require('child_process');

function arg(name) {
  const i = process.argv.indexOf(name);
  return i >= 0 ? process.argv[i + 1] : null;
}

const dbPath = arg('--db');
const jsonPath = arg('--json');

if (!dbPath || !jsonPath) {
  console.error('usage: ensureExerciseLibrary.cjs --db <path> --json <path>');
  process.exit(64);
}

if (!fs.existsSync(dbPath)) {
  console.error(`[ensure-library] db not found: ${dbPath}`);
  process.exit(0); // soft-fail; entrypoint should keep going
}
if (!fs.existsSync(jsonPath)) {
  console.error(`[ensure-library] library json not found: ${jsonPath}`);
  process.exit(0);
}

const library = JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
if (!Array.isArray(library) || library.length === 0) {
  console.error('[ensure-library] library is empty; nothing to do');
  process.exit(0);
}

// Get all user ids
const usersRaw = execFileSync('sqlite3', [dbPath, 'SELECT id FROM User;'], {
  encoding: 'utf8',
});
const userIds = usersRaw.split('\n').map((s) => s.trim()).filter(Boolean);

if (userIds.length === 0) {
  console.error('[ensure-library] no users yet; skipping (will run on next boot after a user exists)');
  process.exit(0);
}

// Quote a string for safe use as a SQLite single-quoted literal.
const q = (s) => `'${String(s).replace(/'/g, "''")}'`;
// Generate a 25-char id with a "c" prefix to roughly match cuid shape.
// Uniqueness comes from 12 random bytes; collision probability is negligible.
const newId = () => 'c' + crypto.randomBytes(12).toString('hex');

const stmts = ['BEGIN;'];
let inserts = 0;
for (const userId of userIds) {
  for (const ex of library) {
    inserts++;
    const muscleGroups = q(JSON.stringify(ex.muscleGroups || []));
    const inputFields = q(
      JSON.stringify(ex.inputFields || ['sets', 'reps', 'weight']),
    );
    const defaultWeightUnit =
      ex.defaultWeightUnit == null ? 'NULL' : q(ex.defaultWeightUnit);
    const description = ex.description == null ? 'NULL' : q(ex.description);

    stmts.push(
      `INSERT OR IGNORE INTO Exercise ` +
        `(id, userId, name, description, muscleGroups, type, inputFields, defaultWeightUnit, isCustom, createdAt) ` +
        `VALUES (${q(newId())}, ${q(userId)}, ${q(ex.name)}, ${description}, ` +
        `${muscleGroups}, ${q(ex.type)}, ${inputFields}, ${defaultWeightUnit}, ` +
        `0, CURRENT_TIMESTAMP);`,
    );
  }
}
stmts.push('COMMIT;');

execFileSync('sqlite3', [dbPath], { input: stmts.join('\n') });
console.error(
  `[ensure-library] processed ${userIds.length} user(s) x ${library.length} exercise(s) ` +
    `(${inserts} INSERT OR IGNORE statements)`,
);
