"""Mobile companion REST API for NEUROVAULT v0.3."""

from __future__ import annotations

import hmac
from typing import Any, Optional


def create_mobile_api(engine, config: Optional[dict[str, Any]] = None):
    """Create the mobile companion FastAPI app."""
    try:
        from fastapi import Depends, FastAPI, Header, HTTPException
        from fastapi.middleware.cors import CORSMiddleware
    except Exception as exc:  # pragma: no cover - optional dependency
        raise ImportError("Mobile API requires fastapi: pip install fastapi uvicorn") from exc

    from neurovault.security.rbac import Permission

    cfg = config or {}
    app = FastAPI(title="NEUROVAULT Mobile API", version="0.3.1")
    allowed_origins_cfg = cfg.get("allowed_origins")
    default_origins = [
        "http://localhost",
        "http://127.0.0.1",
        "http://localhost:3000",
        "http://127.0.0.1:3000",
    ]
    allowed_origins = (
        [str(origin).rstrip("/") for origin in allowed_origins_cfg if str(origin).strip()]
        if isinstance(allowed_origins_cfg, list)
        else default_origins
    )
    if not allowed_origins:
        allowed_origins = default_origins
    if "*" in allowed_origins and not bool(cfg.get("allow_insecure_cors", False)):
        allowed_origins = default_origins

    app.add_middleware(
        CORSMiddleware,
        allow_origins=allowed_origins,
        allow_methods=["GET", "POST"],
        allow_headers=["*"],
    )

    static_api_keys: set[str] = set(str(k) for k in cfg.get("api_keys", []))

    def _is_valid_static_token(token: str) -> bool:
        for key in static_api_keys:
            if hmac.compare_digest(token, key):
                return True
        return False

    def require_permission(required: str):
        async def _verify_auth(authorization: Optional[str] = Header(default=None)):
            if static_api_keys:
                if not authorization or not authorization.startswith("Bearer "):
                    raise HTTPException(401, "Missing authorization")
                token = authorization.split(" ", 1)[1]
                if not _is_valid_static_token(token):
                    raise HTTPException(403, "Invalid token")
                return {"username": "mobile-static", "permissions": {Permission.ADMIN}}

            if not authorization or not authorization.startswith("Bearer "):
                raise HTTPException(401, "Missing authorization")

            token = authorization.split(" ", 1)[1]
            user = engine.authenticate_token(token)
            if not user:
                raise HTTPException(403, "Invalid token")
            if not engine.check_token_permission(token, required):
                raise HTTPException(403, "Insufficient permission")
            return user

        return _verify_auth

    @app.get("/api/v1/health")
    async def health():
        return {"status": "ok", "version": "0.3.1", "service": "neurovault-mobile"}

    @app.get("/api/v1/stats", dependencies=[Depends(require_permission(Permission.READ))])
    async def stats():
        return engine.stats()

    @app.post("/api/v1/recall", dependencies=[Depends(require_permission(Permission.READ))])
    async def recall(req: dict[str, Any]):
        query = str(req.get("query", "")).strip()
        if not query:
            raise HTTPException(400, "query is required")
        limit = int(req.get("limit", 10))
        mode = str(req.get("mode", "multi"))
        results = engine.recall(query, limit=limit, mode=mode)
        return {
            "query": query,
            "count": len(results),
            "results": [
                {
                    "id": r.memory.id.hex(),
                    "content": r.memory.content[:500],
                    "source": r.memory.source,
                    "importance": r.memory.importance,
                    "score": r.score,
                }
                for r in results
            ],
        }

    @app.post("/api/v1/ingest", dependencies=[Depends(require_permission(Permission.WRITE))])
    async def ingest(req: dict[str, Any]):
        if bool(cfg.get("read_only", False)):
            raise HTTPException(403, "API is read-only")
        content = str(req.get("content", "")).strip()
        if not content:
            raise HTTPException(400, "content is required")
        memory = engine.ingest(
            content=content,
            source=str(req.get("source", "mobile")),
            importance=float(req.get("importance", 0.5)),
            metadata=req.get("metadata", {}) if isinstance(req.get("metadata"), dict) else {},
        )
        if memory is None:
            raise HTTPException(403, "blocked by privacy filter")
        return {"id": memory.id.hex(), "status": "ingested"}

    @app.get("/api/v1/entities", dependencies=[Depends(require_permission(Permission.READ))])
    async def entities(entity_type: Optional[str] = None, limit: int = 50):
        ents = engine.get_entities(entity_type=entity_type, limit=limit)
        return {
            "count": len(ents),
            "entities": [
                {
                    "id": e.id.hex() if e.id else "",
                    "name": e.name,
                    "type": e.entity_type,
                    "importance": e.importance,
                    "mention_count": e.mention_count,
                }
                for e in ents
            ],
        }

    @app.get("/api/v1/predictions", dependencies=[Depends(require_permission(Permission.READ))])
    async def predictions(limit: int = 5):
        preds = engine.predict()
        return {
            "count": len(preds[: max(1, limit)]),
            "predictions": [
                {
                    "id": p.memory.id.hex(),
                    "content": p.memory.content[:300],
                    "score": p.score,
                }
                for p in preds[: max(1, limit)]
            ],
        }

    @app.post("/api/v1/consolidate", dependencies=[Depends(require_permission(Permission.WRITE))])
    async def consolidate():
        if bool(cfg.get("read_only", False)):
            raise HTTPException(403, "API is read-only")
        report = engine.consolidate(force=True)
        return {
            "entities": report.entities_extracted,
            "relationships": report.relationships_found,
            "insights": report.insights_generated,
            "duration_s": report.duration_seconds,
        }

    return app
