"""
Auth middleware — plugs into control_api.py to add user authentication.

Provides decorator-style auth checks that the existing control_api can use
without major refactoring.

Usage in control_api.py:
    from src.auth.middleware import require_auth, require_role
    from src.auth.accounts import init_db as init_auth_db

    # At server start:
    init_auth_db()
    accounts.create_user("admin@example.com", "admin123", role="admin")

    # In do_POST / do_GET handlers:
    user = require_auth(handler)       # Returns user dict or sends 403
    require_role(handler, "admin")     # Raises if not admin
"""
from __future__ import annotations

import json
from http.server import BaseHTTPRequestHandler
from typing import Any

from .accounts import get_user, ROLES, ROLE_PERMISSIONS
from .session import validate_session
from .api_keys import validate_api_key


def _json_response(handler: BaseHTTPRequestHandler, code: int, payload: dict[str, Any]) -> None:
    body = json.dumps(payload, ensure_ascii=False).encode("utf-8")
    handler.send_response(code)
    handler.send_header("Content-Type", "application/json; charset=utf-8")
    handler.send_header("Content-Length", str(len(body)))
    handler.end_headers()
    handler.wfile.write(body)


def extract_user(handler: BaseHTTPRequestHandler) -> dict[str, Any] | None:
    """
    Extract authenticated user from request.
    Checks in order:
      1. Session token (Authorization: Bearer <token>)
      2. API key (X-Api-Key: <key>)
    """
    # Session token
    auth_header = handler.headers.get("Authorization", "")
    if auth_header.startswith("Bearer "):
        token = auth_header[7:]
        user_row = validate_session(token)
        if user_row:
            user = dict(user_row)
            return {
                "id": user["id"],
                "email": user["email"],
                "role": user["role"],
                "display_name": user.get("display_name", ""),
                "permissions": ROLE_PERMISSIONS.get(user["role"], []),
            }

    # API key
    api_key = handler.headers.get("X-Api-Key", "")
    if api_key:
        user_row = validate_api_key(api_key)
        if user_row:
            user = dict(user_row)
            scopes = user.get("scopes", "trade:view").split()
            return {
                "id": user["id"],
                "email": user["email"],
                "role": user["role"],
                "display_name": user.get("display_name", ""),
                "permissions": scopes,
                "auth_method": "api_key",
            }

    return None


def require_auth(handler: BaseHTTPRequestHandler) -> dict[str, Any]:
    """
    Require authentication. Returns user dict or sends 401 and returns empty dict.
    Caller should check for empty dict.
    """
    user = extract_user(handler)
    if not user:
        _json_response(handler, 401, {"ok": False, "error": "UNAUTHORIZED",
                                      "message": "Valid session or API key required."})
        return {}
    return user


def require_role(handler: BaseHTTPRequestHandler, role: str) -> bool:
    """
    Require a minimum role. Sends 403 if user doesn't have sufficient role.
    Returns True if authorized.
    """
    user = require_auth(handler)
    if not user:
        return False
    if not has_permission(user, f"role:{role}"):
        _json_response(handler, 403, {"ok": False, "error": "FORBIDDEN",
                                      "message": f"Role '{role}' required."})
        return False
    return True


def has_permission(user: dict[str, Any], permission: str) -> bool:
    """Check if user has a specific permission. Wildcard '*' grants all."""
    perms = user.get("permissions", [])
    return "*" in perms or permission in perms
