/**
 * Tripwire: the auto-update feature requires three things in
 * package.json that are easy to lose in a dep refresh:
 *
 *   1. `update-notifier` in `dependencies` — drives the npm-CLI
 *      banner. Missing → dynamic import in updateNotifier.js
 *      silently no-ops (good fail-safe, but the banner disappears
 *      without any louder signal).
 *   2. `electron-updater` in `optionalDependencies` — drives the
 *      Electron in-app update dialog. Missing → autoUpdate.js
 *      silently no-ops.
 *   3. `build.publish` config — pointed at the GitHub Releases the
 *      Electron updater reads `latest.yml` from. Missing → the
 *      packaged Electron app never sees updates even when
 *      `electron-updater` is installed.
 *
 * Each is a silent failure on its own. Together they make the
 * feature look "shipped" but actually inert. This test forces a
 * loud CI signal when any of the three goes missing.
 *
 * If you INTENTIONALLY remove auto-update, change this test in the
 * same commit and explain why in the diff. Don't just delete it.
 */

import { describe, test, expect } from '@jest/globals';
import { readFileSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';

const __dirname = dirname(fileURLToPath(import.meta.url));
const REPO_ROOT = join(__dirname, '..', '..');
const pkg = JSON.parse(readFileSync(join(REPO_ROOT, 'package.json'), 'utf8'));

describe('package.json — auto-update presence', () => {
  test('update-notifier is in dependencies (CLI banner)', () => {
    expect(pkg.dependencies).toBeDefined();
    expect(pkg.dependencies['update-notifier']).toBeTruthy();
  });

  test('electron-updater is in optionalDependencies (Electron build only)', () => {
    expect(pkg.optionalDependencies?.['electron-updater']).toBeTruthy();
  });

  test('electron-builder has a publish provider configured', () => {
    expect(pkg.build).toBeDefined();
    const publishField = pkg.build.publish;
    expect(Array.isArray(publishField) || (publishField && typeof publishField === 'object')).toBe(true);
    const entries = Array.isArray(publishField) ? publishField : [publishField];
    expect(entries.length).toBeGreaterThan(0);
    for (const entry of entries) {
      expect(entry.provider).toBeTruthy();
    }
  });

  test('GitHub publish target points at a real owner+repo (not the boilerplate `your-org`/`your-repo`)', () => {
    const entries = Array.isArray(pkg.build.publish) ? pkg.build.publish : [pkg.build.publish];
    const github = entries.find(e => e.provider === 'github');
    if (!github) return;        // other providers (S3, etc.) are fine
    expect(github.owner).toBeTruthy();
    expect(github.repo).toBeTruthy();
    // Common copy-paste placeholders.
    expect(github.owner).not.toMatch(/^(your-org|TODO|placeholder)$/i);
    expect(github.repo).not.toMatch(/^(your-repo|TODO|placeholder)$/i);
  });

  test('update-notifier source file exists and is referenced by the CLI entry point', () => {
    // Tripwire against accidental file deletion. The runtime is
    // tolerant of missing dependencies (dynamic import), but if the
    // wrapper FILE goes missing the import line crashes.
    expect(() => readFileSync(join(REPO_ROOT, 'src/utilities/updateNotifier.js'), 'utf8')).not.toThrow();
    const cliEntry = readFileSync(join(REPO_ROOT, 'bin/cli.js'), 'utf8');
    expect(cliEntry).toMatch(/from\s+['"]\.\.\/src\/utilities\/updateNotifier\.js['"]/);
  });

  test('electron autoUpdate source file exists and is referenced by electron/main.js', () => {
    expect(() => readFileSync(join(REPO_ROOT, 'electron/autoUpdate.js'), 'utf8')).not.toThrow();
    const mainEntry = readFileSync(join(REPO_ROOT, 'electron/main.js'), 'utf8');
    expect(mainEntry).toMatch(/from\s+['"]\.\/autoUpdate\.js['"]/);
  });
});
