/**
* @license Apache-2.0
*
* Copyright (c) 2018 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

// MODULES //

var tape = require( 'tape' );
var proxyquire = require( 'proxyquire' );
var ENV = require( '@stdlib/process/env' );
var configdir = require( './../lib' );


// VARIABLES //

var mpath = './../lib/configdir.js';


// FUNCTIONS //

/**
* Mock function returning a home directory.
*
* @private
* @returns {string} directory
*/
function homedir() {
	return '/Beep/Boop';
}

/**
* Mock joining a path according to the POSIX path convention.
*
* @private
* @param {...string} p - path components
* @returns {string} path
*/
function joinPosix() {
	var str;
	var p;
	var i;

	str = '';
	str += arguments[ 0 ];
	for ( i = 1; i < arguments.length; i++ ) {
		p = arguments[ i ];
		if ( p ) {
			if ( p[ p.length-1 ] !== '/' ) {
				str += '/';
			}
			str += p;
		}
	}
	return str;
}

/**
* Returns a copy of the default proxyquire options.
*
* @private
* @returns {Object} options object
*/
function makeOpts() {
	var opts = {
		'./../../platform': 'darwin',
		'@stdlib/assert/is-windows': false,
		'./../../homedir': homedir,
		'@stdlib/process/env': ENV,
		'path': {
			'join': joinPosix
		}
	};
	return opts;
}


// TESTS //

tape( 'main export is a function', function test( t ) {
	t.ok( true, __filename );
	t.strictEqual( typeof configdir, 'function', 'main export is a function' );
	t.end();
});

tape( 'the function throws an error if provided a path value which is not a string primitive', function test( t ) {
	var configdir;
	var values;
	var opts;
	var i;

	values = [
		5,
		NaN,
		true,
		null,
		void 0,
		[],
		{},
		function noop() {}
	];
	opts = makeOpts();
	configdir = proxyquire( mpath, opts );

	for ( i = 0; i < values.length; i++ ) {
		t.throws( badValue( values[i] ), TypeError, 'throws an error when provided '+values[i] );
	}
	t.end();

	function badValue( value ) {
		return function badValue() {
			configdir( value );
		};
	}
});

tape( 'the function supports Mac OS X', function test( t ) {
	var configdir;
	var opts;

	opts = makeOpts();
	opts[ './../../platform' ] = 'darwin';
	configdir = proxyquire( mpath, opts );

	t.strictEqual( configdir(), '/Beep/Boop/Library/Preferences', 'returns directory' );
	t.end();
});

tape( 'the function supports Mac OS X and appends a path', function test( t ) {
	var configdir;
	var opts;

	opts = makeOpts();
	opts[ './../../platform' ] = 'darwin';
	configdir = proxyquire( mpath, opts );

	t.strictEqual( configdir( 'appy/config' ), '/Beep/Boop/Library/Preferences/appy/config', 'returns directory' );
	t.end();
});

tape( 'the function supports Linux (XDG_CONFIG_HOME)', function test( t ) {
	var configdir;
	var opts;

	opts = makeOpts();
	opts[ '@stdlib/process/env' ] = {
		'XDG_CONFIG_HOME': '/Beep/bop/.config',
		'@noCallThru': true
	};
	opts[ './../../platform' ] = 'linux';
	configdir = proxyquire( mpath, opts );

	t.strictEqual( configdir(), '/Beep/bop/.config', 'returns directory' );

	t.end();
});

tape( 'the function supports Linux and appends a path (XDG_CONFIG_HOME)', function test( t ) {
	var configdir;
	var opts;

	opts = makeOpts();
	opts[ '@stdlib/process/env' ] = {
		'XDG_CONFIG_HOME': '/Beep/bop/.config',
		'@noCallThru': true
	};
	opts[ './../../platform' ] = 'linux';
	configdir = proxyquire( mpath, opts );

	t.strictEqual( configdir( 'appy/config' ), '/Beep/bop/.config/appy/config', 'returns directory' );

	t.end();
});

tape( 'the function supports Linux and falls back to a `.config` directory in a user\'s home directory', function test( t ) {
	var configdir;
	var opts;

	opts = makeOpts();
	opts[ '@stdlib/process/env' ] = {
		'@noCallThru': true
	};
	opts[ './../../platform' ] = 'linux';
	configdir = proxyquire( mpath, opts );

	t.strictEqual( configdir(), '/Beep/Boop/.config', 'returns directory' );

	t.end();
});

tape( 'the function supports Linux and falls back to a `.config` directory in a user\'s home directory and appends a path', function test( t ) {
	var configdir;
	var opts;

	opts = makeOpts();
	opts[ '@stdlib/process/env' ] = {
		'@noCallThru': true
	};
	opts[ './../../platform' ] = 'linux';
	configdir = proxyquire( mpath, opts );

	t.strictEqual( configdir( 'appy/config' ), '/Beep/Boop/.config/appy/config', 'returns directory' );

	t.end();
});

tape( 'the function returns `null` if unable to locate a home directory on non-Windows platforms', function test( t ) {
	var configdir;
	var opts;

	opts = makeOpts();
	opts[ '@stdlib/process/env' ] = {
		'@noCallThru': true
	};
	opts[ './../../homedir' ] = mock;

	configdir = proxyquire( mpath, opts );

	t.strictEqual( configdir(), null, 'returns null' );

	t.end();

	function mock() {
		return null;
	}
});

tape( 'the function supports Windows (LOCALAPPDATA)', function test( t ) {
	var configdir;
	var opts;

	opts = makeOpts();
	opts[ '@stdlib/process/env' ] = {
		'LOCALAPPDATA': 'C:\\Users\\beep\\AppData\\Local',
		'@noCallThru': true
	};
	opts[ '@stdlib/assert/is-windows' ] = true;
	configdir = proxyquire( mpath, opts );

	t.strictEqual( configdir(), 'C:\\Users\\beep\\AppData\\Local', 'returns directory' );

	t.end();
});

tape( 'the function supports Windows and appends a path (LOCALAPPDATA)', function test( t ) {
	var configdir;
	var opts;

	opts = makeOpts();
	opts[ '@stdlib/process/env' ] = {
		'LOCALAPPDATA': 'C:\\Users\\beep\\AppData\\Local',
		'@noCallThru': true
	};
	opts[ '@stdlib/assert/is-windows' ] = true;
	opts[ 'path' ] = {
		'join': join
	};
	configdir = proxyquire( mpath, opts );

	t.strictEqual( configdir( 'appy\\config' ), 'C:\\Users\\beep\\AppData\\Local\\appy\\config', 'returns directory' );

	t.end();

	function join( a, b ) {
		return a + '\\' + b;
	}
});

tape( 'the function supports Windows (APPDATA)', function test( t ) {
	var configdir;
	var opts;

	opts = makeOpts();
	opts[ '@stdlib/process/env' ] = {
		'APPDATA': 'C:\\Users\\beep\\AppData\\Roaming',
		'@noCallThru': true
	};
	opts[ '@stdlib/assert/is-windows' ] = true;
	configdir = proxyquire( mpath, opts );

	t.strictEqual( configdir(), 'C:\\Users\\beep\\AppData\\Roaming', 'returns directory' );

	t.end();
});

tape( 'the function supports Windows and appends a path (APPDATA)', function test( t ) {
	var configdir;
	var opts;

	opts = makeOpts();
	opts[ '@stdlib/process/env' ] = {
		'LOCALAPPDATA': 'C:\\Users\\beep\\AppData\\Roaming',
		'@noCallThru': true
	};
	opts[ '@stdlib/assert/is-windows' ] = true;
	opts[ 'path' ] = {
		'join': join
	};
	configdir = proxyquire( mpath, opts );

	t.strictEqual( configdir( 'appy\\config' ), 'C:\\Users\\beep\\AppData\\Roaming\\appy\\config', 'returns appended path' );

	t.end();

	function join( a, b ) {
		return a + '\\' + b;
	}
});

tape( 'the function returns `null` if unable to locate an application data directory on Windows', function test( t ) {
	var configdir;
	var opts;

	opts = makeOpts();
	opts[ '@stdlib/process/env' ] = {
		'@noCallThru': true
	};
	opts[ '@stdlib/assert/is-windows' ] = true;

	configdir = proxyquire( mpath, opts );

	t.strictEqual( configdir(), null, 'returns null' );

	t.end();
});
