import asyncio
import logging
from urllib.parse import urlparse

from behave_auto_docstring import given, when, then

from almabtrieb import Almabtrieb

from cattle_grid.app import app_globals

from cattle_grid.account.account import create_account, add_permission
from cattle_grid.testing.features.actor import Actor
from cattle_grid.database import database_session

logger = logging.getLogger(__name__)


@given('An account called "{alice}"')
async def create_account_step(context, alice: str):
    """
    Creates an account with name `alice`.
    The connection is stored in `context.connections[alice]` it
    is an [Almabtrieb][almabtrieb.Almabtrieb] object.
    """
    async with database_session(
        db_url=app_globals.application_config.db_url
    ) as session:  # type: ignore
        account = await create_account(session, alice, alice)
        assert account
        await add_permission(session, account, "admin")

    mq_host = urlparse(app_globals.application_config.amqp_url).hostname

    context.connections[alice] = Almabtrieb.from_connection_string(
        f"amqp://{alice}:{alice}@{mq_host}/", silent=True
    )
    context.connections[alice].task = asyncio.create_task(
        context.connections[alice].run()
    )

    for _ in range(10):
        if context.connections[alice].connected:
            return
        logger.debug("Connecting")
        await asyncio.sleep(0.1)

    raise RuntimeError("Could not connect")


@given('"{alice}" created an actor called "{alyssa}"')
def create_actor_step(context, alice, alyssa):
    hostname = {"alice": "abel", "bob": "banach", "Bob": "banach"}.get(alyssa, "abel")

    context.execute_steps(
        f"""
        Given "{alice}" created an actor on "{hostname}" called "{alyssa}" with username "{alyssa}"
        """
    )


@given(
    '"{alice}" created an actor on "{hostname}" called "{alyssa}" with username "{username}"'
)
async def create_actor_on_host_step(context, alice, alyssa, hostname, username):
    connection = context.connections[alice]
    result = await connection.create_actor(
        base_url=f"http://{hostname}", preferred_username=username
    )
    context.actors[alyssa] = Actor(profile=result, connection=connection)


@when('"{alice}" deletes the actor "{alyssa}"')
async def alice_delete_actor_step(context, alice, alyssa):
    alyssa_actor = context.actors[alyssa]

    await alyssa_actor.publish(
        "delete_actor",
        {
            "actor": alyssa_actor.id,
        },
    )


@then('"{alice}" has no actors')
async def check_no_actors(context, alice):
    response = await context.connections[alice].info()

    assert len(response.actors) == 0, f"Alice has actors {', '.join(response.actors)}"
