"""
API Key Authentication for Stegasoo REST API.

Provides simple API key authentication with hashed key storage.
Keys can be stored in user config (~/.stegasoo/) or project config (./config/).

Usage:
    from .auth import require_api_key, get_api_key_status

    @app.get("/protected")
    async def protected_endpoint(api_key: str = Depends(require_api_key)):
        return {"status": "authenticated"}
"""

import hashlib
import json
import os
import secrets
from pathlib import Path

from fastapi import HTTPException, Security
from fastapi.security import APIKeyHeader

# API key header name
API_KEY_HEADER = APIKeyHeader(name="X-API-Key", auto_error=False)

# Config locations
USER_CONFIG_DIR = Path.home() / ".stegasoo"
PROJECT_CONFIG_DIR = Path("./config")

# Key file name
API_KEYS_FILE = "api_keys.json"

# Environment variable for API key (alternative to file)
API_KEY_ENV_VAR = "STEGASOO_API_KEY"


def _hash_key(key: str) -> str:
    """Hash an API key for storage."""
    return hashlib.sha256(key.encode()).hexdigest()


def _get_keys_file(location: str = "user") -> Path:
    """Get path to API keys file."""
    if location == "project":
        return PROJECT_CONFIG_DIR / API_KEYS_FILE
    return USER_CONFIG_DIR / API_KEYS_FILE


def _load_keys(location: str = "user") -> dict:
    """Load API keys from config file."""
    keys_file = _get_keys_file(location)
    if keys_file.exists():
        try:
            with open(keys_file) as f:
                return json.load(f)
        except (OSError, json.JSONDecodeError):
            return {"keys": [], "enabled": True}
    return {"keys": [], "enabled": True}


def _save_keys(data: dict, location: str = "user") -> None:
    """Save API keys to config file."""
    keys_file = _get_keys_file(location)
    keys_file.parent.mkdir(parents=True, exist_ok=True)

    with open(keys_file, "w") as f:
        json.dump(data, f, indent=2)

    # Secure permissions (owner read/write only)
    os.chmod(keys_file, 0o600)


def generate_api_key() -> str:
    """Generate a new API key."""
    # Format: stegasoo_XXXX_XXXXXXXXXXXXXXXXXXXXXXXXXXXX
    # 32 bytes = 256 bits of entropy
    random_part = secrets.token_hex(16)
    return f"stegasoo_{random_part[:4]}_{random_part[4:]}"


def add_api_key(name: str, location: str = "user") -> str:
    """
    Generate and store a new API key.

    Args:
        name: Descriptive name for the key (e.g., "laptop", "automation")
        location: "user" or "project"

    Returns:
        The generated API key (only shown once!)
    """
    key = generate_api_key()
    key_hash = _hash_key(key)

    data = _load_keys(location)

    # Check for duplicate name
    for existing in data["keys"]:
        if existing["name"] == name:
            raise ValueError(f"Key with name '{name}' already exists")

    data["keys"].append(
        {
            "name": name,
            "hash": key_hash,
            "created": __import__("datetime").datetime.now().isoformat(),
        }
    )

    _save_keys(data, location)

    return key


def remove_api_key(name: str, location: str = "user") -> bool:
    """
    Remove an API key by name.

    Returns:
        True if key was found and removed, False otherwise
    """
    data = _load_keys(location)
    original_count = len(data["keys"])

    data["keys"] = [k for k in data["keys"] if k["name"] != name]

    if len(data["keys"]) < original_count:
        _save_keys(data, location)
        return True
    return False


def list_api_keys(location: str = "user") -> list[dict]:
    """
    List all API keys (names and creation dates, not actual keys).
    """
    data = _load_keys(location)
    return [{"name": k["name"], "created": k.get("created", "unknown")} for k in data["keys"]]


def set_auth_enabled(enabled: bool, location: str = "user") -> None:
    """Enable or disable API key authentication."""
    data = _load_keys(location)
    data["enabled"] = enabled
    _save_keys(data, location)


def is_auth_enabled() -> bool:
    """Check if API key authentication is enabled."""
    # Check project config first, then user config
    for location in ["project", "user"]:
        data = _load_keys(location)
        if "enabled" in data:
            return data["enabled"]

    # Default: enabled if any keys exist
    return bool(get_all_key_hashes())


def get_all_key_hashes() -> set[str]:
    """Get all valid API key hashes from all sources."""
    hashes = set()

    # Check environment variable first
    env_key = os.environ.get(API_KEY_ENV_VAR)
    if env_key:
        hashes.add(_hash_key(env_key))

    # Check project and user configs
    for location in ["project", "user"]:
        data = _load_keys(location)
        for key_entry in data.get("keys", []):
            if "hash" in key_entry:
                hashes.add(key_entry["hash"])

    return hashes


def validate_api_key(key: str) -> bool:
    """Validate an API key against stored hashes."""
    if not key:
        return False

    key_hash = _hash_key(key)
    valid_hashes = get_all_key_hashes()

    return key_hash in valid_hashes


def get_api_key_status() -> dict:
    """Get current API key authentication status."""
    user_keys = list_api_keys("user")
    project_keys = list_api_keys("project")
    env_configured = bool(os.environ.get(API_KEY_ENV_VAR))

    total_keys = len(user_keys) + len(project_keys) + (1 if env_configured else 0)

    return {
        "enabled": is_auth_enabled(),
        "total_keys": total_keys,
        "user_keys": len(user_keys),
        "project_keys": len(project_keys),
        "env_configured": env_configured,
        "keys": {
            "user": user_keys,
            "project": project_keys,
        },
    }


# FastAPI dependency for API key authentication
async def require_api_key(api_key: str | None = Security(API_KEY_HEADER)) -> str:
    """
    FastAPI dependency that requires a valid API key.

    Usage:
        @app.get("/protected")
        async def endpoint(key: str = Depends(require_api_key)):
            ...
    """
    # Check if auth is enabled
    if not is_auth_enabled():
        return "auth_disabled"

    # No keys configured = auth disabled
    if not get_all_key_hashes():
        return "no_keys_configured"

    # Validate the provided key
    if not api_key:
        raise HTTPException(
            status_code=401,
            detail="API key required. Provide X-API-Key header.",
            headers={"WWW-Authenticate": "ApiKey"},
        )

    if not validate_api_key(api_key):
        raise HTTPException(
            status_code=403,
            detail="Invalid API key.",
        )

    return api_key


async def optional_api_key(api_key: str | None = Security(API_KEY_HEADER)) -> str | None:
    """
    FastAPI dependency that optionally validates API key.

    Returns the key if valid, None if not provided or invalid.
    Doesn't raise exceptions - useful for endpoints that work
    with or without auth.
    """
    if api_key and validate_api_key(api_key):
        return api_key
    return None
