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

import pytest

from homeassistant.auth.providers import homeassistant as hass_auth
from homeassistant.scripts import auth as script_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"