"""Test the auth script to manage local users."""
from unittest.mock import Mock, patch

import pytest

from homeassistant.scripts import auth as script_auth
from homeassistant.auth.providers import homeassistant as hass_auth

from tests.common import register_auth_provider


@pytest.fixture
def provider(hass):
    """Home Assistant auth provider."""
    provider = hass.loop.run_until_complete(register_auth_provider(hass, {
        'type': 'homeassistant',
    }))
    hass.loop.run_until_complete(provider.async_initialize())
    return provider


async def test_list_user(hass, provider, capsys):
    """Test we can list users."""
    data = provider.data
    data.add_auth('test-user', 'test-pass')
    data.add_auth('second-user', 'second-pass')

    await script_auth.list_users(hass, provider, None)

    captured = capsys.readouterr()

    assert captured.out == '\n'.join([
        'test-user',
        'second-user',
        '',
        'Total users: 2',
        ''
    ])


async def test_add_user(hass, provider, capsys, hass_storage):
    """Test we can add a user."""
    data = provider.data
    await script_auth.add_user(
        hass, provider, Mock(username='paulus', password='test-pass'))

    assert len(hass_storage[hass_auth.STORAGE_KEY]['data']['users']) == 1

    captured = capsys.readouterr()
    assert captured.out == 'Auth created\n'

    assert len(data.users) == 1
    data.validate_login('paulus', 'test-pass')


async def test_validate_login(hass, provider, capsys):
    """Test we can validate a user login."""
    data = provider.data
    data.add_auth('test-user', 'test-pass')

    await script_auth.validate_login(
        hass, provider, Mock(username='test-user', password='test-pass'))
    captured = capsys.readouterr()
    assert captured.out == 'Auth valid\n'

    await script_auth.validate_login(
        hass, provider, Mock(username='test-user', password='invalid-pass'))
    captured = capsys.readouterr()
    assert captured.out == 'Auth invalid\n'

    await script_auth.validate_login(
        hass, provider, Mock(username='invalid-user', password='test-pass'))
    captured = capsys.readouterr()
    assert captured.out == 'Auth invalid\n'


async def test_change_password(hass, provider, capsys, hass_storage):
    """Test we can change a password."""
    data = provider.data
    data.add_auth('test-user', 'test-pass')

    await script_auth.change_password(
        hass, provider, Mock(username='test-user', new_password='new-pass'))

    assert len(hass_storage[hass_auth.STORAGE_KEY]['data']['users']) == 1
    captured = capsys.readouterr()
    assert captured.out == 'Password changed\n'
    data.validate_login('test-user', 'new-pass')
    with pytest.raises(hass_auth.InvalidAuth):
        data.validate_login('test-user', 'test-pass')


async def test_change_password_invalid_user(hass, provider, capsys,
                                            hass_storage):
    """Test changing password of non-existing user."""
    data = provider.data
    data.add_auth('test-user', 'test-pass')

    await script_auth.change_password(
        hass, provider, Mock(username='invalid-user', new_password='new-pass'))

    assert hass_auth.STORAGE_KEY not in hass_storage
    captured = capsys.readouterr()
    assert captured.out == 'User not found\n'
    data.validate_login('test-user', 'test-pass')
    with pytest.raises(hass_auth.InvalidAuth):
        data.validate_login('invalid-user', 'new-pass')


def test_parsing_args(loop):
    """Test we parse args correctly."""
    called = False

    async def mock_func(hass, provider, args2):
        """Mock function to be called."""
        nonlocal called
        called = True
        assert provider.hass.config.config_dir == '/somewhere/config'
        assert args2 is args

    args = Mock(config='/somewhere/config', func=mock_func)

    with patch('argparse.ArgumentParser.parse_args', return_value=args):
        script_auth.run(None)

    assert called, 'Mock function did not get called'