from __future__ import annotations

import hashlib
from typing import Any

DEFAULT_PROFILE_ID = "default"
PROFILE_SESSION_TIMEOUT_SEC = 1800


def normalize_profile_id(value: Any) -> str:
    profile_id = str(value or "").strip()
    return profile_id if profile_id else DEFAULT_PROFILE_ID


def _profile_key(value: Any) -> str:
    return normalize_profile_id(value).casefold()


def normalize_pin(value: Any) -> str | None:
    pin = str(value or "").strip()
    if not pin:
        return None
    if not pin.isdigit():
        return None
    if len(pin) < 4 or len(pin) > 6:
        return None
    return pin


def hash_profile_pin(profile_id: str, pin: str) -> str:
    digest_input = f"{_profile_key(profile_id)}:{pin}"
    return hashlib.sha256(digest_input.encode("utf-8")).hexdigest()


def first_query_param_value(query_params: Any, key: str) -> str | None:
    raw = query_params.get(key)
    if raw is None:
        return None
    if isinstance(raw, list):
        return str(raw[0]) if raw else None
    return str(raw)


def is_truthy_flag(value: Any) -> bool:
    normalized = str(value or "").strip().lower()
    return normalized in {"1", "true", "yes", "y", "on"}


def resolve_login_profile(session_profile: Any, query_profile: Any) -> str | None:
    if str(session_profile or "").strip():
        return normalize_profile_id(session_profile)
    if str(query_profile or "").strip():
        return normalize_profile_id(query_profile)
    return None


def find_existing_profile_id(profile_id: Any, available_profiles: set[str]) -> str | None:
    requested_key = _profile_key(profile_id)
    for existing in available_profiles:
        if _profile_key(existing) == requested_key:
            return existing
    return None


def profile_exists(profile_id: Any, available_profiles: set[str]) -> bool:
    return find_existing_profile_id(profile_id, available_profiles) is not None


def is_profile_session_expired(last_active: Any, now_epoch: float, timeout_sec: int = PROFILE_SESSION_TIMEOUT_SEC) -> bool:
    if not isinstance(last_active, (int, float)):
        return False
    return (now_epoch - float(last_active)) > timeout_sec
