/**
 * Unit tests for the centralized path resolver.
 */

import * as os from 'os';
import * as path from 'path';
import {
    expandTilde,
    resolvePathInput,
    isInside,
} from '../src/lib/paths';

describe('expandTilde', () => {
    test('expands "~" to home', () => {
        expect(expandTilde('~')).toBe(os.homedir());
    });

    test('expands "~/foo" to home/foo', () => {
        expect(expandTilde('~/foo')).toBe(path.join(os.homedir(), 'foo'));
    });

    test('leaves absolute paths untouched', () => {
        expect(expandTilde('/tmp/x')).toBe('/tmp/x');
    });

    test('returns empty for blank input', () => {
        expect(expandTilde('')).toBe('');
        expect(expandTilde('   ')).toBe('');
    });
});

describe('resolvePathInput', () => {
    test('accepts absolute paths', () => {
        expect(resolvePathInput('/tmp/abc')).toBe(path.normalize('/tmp/abc'));
    });

    test('accepts ~/-prefixed paths after expansion', () => {
        expect(resolvePathInput('~/notes')).toBe(path.normalize(path.join(os.homedir(), 'notes')));
    });

    test('rejects relative paths to prevent surprises', () => {
        expect(resolvePathInput('relative/dir')).toBe('');
        expect(resolvePathInput('./local')).toBe('');
    });

    test('returns empty on blank / undefined', () => {
        expect(resolvePathInput('')).toBe('');
        expect(resolvePathInput(undefined as any)).toBe('');
    });
});

describe('isInside', () => {
    test('a path is inside itself', () => {
        expect(isInside('/tmp/a', '/tmp/a')).toBe(true);
    });

    test('detects direct descendants', () => {
        expect(isInside('/tmp/a', '/tmp/a/b')).toBe(true);
    });

    test('detects deep descendants', () => {
        expect(isInside('/tmp/a', '/tmp/a/b/c/d.txt')).toBe(true);
    });

    test('rejects siblings', () => {
        expect(isInside('/tmp/a', '/tmp/b')).toBe(false);
    });

    test('rejects path-traversal escapes', () => {
        // Even though string-prefix would say "/tmp/a/../b" starts with "/tmp/a/",
        // path.resolve normalizes the dotdot back to the parent → not inside.
        expect(isInside('/tmp/a', '/tmp/a/../b')).toBe(false);
    });

    test('rejects siblings whose name shares a prefix', () => {
        // "/tmp/agents-evil" must not be considered inside "/tmp/agents".
        expect(isInside('/tmp/agents', '/tmp/agents-evil')).toBe(false);
    });

    test('returns false on empty inputs', () => {
        expect(isInside('', '/tmp/a')).toBe(false);
        expect(isInside('/tmp/a', '')).toBe(false);
    });
});
