from typing import Sequence

from fastapi import FastAPI, Request, Response
from fastapi.security import HTTPBasic

from bmsdna.lakeapi.core.config import BasicConfig, UserConfig
from functools import lru_cache

security = HTTPBasic()
userhashmap: dict[str, str] | None = None


@lru_cache
def is_correct(
    hash: str,
    pwd_str: str,
):
    import argon2

    ph = argon2.PasswordHasher()
    return ph.verify(
        hash.encode("utf-8"),
        pwd_str.encode("utf-8"),
    )


def get_basic_auth_middleware_func(users: Sequence[UserConfig]):
    async def basic_auth_middleware_func(request: Request, call_next):
        import json

        credentials = await HTTPBasic(auto_error=False)(request)
        if credentials is None:
            return Response(
                status_code=401,
                headers={"WWW-Authenticate": "Basic"},
                content=json.dumps({"detail": "Not authenticated"}),
            )

        global userhashmap
        userhashmap = userhashmap or {
            ud["name"].casefold(): ud["passwordhash"] for ud in users if ud["name"]
        }  # pay attention not to include an empty user by accident

        if credentials.username.casefold() not in userhashmap.keys():
            return Response(
                status_code=401,
                headers={"WWW-Authenticate": "Basic"},
                content=json.dumps({"detail": "Incorrect email or password"}),
            )
        pwd_str = credentials.password
        hash = userhashmap[credentials.username.casefold()]

        is_correct_password = is_correct(hash, pwd_str)
        if not isinstance(is_correct_password, bool):
            is_correct_password = is_correct_password
        if not is_correct_password:
            return Response(
                status_code=401,
                headers={"WWW-Authenticate": "Basic"},
                content="Incorrect email or password",
            )
        request.scope["user"] = {"username": credentials.username}
        return await call_next(request)

    return basic_auth_middleware_func


def add_user_middlware(
    app: FastAPI,
    basic_config: BasicConfig,
    users: Sequence[UserConfig],
):
    from starlette.middleware.base import BaseHTTPMiddleware

    app.add_middleware(
        BaseHTTPMiddleware, dispatch=get_basic_auth_middleware_func(users)
    )
