from functools import lru_cache
from typing import Protocol
import bcrypt

from backend.core.config import get_app_settings


class Hasher(Protocol):
  def hash(self, password: str) -> str: ...

  def verify(self, password: str, hashed: str) -> bool: ...

class FakeHasher:
  def hash(self, password: str) -> str:
    return password

  def verify(self, password: str, hashed: str) -> bool:
    return password == hashed

class BcryptHasher:
  def hash(self, password: str) -> str:
    return bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')

  def verify(self, password: str, hashed: str) -> bool:
    return bcrypt.checkpw(password.encode('utf-8'), hashed.encode('utf-8'))

@lru_cache(maxsize=1)
def get_hasher() -> Hasher:
    settings = get_app_settings()

    if settings.TESTING:
        return FakeHasher()

    return BcryptHasher()
