#!/usr/bin/env node
/**
 * ensureExerciseLibrary — runs at every container boot from
 * docker_entrypoint.sh. Reconciles every existing user's exercise
 * library with the curated /app/prisma/exercises.seed.json:
 *
 *   - INSERT new library entries (rows that don't exist yet for this
 *     user) — same as previous behavior.
 *   - UPDATE existing rows where `isCustom = 0` to match the curated
 *     values (description, type, muscleGroups, inputFields,
 *     defaultWeightUnit). This propagates maintainer-side fixes
 *     (e.g. correcting cardio inputFields) to existing installs
 *     without overwriting user-customized rows.
 *   - SKIP rows where `isCustom = 1` — user customizations win, end
 *     of story. PATCH /api/exercises/[id] flips isCustom to 1 on
 *     any user edit so this rule is honored automatically.
 *
 * Multi-user-aware: iterates all rows in `User`. Idempotent.
 * Additive only — exercises removed from the curated JSON are NOT
 * deleted from existing installs (users may have logged sets
 * against them).
 *
 * Cheap: a single transaction, ~164 rows × 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 in the runner image) instead of a
 * Node SQLite binding so we don't 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);
}

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');
  process.exit(0);
}

const q = (s) => `'${String(s).replace(/'/g, "''")}'`;
const newId = () => 'c' + crypto.randomBytes(12).toString('hex');

const stmts = ['BEGIN;'];
let upserts = 0;
for (const userId of userIds) {
  for (const ex of library) {
    upserts++;
    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);

    // INSERT a new row for this (userId, name) pair, or UPDATE the
    // existing one IF it's not user-customized. The WHERE clause on
    // the DO UPDATE side is the key piece — skips rows the user has
    // edited (isCustom=1). SQLite supports this since 3.24 (2018).
    stmts.push(
      `INSERT 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) ` +
        `ON CONFLICT(userId, name) DO UPDATE SET ` +
        `description = excluded.description, ` +
        `muscleGroups = excluded.muscleGroups, ` +
        `type = excluded.type, ` +
        `inputFields = excluded.inputFields, ` +
        `defaultWeightUnit = excluded.defaultWeightUnit ` +
        `WHERE Exercise.isCustom = 0;`,
    );
  }
}
stmts.push('COMMIT;');

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