# Familiar - Self-Hosted AI Companion Platform
# Copyright (c) 2026 George Scott Foley
# ORCID: 0009-0006-4957-0540
# Email: Georgescottfoley@proton.me
# Licensed under the MIT License - see LICENSE file for details

"""Dashboard authentication — extracted from app.py for Blueprint sharing."""

from __future__ import annotations

import hmac
import logging
import os
from functools import wraps
from pathlib import Path

from flask import abort, request

logger = logging.getLogger(__name__)

# Module-level state — set by app.py's run_dashboard()
_first_run_mode = False


def set_first_run_mode(value: bool) -> None:
    global _first_run_mode
    _first_run_mode = value


def is_first_run() -> bool:
    return _first_run_mode


def require_auth(f):
    """
    Require API key authentication for dashboard endpoints.

    API key can be provided via:
    - X-API-Key header
    - api_key query parameter

    If FAMILIAR_DASHBOARD_KEY is not set, auto-generates and persists one.
    """

    @wraps(f)
    def decorated(*args, **kwargs):
        if _first_run_mode:
            return f(*args, **kwargs)

        expected_key = os.environ.get("FAMILIAR_DASHBOARD_KEY")

        if not expected_key:
            if not getattr(require_auth, "_auto_key", None):
                import secrets as _secrets

                try:
                    from familiar.core.credential_store import keyring_get, keyring_set

                    stored = keyring_get("dashboard", "api_key")
                    if stored:
                        require_auth._auto_key = stored
                        logger.info("Loaded dashboard auth key from keyring")
                    else:
                        require_auth._auto_key = _secrets.token_urlsafe(32)
                        keyring_set("dashboard", "api_key", require_auth._auto_key)
                        logger.info("Generated and persisted dashboard auth key in keyring")
                except Exception:
                    _key_path = Path.home() / ".familiar" / "data" / "dashboard_key"
                    if _key_path.exists():
                        require_auth._auto_key = _key_path.read_text().strip()
                    else:
                        require_auth._auto_key = _secrets.token_urlsafe(32)
                        _key_path.parent.mkdir(parents=True, exist_ok=True)
                        _key_path.write_text(require_auth._auto_key)
                        _key_path.chmod(0o600)
                print(f"\n{'=' * 60}")
                print("  Dashboard auth key:")
                print(f"   {require_auth._auto_key}")
                print("   Add to requests as X-API-Key header or ?api_key= param")
                print("   Set FAMILIAR_DASHBOARD_KEY env var to override")
                print(f"{'=' * 60}\n")
            expected_key = require_auth._auto_key

        provided_key = request.headers.get("X-API-Key") or request.args.get("api_key")

        if not provided_key:
            logger.warning(f"Unauthenticated request to {request.path} from {request.remote_addr}")
            abort(401, description="API key required. Provide via X-API-Key header.")

        if not hmac.compare_digest(provided_key, expected_key):
            logger.warning(f"Invalid API key from {request.remote_addr}")
            abort(401, description="Invalid API key")

        return f(*args, **kwargs)

    return decorated


def require_localhost(f):
    """Restrict endpoint to localhost requests only (for onboarding)."""

    @wraps(f)
    def decorated(*args, **kwargs):
        if _first_run_mode:
            return f(*args, **kwargs)

        lan_allowed = os.environ.get("FAMILIAR_ONBOARD_LAN", "").lower() in ("1", "true")
        if not lan_allowed and request.remote_addr not in ("127.0.0.1", "::1"):
            abort(403, description="This endpoint is only available from localhost.")
        return f(*args, **kwargs)

    return decorated


def get_api_key() -> str:
    """Return the current dashboard API key (auto-generated or env var)."""
    return (
        os.environ.get("FAMILIAR_DASHBOARD_KEY")
        or getattr(require_auth, "_auto_key", "")
        or ""
    )
