"""
Session management — HMAC-based session tokens.
"""
from __future__ import annotations

import hashlib
import hmac
import secrets
import sqlite3
from datetime import datetime, timedelta, timezone
from pathlib import Path

from .accounts import ACCOUNTS_DB

SESSION_SECRET = secrets.token_hex(32)  # regenerated on each process start
SESSION_DURATION_HOURS = 24


def _connect() -> sqlite3.Connection:
    conn = sqlite3.connect(str(ACCOUNTS_DB))
    conn.row_factory = sqlite3.Row
    return conn


def _hash_token(token: str) -> str:
    return hashlib.sha256(token.encode()).hexdigest()


def create_session(user_id: int) -> dict[str, str]:
    """Create a new session for a user. Returns {token, expires_at}."""
    token = secrets.token_urlsafe(48)
    token_hash = _hash_token(token)
    expires_at = (datetime.now(timezone.utc) + timedelta(hours=SESSION_DURATION_HOURS)).isoformat()
    now = datetime.now(timezone.utc).isoformat()

    conn = _connect()
    # Clean up expired sessions for this user
    conn.execute("DELETE FROM sessions WHERE user_id = ? AND expires_at < ?", (user_id, now))
    conn.execute(
        "INSERT INTO sessions (user_id, token_hash, created_at, expires_at) VALUES (?, ?, ?, ?)",
        (user_id, token_hash, now, expires_at),
    )
    conn.commit()
    conn.close()
    return {"token": token, "expires_at": expires_at}


def validate_session(token: str) -> dict | None:
    """Validate a session token. Returns user dict or None."""
    token_hash = _hash_token(token)
    now = datetime.now(timezone.utc).isoformat()
    conn = _connect()
    row = conn.execute(
        "SELECT u.* FROM sessions s JOIN users u ON s.user_id = u.id "
        "WHERE s.token_hash = ? AND s.expires_at > ? AND u.is_active = 1",
        (token_hash, now),
    ).fetchone()
    conn.close()
    if not row:
        return None
    return dict(row)


def destroy_session(token: str) -> None:
    token_hash = _hash_token(token)
    conn = _connect()
    conn.execute("DELETE FROM sessions WHERE token_hash = ?", (token_hash,))
    conn.commit()
    conn.close()
