"""
Kiosk-Session-Service: Redis-basierte Short-Lived Sessions für Kiosk-User-Auth.

Nach erfolgreicher PIN/QR/NFC-Auth bekommt der Kiosk-Client ein Session-Token
(UUID, 15min TTL). Dieses Token wird in allen Stempel-Requests als Header
X-Kiosk-Session-Token mitgeschickt.

Redis ist Pflicht für Sessions. Bei Redis-Ausfall → 503.
"""
from __future__ import annotations

import json
import uuid
from datetime import datetime, timezone
from typing import Optional

from fastapi import HTTPException

SESSION_TTL_SECONDS = 15 * 60  # 15 Minuten
SESSION_KEY_PREFIX = "kiosk_session:"


class KioskSessionService:

    def _get_redis(self):
        """Redis-Client aus app.core.redis holen. Raises 503 wenn nicht verfügbar."""
        try:
            from app.core.redis import get_redis_client
            client = get_redis_client()
            if client is None:
                raise HTTPException(
                    status_code=503,
                    detail="Session-Service nicht verfügbar (Redis nicht erreichbar)."
                )
            return client
        except ImportError:
            raise HTTPException(
                status_code=503,
                detail="Session-Service nicht konfiguriert."
            )

    async def create_session(
        self,
        user_id: uuid.UUID,
        company_id: uuid.UUID,
        device_id: uuid.UUID,
        auth_method: str,  # "pin" | "nfc" | "qr" | "list"
    ) -> str:
        """Erzeugt eine neue Kiosk-Session und speichert sie in Redis."""
        redis = self._get_redis()
        session_token = str(uuid.uuid4())
        key = SESSION_KEY_PREFIX + session_token
        payload = {
            "user_id": str(user_id),
            "company_id": str(company_id),
            "device_id": str(device_id),
            "auth_method": auth_method,
            "created_at": datetime.now(timezone.utc).isoformat(),
        }
        try:
            redis.setex(key, SESSION_TTL_SECONDS, json.dumps(payload))
        except Exception as exc:
            raise HTTPException(
                status_code=503,
                detail=f"Session konnte nicht erstellt werden: {exc}"
            )
        return session_token

    async def get_session(self, session_token: str) -> Optional[dict]:
        """Gibt Session-Daten zurück oder None wenn abgelaufen/nicht vorhanden."""
        redis = self._get_redis()
        key = SESSION_KEY_PREFIX + session_token
        try:
            data = redis.get(key)
        except Exception as exc:
            raise HTTPException(
                status_code=503,
                detail=f"Session-Lookup fehlgeschlagen: {exc}"
            )
        if data is None:
            return None
        return json.loads(data)

    async def invalidate_session(self, session_token: str) -> None:
        """Session sofort ungültig machen (Logout)."""
        redis = self._get_redis()
        key = SESSION_KEY_PREFIX + session_token
        try:
            redis.delete(key)
        except Exception:
            pass  # Best-effort

    async def refresh_session(self, session_token: str) -> bool:
        """TTL einer aktiven Session zurücksetzen. Returns False wenn Session nicht mehr existiert."""
        redis = self._get_redis()
        key = SESSION_KEY_PREFIX + session_token
        try:
            result = redis.expire(key, SESSION_TTL_SECONDS)
            return bool(result)
        except Exception:
            return False

    async def require_session(self, session_token: str) -> dict:
        """Wie get_session, aber wirft 401 wenn Session ungültig/abgelaufen."""
        session = await self.get_session(session_token)
        if session is None:
            raise HTTPException(
                status_code=401,
                detail="Kiosk-Session abgelaufen oder ungültig. Bitte neu anmelden."
            )
        return session


kiosk_session_service = KioskSessionService()
