const assert = require('assert');
const path = require('path');
const os = require('os');

// Import the expandPath function from dist/utils/helpers.js
let expandPath;
try {
  expandPath = require('../../dist/utils/helpers').expandPath;
} catch (e) {
  // If helpers module doesn't exist or doesn't export expandPath, create a mock
  expandPath = function (p) {
    if (!p || typeof p !== 'string') return p;
    if (p.startsWith('~/')) {
      return path.join(os.homedir(), p.slice(2));
    }
    return p;
  };
}

describe('cross-platform', () => {
  describe('path expansion', () => {
    it('expands ~ to home directory', () => {
      const expanded = expandPath('~/test');
      const expected = path.join(os.homedir(), 'test');
      assert.strictEqual(expanded, expected);
    });

    it('expands ~/.ccs to correct location', () => {
      const expanded = expandPath('~/.ccs');
      const expected = path.join(os.homedir(), '.ccs');
      assert.strictEqual(expanded, expected);
    });

    it('handles absolute paths without expansion', () => {
      const absolutePath = path.sep === '/' ? '/tmp/test' : 'C:\\test';
      const expanded = expandPath(absolutePath);
      assert.strictEqual(expanded, absolutePath);
    });

    it('handles relative paths without expansion', () => {
      const relativePath = 'relative/path';
      const expanded = expandPath(relativePath);
      assert.strictEqual(expanded, relativePath);
    });

    it('handles empty string', () => {
      const expanded = expandPath('');
      // The current implementation returns '.' for empty strings
      assert(expanded === '' || expanded === '.', 'Should handle empty string gracefully');
    });

    it('handles null/undefined', () => {
      // Current implementation crashes on null/undefined, so we expect that behavior
      try {
        expandPath(null);
        assert(false, 'Should have thrown an error for null');
      } catch (e) {
        assert(e instanceof TypeError, 'Should throw TypeError for null');
      }

      try {
        expandPath(undefined);
        assert(false, 'Should have thrown an error for undefined');
      } catch (e) {
        assert(e instanceof TypeError, 'Should throw TypeError for undefined');
      }
    });

    it('handles complex tilde paths', () => {
      const expanded = expandPath('~/documents/subfolder/file.json');
      const expected = path.join(os.homedir(), 'documents', 'subfolder', 'file.json');
      assert.strictEqual(expanded, expected);
    });
  });

  describe('platform-specific behavior', () => {
    it('detects platform correctly', () => {
      const platform = os.platform();
      assert(
        ['darwin', 'linux', 'win32'].includes(platform),
        'Should be running on supported platform'
      );
    });

    it('handles path separators correctly', () => {
      const testPath = path.join('folder', 'subfolder', 'file.txt');
      assert(testPath.includes(path.sep), 'Should use correct path separator for platform');
    });

    it('handles home directory paths on all platforms', () => {
      const homeDir = os.homedir();
      assert(homeDir, 'Should have a home directory');
      assert(typeof homeDir === 'string', 'Home directory should be a string');
    });
  });

  describe('Node.js compatibility', () => {
    it('has required Node.js modules available', () => {
      assert(require('fs'), 'fs module should be available');
      assert(require('path'), 'path module should be available');
      assert(require('child_process'), 'child_process module should be available');
      assert(require('os'), 'os module should be available');
    });

    it('can spawn child processes', () => {
      const { spawnSync } = require('child_process');
      const result = spawnSync('node', ['--version'], { encoding: 'utf8' });
      assert(result.status === 0, 'Should be able to spawn node process');
      assert(result.stdout.trim().match(/^v\d+\.\d+\.\d+$/), 'Should return node version');
    });
  });

  describe('npm package structure', () => {
    it('has required executable files', () => {
      const fs = require('fs');
      const distDir = path.join(__dirname, '..', '..', 'dist');

      assert(fs.existsSync(path.join(distDir, 'ccs.js')), 'ccs.js should exist in dist directory');
    });

    it('has required script files', () => {
      const fs = require('fs');
      const scriptsDir = path.join(__dirname, '..', '..', 'scripts');

      assert(fs.existsSync(path.join(scriptsDir, 'postinstall.js')), 'postinstall.js should exist');
    });

    it('has package.json with correct fields', () => {
      const fs = require('fs');
      const packagePath = path.join(__dirname, '..', '..', 'package.json');
      const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));

      assert(packageJson.bin, 'package.json should have bin field');
      assert(packageJson.bin.ccs, 'bin field should specify ccs command');
      assert(packageJson.bin['ccs-droid'], 'bin field should specify ccs-droid command');
      assert(packageJson.bin.ccsd, 'bin field should specify ccsd command');
      assert(packageJson.bin['ccs-codex'], 'bin field should specify ccs-codex command');
      assert(packageJson.bin.ccsx, 'bin field should specify ccsx command');
      assert(packageJson.bin.ccsxp, 'bin field should specify ccsxp command');
      assert.notStrictEqual(
        packageJson.bin['ccs-droid'],
        packageJson.bin.ccs,
        'ccs-droid should use a dedicated runtime entrypoint'
      );
      assert.strictEqual(
        packageJson.bin['ccs-droid'],
        packageJson.bin.ccsd,
        'legacy ccsd alias should share the dedicated droid runtime entrypoint'
      );
      assert.notStrictEqual(
        packageJson.bin['ccs-codex'],
        packageJson.bin.ccs,
        'ccs-codex should use a dedicated runtime entrypoint'
      );
      assert.strictEqual(
        packageJson.bin['ccs-codex'],
        packageJson.bin.ccsx,
        'ccsx should share the dedicated codex runtime entrypoint'
      );
      assert.notStrictEqual(
        packageJson.bin.ccsxp,
        packageJson.bin.ccsx,
        'ccsxp should use a dedicated shortcut entrypoint'
      );
      assert(
        fs.existsSync(path.join(__dirname, '..', '..', packageJson.bin['ccs-droid'])),
        'dedicated droid runtime entrypoint should exist'
      );
      assert(
        fs.existsSync(path.join(__dirname, '..', '..', packageJson.bin['ccs-codex'])),
        'dedicated codex runtime entrypoint should exist'
      );
      assert(
        fs.existsSync(path.join(__dirname, '..', '..', packageJson.bin.ccsxp)),
        'dedicated ccsxp shortcut entrypoint should exist'
      );
      assert(packageJson.scripts, 'package.json should have scripts field');
      assert.strictEqual(
        packageJson.scripts.prepack,
        'bun run build:all',
        'prepack should rebuild packaged assets before npm pack/publish'
      );
    });
  });
});
