"""
Memo service routes for Memos-style backend.
"""

from typing import List

from fastapi import APIRouter, Body, Depends, HTTPException, Query, Request

from memos_core.schemas import (
    MemoCreate,
    MemoUpdate,
    MemoResponse,
)
from memos_core.services import get_memo_service


router = APIRouter(prefix="/memos")


def get_current_user_id(request: Request) -> str | None:
    """Extract user_id from request.state (set by auth middleware)."""
    return getattr(request.state, "user_id", None)


@router.get("", summary="List memos", response_model=List[MemoResponse])
async def list_memos(
    request: Request,
    tag: str | None = Query(default=None),
    memo_service=Depends(get_memo_service),
):
    """List memos for the current user (or anonymous if not logged in)."""
    try:
        user_id = get_current_user_id(request)
        return await memo_service.list_memos(user_id=user_id, tag=tag)
    except Exception as exc:  # pragma: no cover
        raise HTTPException(status_code=500, detail=str(exc)) from exc


@router.post("", summary="Create memo (Connect compatibility)")
async def create_memo_or_list_memos(
    request: Request,
    payload: dict = Body(default_factory=dict),  # noqa: B008
    memo_service=Depends(get_memo_service),
):
    """
    Vite dev proxy maps multiple Connect RPCs to the same REST path `/api/v1/memos`:
    - MemoService/ListMemos  -> POST /api/v1/memos  (should be GET but method can't be rewritten)
    - MemoService/CreateMemo -> POST /api/v1/memos

    To avoid 422 and keep dev UX smooth, accept an untyped payload and branch by shape.
    """
    try:
        user_id = get_current_user_id(request)
        raw = payload if isinstance(payload, dict) else {}

        # Connect CreateMemo often wraps payload as { "memo": { ... } }
        if isinstance(raw.get("memo"), dict):
            memo_create = MemoCreate(**raw["memo"])
            return await memo_service.create_memo(memo_create, user_id=user_id)

        # If it looks like a create payload, also treat as create.
        if "content" in raw:
            memo_create = MemoCreate(**raw)
            return await memo_service.create_memo(memo_create, user_id=user_id)

        # Otherwise treat as ListMemos.
        # Support basic tag filter when provided.
        tag = raw.get("tag") if isinstance(raw.get("tag"), str) else None
        return await memo_service.list_memos(user_id=user_id, tag=tag)
    except Exception as exc:  # pragma: no cover
        raise HTTPException(status_code=400, detail=str(exc)) from exc


@router.get("/{memo_id}", summary="Get memo by ID", response_model=MemoResponse)
async def get_memo(
    request: Request,
    memo_id: int, 
    memo_service=Depends(get_memo_service)
):
    """Get a specific memo (only if owned by current user or public)."""
    try:
        user_id = get_current_user_id(request)
        return await memo_service.get_memo(memo_id, user_id=user_id)
    except Exception as exc:  # pragma: no cover
        raise HTTPException(status_code=404, detail=str(exc)) from exc


@router.patch("/{memo_id}", summary="Update memo", response_model=MemoResponse)
async def update_memo(
    request: Request,
    memo_id: int,
    payload: MemoUpdate,
    memo_service=Depends(get_memo_service),
):
    """Update a memo (only if owned by current user)."""
    try:
        user_id = get_current_user_id(request)
        return await memo_service.update_memo(memo_id, payload, user_id=user_id)
    except Exception as exc:  # pragma: no cover
        raise HTTPException(status_code=400, detail=str(exc)) from exc


@router.delete("/{memo_id}", summary="Delete memo")
async def delete_memo(
    request: Request,
    memo_id: int, 
    memo_service=Depends(get_memo_service)
):
    """Delete a memo (only if owned by current user)."""
    try:
        user_id = get_current_user_id(request)
        await memo_service.delete_memo(memo_id, user_id=user_id)
        return {"status": "success"}
    except Exception as exc:  # pragma: no cover
        raise HTTPException(status_code=400, detail=str(exc)) from exc
