"""
Trusted Device Service pentru Web 2FA — async SQLite version

Permite utilizatorilor să „țină minte" un dispozitiv timp de 30 de zile.
Dacă tokenul de dispozitiv de încredere este valid, pasul OTP este sărit.

Securitate critică:
- Tokenul brut (64 hex chars) este returnat clientului și stocat în localStorage
- Pe server se stochează DOAR sha256(token), niciodată tokenul brut
- Skip-uiește DOAR OTP-ul, nu verificarea Oracle (user+parolă rămân obligatorii)
- Expiră automat după TRUSTED_DEVICE_EXPIRE_DAYS zile

Storage: SQLite (shared/database/app_db.py) — tabelul trusted_devices.
"""

import hashlib
import logging
import os
import secrets
from datetime import datetime, timedelta
from typing import Optional

logger = logging.getLogger(__name__)

# ============================================================================
# CONSTANTE
# ============================================================================

TRUSTED_DEVICE_EXPIRE_DAYS = int(os.environ.get("TRUSTED_DEVICE_EXPIRE_DAYS", "30"))


def _hash_token(raw_token: str) -> str:
    """Calculează sha256 al tokenului brut."""
    return hashlib.sha256(raw_token.encode("utf-8")).hexdigest()


# ============================================================================
# API PUBLICĂ (async)
# ============================================================================

async def create_trusted_device_token(username: str, server_id: Optional[str]) -> str:
    """
    Generează un token de dispozitiv de încredere și îl stochează (ca hash).

    Args:
        username: Username Oracle (uppercase)
        server_id: ID-ul serverului Oracle (pentru multi-server mode)

    Returns:
        Tokenul brut (64 hex chars) — de returnat clientului pentru localStorage
    """
    from shared.database.app_db import get_db

    raw_token = secrets.token_hex(64)
    token_hash = _hash_token(raw_token)

    now = datetime.now()
    expires_at = now + timedelta(days=TRUSTED_DEVICE_EXPIRE_DAYS)

    db = await get_db()
    try:
        # Cleanup expired tokens for this user
        await db.execute(
            "DELETE FROM trusted_devices WHERE expires_at < ?",
            (now.isoformat(),)
        )

        # Insert new token
        await db.execute(
            """INSERT INTO trusted_devices (token_hash, username, server_id, expires_at, created_at)
               VALUES (?, ?, ?, ?, ?)""",
            (token_hash, username.upper(), server_id, expires_at.isoformat(), now.isoformat())
        )
        await db.commit()
    finally:
        await db.close()

    logger.info(
        f"[TRUSTED_DEVICE] Token created for '{username}' "
        f"(server={server_id}, expires in {TRUSTED_DEVICE_EXPIRE_DAYS}d)"
    )
    return raw_token


async def verify_trusted_device_token(
    raw_token: str,
    username: str,
    server_id: Optional[str]
) -> bool:
    """
    Verifică dacă tokenul de dispozitiv de încredere este valid.

    Verifică: hash există, username corespunde, nu a expirat.
    Fail silently — returnează False fără a ridica excepție.

    Args:
        raw_token: Tokenul brut din localStorage
        username: Username Oracle (uppercase)
        server_id: ID-ul serverului Oracle

    Returns:
        True dacă dispozitivul este de încredere și autentificarea poate sări OTP-ul
    """
    from shared.database.app_db import get_db

    try:
        token_hash = _hash_token(raw_token)

        db = await get_db()
        try:
            cursor = await db.execute(
                "SELECT username, server_id, expires_at FROM trusted_devices WHERE token_hash = ?",
                (token_hash,)
            )
            row = await cursor.fetchone()

            if not row:
                logger.debug(f"[TRUSTED_DEVICE] Token not found for '{username}'")
                return False

            stored_username = row["username"]
            stored_server = row["server_id"]
            expires_at_str = row["expires_at"]

            # Verifică username (case-insensitive)
            if stored_username.upper() != username.upper():
                logger.warning(
                    f"[TRUSTED_DEVICE] Username mismatch: "
                    f"expected '{username}', got '{stored_username}'"
                )
                return False

            # Cross-server trust — log but allow
            if stored_server != server_id:
                logger.info(
                    f"[TRUSTED_DEVICE] Cross-server trust for '{username}': "
                    f"token from '{stored_server}', logging into '{server_id}' — allowing"
                )

            # Verifică expirarea
            if expires_at_str < datetime.now().isoformat():
                logger.info(f"[TRUSTED_DEVICE] Token expired for '{username}'")
                await db.execute("DELETE FROM trusted_devices WHERE token_hash = ?", (token_hash,))
                await db.commit()
                return False

            logger.info(f"[TRUSTED_DEVICE] Token valid for '{username}' (server={server_id})")
            return True
        finally:
            await db.close()

    except Exception as e:
        logger.error(f"[TRUSTED_DEVICE] Unexpected error during verification: {e}")
        return False


async def revoke_all_for_user(username: str, server_id: Optional[str] = None) -> int:
    """
    Revocă toate token-urile de dispozitiv de încredere ale unui utilizator.

    Args:
        username: Username Oracle (uppercase)
        server_id: Dacă specificat, revocă doar pentru serverul respectiv

    Returns:
        Numărul de token-uri revocate
    """
    from shared.database.app_db import get_db

    username_upper = username.upper()

    db = await get_db()
    try:
        if server_id is not None:
            cursor = await db.execute(
                "DELETE FROM trusted_devices WHERE UPPER(username) = ? AND server_id = ?",
                (username_upper, server_id)
            )
        else:
            cursor = await db.execute(
                "DELETE FROM trusted_devices WHERE UPPER(username) = ?",
                (username_upper,)
            )
        await db.commit()
        deleted = cursor.rowcount
    finally:
        await db.close()

    if deleted:
        logger.info(
            f"[TRUSTED_DEVICE] Revoked {deleted} tokens for '{username}'"
            + (f" (server={server_id})" if server_id else "")
        )

    return deleted
