"""مدیریت state و PKCE verifier سمت سرور برای جریان لاگین (BFF).

verifier در حافظه‌ی سرویس نگه داشته می‌شود و فقط با state بازیابی می‌گردد؛
بنابراین به sessionStorage/origin مرورگر وابسته نیست.

نکته production: برای چند worker/instance، این store باید به Redis منتقل شود.
"""
from __future__ import annotations

import base64
import hashlib
import secrets
import time
from threading import Lock


def generate_pkce_pair() -> tuple[str, str]:
    """(verifier, challenge) با روش S256 تولید می‌کند."""
    verifier = base64.urlsafe_b64encode(secrets.token_bytes(32)).rstrip(b"=").decode("ascii")
    digest = hashlib.sha256(verifier.encode("ascii")).digest()
    challenge = base64.urlsafe_b64encode(digest).rstrip(b"=").decode("ascii")
    return verifier, challenge


def generate_state() -> str:
    return secrets.token_urlsafe(24)


class PKCEStore:
    def __init__(self, ttl_seconds: int = 600) -> None:
        self._data: dict[str, tuple[str, float]] = {}
        self._ttl = ttl_seconds
        self._lock = Lock()

    def _prune_locked(self) -> None:
        now = time.time()
        expired = [key for key, (_, exp) in self._data.items() if exp < now]
        for key in expired:
            self._data.pop(key, None)

    def put(self, state: str, verifier: str) -> None:
        with self._lock:
            self._prune_locked()
            self._data[state] = (verifier, time.time() + self._ttl)

    def pop(self, state: str) -> str | None:
        with self._lock:
            self._prune_locked()
            item = self._data.pop(state, None)
            return item[0] if item else None


pkce_store = PKCEStore()
