import os
from operator import itemgetter
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession
from sqlalchemy import select, desc
from retailtwin.views import get_inventory_view, get_stores_view
from retailtwin.api.settings import Settings


async def get_session():
    try:
        engine = create_async_engine(Settings().db_uri.unicode_string())
        yield async_sessionmaker(engine, expire_on_commit=False)
    except:  # noqa
        await engine.dispose()


def detail_button(batch: int):
    return "".join(
        [
            f'<a href="detail.html?batch={batch}">'
            f'<button class="btn btn-secondary" type="button">🔍</button>'
            f"</a>"
        ]
    )


async def get_inventory(
    store: int,
    page: int,
    pagesize: int,
    sortby: str,
    root_path: str,
    async_session: async_sessionmaker[AsyncSession] = None,
) -> str:
    """Get inventory for a given location

    Args:
        store (int): Location id
        page (int): Page number for pagination
        pagesize (int): Page size for pagination
        sortby (str): Column name used for sorting
        root_path (str): Root path of the API
        async_session (async_sessionmaker[AsyncSession], optional):
            SQLAlchemy async session. Defaults to None.

    Returns:
        str: HTML table rows with the content
    """
    output = list()
    inventory = get_inventory_view()

    # Selects the column from which to sort by, and if asc or desc
    col_reversed = sortby.startswith("-")
    col_selector = itemgetter(sortby.strip("-"))

    async with async_session() as session:
        stmt = (
            select(
                inventory.c[
                    "upc",
                    "batch",
                    "name",
                    "package",
                    "received",
                    "best_until",
                    "quantity",
                ]
            )
            .where(inventory.c.location == store)
            .limit(pagesize)
            .offset(pagesize * page)
            .order_by(
                desc(col_selector(inventory.c))
                if col_reversed
                else col_selector(inventory.c)
            )
        )
        result = await session.execute(stmt)

        query_params = " ".join(
            [
                f'js:{{page: "{page + 1}",'
                f'pagesize: "{pagesize}",'
                f'sortby: "{sortby}",'
                'store: document.getElementById("store").value}'
            ]
        )

        # Turn the results in a sequence of HTML table rows
        for i, record in enumerate(result.fetchall()):
            line = ""
            cells = (
                " ".join(f"<td>{it}</td>" for it in record)
                + f" <td>{detail_button(record[1])}</td>"
            )
            if i == (pagesize - 1):  # Handle last row for infinite scrolling
                line = " ".join(
                    [
                        f'<tr hx-get="{root_path}/stock"',
                        f"hx-vals='{query_params}'",
                        f'hx-trigger="revealed" hx-swap="afterend">{cells}</tr>',
                    ]
                )
            else:
                line = f"<tr>{cells}</tr>"

            output.append(line)

    return os.linesep.join(output)


async def get_stores(
    root_path: str,
    async_session: async_sessionmaker[AsyncSession] = None,
):
    # Build store options
    store_rows = ['<option selected value="1">Choose store</option>']
    stores = get_stores_view()
    async with async_session() as session:
        stmt = select(stores)
        result = await session.execute(stmt)
        for record in result.fetchall():
            store_rows.append(f'<option value="{record[0]}">{record[1]}</option>')

    # Wrap with the select tag
    query_params = (
        'js:{page: "0", '
        'pagesize: "20", '
        'sortby: "upc", '
        'store: document.getElementById("store").value}'
    )
    return (
        f'<select class="form-select" id="store"'
        f'hx-get="{root_path}/stock" '
        f"hx-vals='{query_params}' "
        f'hx-target="#results" '
        f">{os.linesep.join(store_rows)}</>"
    )
