import { expect, test, describe, beforeEach, afterEach } from 'bun:test';
import * as path from 'path';
import * as os from 'os';
import { expandPath } from '../../../src/utils/helpers';

describe('expandPath', () => {
  const originalEnv = { ...process.env };
  const HOME = os.homedir();

  beforeEach(() => {
    process.env.TEST_HOME = '/custom/home';
    process.env.TEST_VAR = 'foo';
  });

  afterEach(() => {
    process.env = { ...originalEnv };
  });

  test('1. Tilde expansion: ~/path -> /home/user/path', () => {
    expect(expandPath('~/test/file.txt')).toBe(path.join(HOME, 'test/file.txt'));
  });

  test('2. Windows tilde with backslash: ~\\path', () => {
    // expandPath handles both ~/ and ~\ regardless of platform
    expect(expandPath('~\\test\\file.txt')).toBe(path.join(HOME, 'test/file.txt'));
  });

  test('3. Environment variable expansion: ${VAR}/path', () => {
    expect(expandPath('${TEST_HOME}/file.txt')).toBe(path.normalize('/custom/home/file.txt'));
  });

  test('4. Dollar sign env vars: $VAR/path', () => {
    expect(expandPath('$TEST_HOME/file.txt')).toBe(path.normalize('/custom/home/file.txt'));
  });

  test('5. Windows %VAR% expansion: %VAR%\\path (simulated)', () => {
    // We can't easily mock process.platform if it's not win32,
    // but the function check process.platform === 'win32'
    if (process.platform === 'win32') {
      expect(expandPath('%TEST_HOME%\\file.txt')).toBe(path.normalize('/custom/home/file.txt'));
    } else {
      // Should remain unchanged on non-windows (but separators normalized)
      expect(expandPath('%TEST_HOME%\\file.txt')).toBe(path.normalize('%TEST_HOME%/file.txt'));
    }
  });

  test('6. Mixed path separators normalization', () => {
    const result = expandPath('path/to\\some/file');
    expect(result).toBe(path.normalize('path/to/some/file'));
  });

  test('7. Nested env vars: ${HOME}/${VAR}/path', () => {
    expect(expandPath('${TEST_HOME}/${TEST_VAR}/file.txt')).toBe(
      path.normalize('/custom/home/foo/file.txt')
    );
  });

  test('8. Empty/null path handling', () => {
    expect(expandPath('')).toBe('.');
  });

  test('9. Already absolute paths stay unchanged', () => {
    const absPath = '/absolute/path';
    expect(expandPath(absPath)).toBe(path.normalize(absPath));
  });

  test('10. Undefined env vars -> empty string', () => {
    expect(expandPath('${UNDEFINED_VAR}/file.txt')).toBe(path.normalize('/file.txt'));
    expect(expandPath('$UNDEFINED_VAR/file.txt')).toBe(path.normalize('/file.txt'));
  });

  test('11. Windows drive letters stay intact', () => {
    // Windows drive letter paths should be preserved
    const result = expandPath('C:\\Users\\test\\file.txt');
    expect(result).toContain('Users');
    expect(result).toContain('test');
  });

  test('12. Windows UNC paths handled', () => {
    // UNC paths start with \\
    const uncPath = '\\\\server\\share\\folder';
    const result = expandPath(uncPath);
    // Should normalize but preserve the structure
    expect(result).toContain('server');
    expect(result).toContain('share');
  });

  test('13. Null-like input throws TypeError', () => {
    // Function requires string input - documents current behavior
    // @ts-ignore - testing runtime edge case
    expect(() => expandPath(undefined as unknown as string)).toThrow(TypeError);
    // @ts-ignore - testing runtime edge case
    expect(() => expandPath(null as unknown as string)).toThrow(TypeError);
  });

  test('14. Path with spaces preserved', () => {
    const pathWithSpaces = '~/My Documents/file.txt';
    const result = expandPath(pathWithSpaces);
    expect(result).toContain('My Documents');
  });

  test('15. Multiple consecutive slashes normalized', () => {
    const result = expandPath('path//to///file.txt');
    expect(result).toBe(path.normalize('path/to/file.txt'));
  });
});
