"""cortex/api/routes/memory/legacy.py — Deprecated v1 /remember and /retrieve endpoints."""

from __future__ import annotations

import logging
from typing import Any

from fastapi import Depends, HTTPException, Query, Request, Response, status
from fastapi.responses import JSONResponse

from cortex.api.deps import PREFIX, _resolve_owner_id, _serialise, get_plugin
from cortex.api.deprecation import add_deprecation_headers
from cortex.api.models import (
    RememberRequest,
    RememberResponse,
    RetrieveRequest,
)

from cortex.api.routes.memory.helpers import (
    _MAX_REMEMBER_BYTES,
    _MODE_ALIASES,
    _emit_shadow_event,
    _normalize_and_validate_remember_conversation,
    _shadow_remember,
)

logger = logging.getLogger(__name__)


def _register(router, verify_api_key):
    """Register deprecated v1 remember/retrieve endpoints."""

    # DEPRECATED: v1 remember — use POST {PREFIX}/remember/v2 (canonical)
    @router.post(
        f"{PREFIX}/remember",
        response_model=RememberResponse,
        status_code=status.HTTP_200_OK,
        summary="Extract and store memories (DEPRECATED — use /memories/remember)",
        tags=["memory"],
        operation_id="remember",
        deprecated=True,
    )
    async def remember(
        request: Request,
        body: RememberRequest,
        response: Response,
        shadow: bool = Query(False, description="Shadow mode — extract but do not persist"),
        _: None = Depends(verify_api_key),
        plugin: Any = Depends(get_plugin),
    ) -> JSONResponse:
        """
        Extract semantic claims from a conversation and persist them to memory.

        Accepts either a list of ``{role, content}`` messages or a raw text string.
        Pass ``?shadow=true`` to run extraction without persisting (dry run).

        .. deprecated::
            Use ``POST /memories/remember`` instead, which returns enhanced response details.
        """
        add_deprecation_headers(response, f"{PREFIX}/memories/remember")

        # Issue #486 — body size guard (before any serialisation work)
        import json as _json
        try:
            _cfg_limit = getattr(getattr(plugin, "config", None), "max_remember_body_bytes", None)
            _body_limit = int(_cfg_limit) if isinstance(_cfg_limit, int) else _MAX_REMEMBER_BYTES
        except (TypeError, ValueError):
            _body_limit = _MAX_REMEMBER_BYTES
        if _body_limit > 0:
            _body_bytes = len(_json.dumps(
                body.conversation if not hasattr(body.conversation, "__iter__")
                or isinstance(body.conversation, str)
                else [m.model_dump() if hasattr(m, "model_dump") else (m.dict() if hasattr(m, "dict") else m) for m in body.conversation]
            ).encode("utf-8"))
            if _body_bytes > _body_limit:
                raise HTTPException(
                    status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE,
                    detail=f"Request body too large ({_body_bytes} bytes > {_body_limit} limit)",
                )

        conversation = _normalize_and_validate_remember_conversation(body.conversation)

        effective_owner = _resolve_owner_id(request, body.owner_id)

        if shadow:
            shadow_result = await _shadow_remember(
                plugin, conversation, body.session_id, effective_owner,
            )
            return JSONResponse(content={
                "session_id": body.session_id or "shadow",
                "shadow": True,
                "claims_extracted": shadow_result["claims_extracted"],
                "claims_stored": 0,
                "would_store": shadow_result["would_store"],
                "claims_detail": shadow_result.get("claims_detail", []),
                "entities_resolved": shadow_result["entities_resolved"],
                "noise_filtered": shadow_result["noise_filtered"],
                "errors": shadow_result["errors"],
                "warnings": [],
                "zero_claim_warning": False,
                "ok": True,
            })

        try:
            report = await plugin.remember(
                conversation=conversation,
                session_id=body.session_id,
                owner_id=effective_owner,
                source_session_id=getattr(body, "source_session_id", None),
                source_message_id=getattr(body, "source_message_id", None),
                source_channel=getattr(body, "source_channel", None),
                source_type=getattr(body, "source_type", None),
            )
        except (ValueError, TypeError) as exc:
            raise HTTPException(
                status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
                detail=f"Invalid conversation payload: {exc}",
            ) from exc
        return JSONResponse(content={
            "session_id": report.session_id,
            "claims_extracted": report.claims_extracted,
            "claims_stored": report.claims_stored,
            "entities_resolved": report.entities_resolved,
            "noise_filtered": report.noise_filtered,
            "errors": report.errors,
            "warnings": getattr(report, "warnings", []),
            "zero_claim_warning": getattr(report, "zero_claim_warning", False),
            "ok": report.ok,
        })

    # DEPRECATED: v1 retrieve — use POST {PREFIX}/retrieve/v2 (canonical)
    @router.post(
        f"{PREFIX}/retrieve",
        summary="Retrieve context for a query (DEPRECATED — use /memories/retrieve)",
        tags=["memory"],
        operation_id="retrieve",
        deprecated=True,
    )
    async def retrieve(
        request: Request,
        body: RetrieveRequest,
        response: Response,
        shadow: bool = Query(False, description="Shadow mode — flag response as shadow"),
        _: None = Depends(verify_api_key),
        plugin: Any = Depends(get_plugin),
    ) -> JSONResponse:
        """
        Retrieve relevant memories for a query, respecting an optional token budget.

        Returns the raw RetrievalResult serialised as JSON.
        Pass ``?shadow=true`` to flag the response as a shadow-mode retrieval.

        .. deprecated::
            Use ``POST /memories/retrieve`` instead, which supports explain mode.
        """
        add_deprecation_headers(response, f"{PREFIX}/memories/retrieve")
        effective_mode = body.strategy or body.mode
        effective_mode = _MODE_ALIASES.get(effective_mode, effective_mode)
        effective_owner = _resolve_owner_id(request, body.owner_id)
        result = await plugin.retrieve(
            query=body.query,
            token_budget=body.token_budget,
            mode=effective_mode,
            owner_id=effective_owner,
        )
        if result is None:
            raise HTTPException(
                status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
                detail="Retrieval pipeline not available",
            )
        if hasattr(result, "__dict__"):
            data = _serialise(result.__dict__)
        else:
            data = _serialise(result)
        if shadow:
            data["shadow"] = True
            _emit_shadow_event(endpoint="/api/v1/retrieve", session_id="shadow")
        return JSONResponse(content=data)
