/**
 * Regression tests for getLocalVersion() — DC-033.
 *
 * The SelfUpdater's getLocalVersion() reads package.json + VERSION from the
 * filesystem relative to its own __dirname. server.js loads it via
 * `./src/docker/self-updater`, so __dirname inside the container is
 * `/app/src/docker` — which has no package.json. The function's outer
 * try/catch silently swallowed the ENOENT and returned the
 * `{ version: '0.0.0', commit: null }` fallback, making every DashCaddy
 * host running v1.14.x (≤ v1.14.8) appear to be at "version 0.0.0" in the
 * dashboard and "always outdated" to checkForUpdate().
 *
 * DC-033 fixed it by walking a candidate list (api root first, __dirname
 * second). DC-035 is the regression test: if anyone re-introduces the
 * __dirname antipattern — or accidentally deletes the api-root package.json
 * — this suite will fail loudly.
 *
 * Loading pattern matters: this test loads `./src/docker/self-updater` to
 * match what server.js does at runtime. The legacy `./self-updater` path
 * (from /app) was deleted by DC-036, so the only require() that exists
 * now is the docker copy.
 */

const path = require('path');

describe('SelfUpdater.getLocalVersion() — DC-033 regression', () => {
  // Resolve from a known cwd so require('./src/docker/self-updater') lands
  // on the api-root copy, not some other relative-resolution target.
  const API_ROOT = path.join(__dirname, '..');
  let SelfUpdater;

  beforeAll(() => {
    // Sanity check: the file must exist at the expected path.
    const target = path.join(API_ROOT, 'src', 'docker', 'self-updater.js');
    expect(() => require.resolve(target)).not.toThrow();

    const mod = require(path.join(API_ROOT, 'src', 'docker', 'self-updater.js'));
    SelfUpdater = mod.SelfUpdater || mod.default || mod;
  });

  test('module loads and exports a SelfUpdater class', () => {
    expect(typeof SelfUpdater).toBe('function');
    expect(SelfUpdater.name).toBe('SelfUpdater');
  });

  describe('getLocalVersion() returns real version + commit', () => {
    let result;

    beforeAll(() => {
      // Empty options — DEFAULTS will be used; getLocalVersion doesn't
      // need config to read sibling files.
      const instance = new SelfUpdater({});
      result = instance.getLocalVersion();
    });

    test('result is an object with version + commit', () => {
      expect(result).toEqual(expect.objectContaining({
        version: expect.any(String),
        commit: expect.any(String),
      }));
    });

    test('version is NOT the 0.0.0 fallback (the DC-033 bug)', () => {
      // If this fails, someone re-introduced the __dirname antipattern.
      expect(result.version).not.toBe('0.0.0');
    });

    test('version is a valid semver string', () => {
      // Anchored semver: MAJOR.MINOR.PATCH with optional pre-release/build.
      // Reject '0.0.0' explicitly and anything without 3 numeric components.
      expect(result.version).toMatch(/^\d+\.\d+\.\d+/);
      const parts = result.version.split('.');
      expect(parts.length).toBeGreaterThanOrEqual(3);
      for (const part of parts) {
        // Allow pre-release suffixes (e.g. "1-rc1") but the first 3 must be numeric.
        const numeric = part.split('-')[0].split('+')[0];
        expect(numeric).toMatch(/^\d+$/);
      }
    });

    test('commit contains a git SHA and is not null', () => {
      expect(result.commit).not.toBeNull();
      expect(result.commit).toMatch(/(?:^|-)[0-9a-f]{7,40}$/);
    });
  });

  describe('repeat construction uses the same resolved metadata', () => {
    test('a second instance resolves the same non-fallback version metadata', () => {
      const mod = require(path.join(API_ROOT, 'src', 'docker', 'self-updater.js'));
      const Cls = mod.SelfUpdater || mod.default || mod;
      const result = new Cls({}).getLocalVersion();
      expect(result.version).not.toBe('0.0.0');
      expect(result.commit).toMatch(/(?:^|-)[0-9a-f]{7,40}$/);
    });
  });
});