import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import * as fs from 'node:fs';
import * as path from 'node:path';
import { execFileSync } from 'node:child_process';

import { setupTestDb, type TestDb } from './helpers/db';

let db: TestDb;
let library: { name: string }[];

beforeAll(async () => {
  db = await setupTestDb();
  // The library JSON shipped with the app — same one consumed in prod.
  library = JSON.parse(
    fs.readFileSync(
      path.resolve(__dirname, '..', 'prisma', 'exercises.seed.json'),
      'utf8',
    ),
  );
});

afterAll(async () => {
  await db?.cleanup();
});

describe('ensureExerciseLibrary.cjs (runtime entrypoint script)', () => {
  it('inserts the full library for every user, idempotently', async () => {
    // Two users, no exercises yet.
    const alice = await db.prisma.user.create({
      data: { email: 'alice@test', passwordHash: 'x', isAdmin: true },
    });
    const bob = await db.prisma.user.create({
      data: { email: 'bob@test', passwordHash: 'x' },
    });

    const scriptPath = path.resolve(
      __dirname,
      '..',
      'prisma',
      'ensureExerciseLibrary.cjs',
    );
    const jsonPath = path.resolve(
      __dirname,
      '..',
      'prisma',
      'exercises.seed.json',
    );

    const run = () =>
      execFileSync(
        'node',
        [scriptPath, '--db', db.dbPath, '--json', jsonPath],
        { stdio: 'pipe' },
      );

    run();

    const aliceCount = await db.prisma.exercise.count({
      where: { userId: alice.id },
    });
    const bobCount = await db.prisma.exercise.count({
      where: { userId: bob.id },
    });
    expect(aliceCount).toBe(library.length);
    expect(bobCount).toBe(library.length);

    // Idempotency — second run must not duplicate or change counts.
    run();
    expect(
      await db.prisma.exercise.count({ where: { userId: alice.id } }),
    ).toBe(library.length);
    expect(
      await db.prisma.exercise.count({ where: { userId: bob.id } }),
    ).toBe(library.length);

    // A user's own custom exercise with the same name as a library entry
    // must NOT be overwritten by a subsequent ensure pass.
    const targetName = library[0].name;
    await db.prisma.exercise.deleteMany({
      where: { userId: bob.id, name: targetName },
    });
    await db.prisma.exercise.create({
      data: {
        userId: bob.id,
        name: targetName,
        muscleGroups: '[]',
        type: 'custom-by-bob',
        isCustom: true,
      },
    });

    run();

    const bobOwn = await db.prisma.exercise.findUnique({
      where: { userId_name: { userId: bob.id, name: targetName } },
    });
    expect(bobOwn?.isCustom).toBe(true);
    expect(bobOwn?.type).toBe('custom-by-bob');
  });
});
