"""
Memo service routes for Memos-style backend (SQLite).
"""

from datetime import datetime, timedelta
from typing import List, Any
import logging
import re
import secrets

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

from common.memos_core.schemas import (
    MemoCreate,
    MemoUpdate,
    MemoResponse,
    MemoVersionResponse,
    DeadlineListResponse,
)
from common.memos_core.services import get_memo_service, get_memo_relation_service, get_reaction_service
from common.memos_core.query_parser import parse_date_range


logger = logging.getLogger(__name__)
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),
    filter: str | None = Query(default=None),
    row_status: str | None = Query(default=None, description="Filter by status: NORMAL or ARCHIVED"),
    start_date: str | None = Query(default=None, description="ISO format date (YYYY-MM-DD)"),
    end_date: str | None = Query(default=None, description="ISO format date (YYYY-MM-DD)"),
    workspace_id: str | None = Query(default=None, description="Workspace filter: PERSONAL or AI_SALES_CRM"),
    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)
        is_auth = getattr(request.state, "is_authenticated", False)
        logger.warning("🔍 LIST_MEMOS: user_id=%s, is_authenticated=%s, has_auth_header=%s",
                       user_id, is_auth, bool(request.headers.get("authorization")))

        dt_start, dt_end = parse_date_range(
            start_date=start_date,
            end_date=end_date,
            filter_str=filter,
        )

        creator_id = None
        if filter:
            logger.debug("List memos GET with filter=%r", filter)
            pattern_creator = r"creator_id\s*==\s*([a-zA-Z0-9_\-\.]+)"
            match_creator = re.search(pattern_creator, filter)
            if match_creator:
                creator_id = match_creator.group(1)

        pinned = None
        if filter and re.search(r'\bpinned\b(?!\s*==\s*false)', filter):
            pinned = True

        return await memo_service.list_memos(
            user_id=user_id,
            creator_id=creator_id,
            tag=tag,
            pinned=pinned,
            row_status=row_status,
            start_date=dt_start,
            end_date=dt_end,
            workspace_id=workspace_id,
        )
    except Exception as exc:
        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),
    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
    - MemoService/CreateMemo -> POST /api/v1/memos
    """
    try:
        user_id = get_current_user_id(request)
        raw = payload if isinstance(payload, dict) else {}

        if isinstance(raw.get("memo"), dict):
            memo_create = MemoCreate(**raw["memo"])
            return await memo_service.create_memo(memo_create, user_id=user_id)

        if "content" in raw:
            memo_create = MemoCreate(**raw)
            return await memo_service.create_memo(memo_create, user_id=user_id)

        tag = raw.get("tag") if isinstance(raw.get("tag"), str) else None

        start_date = None
        end_date = None
        raw_filter = raw.get("filter", "")

        creator_id = None
        if raw_filter and isinstance(raw_filter, str):
            logger.debug("List memos POST with raw_filter=%r", raw_filter)
            start_date, end_date = parse_date_range(filter_str=raw_filter)
            pattern_creator = r"creator_id\s*==\s*([a-zA-Z0-9_\-\.]+)"
            match_creator = re.search(pattern_creator, raw_filter)
            if match_creator:
                creator_id = match_creator.group(1)

        pinned = None
        if raw_filter and isinstance(raw_filter, str):
            if re.search(r'\bpinned\b(?!\s*==\s*false)', raw_filter):
                pinned = True

        return await memo_service.list_memos(
            user_id=user_id,
            creator_id=creator_id,
            tag=tag,
            pinned=pinned,
            row_status=row_status,
            start_date=start_date,
            end_date=end_date,
            workspace_id=raw.get("workspace_id") or raw.get("workspaceId"),
        )
    except Exception as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc


@router.get("/deadlines", summary="List all memos with deadline", response_model=DeadlineListResponse)
async def list_deadlines(
    request: Request,
    workspace_id: str | None = Query(default=None, description="Workspace filter: PERSONAL or AI_SALES_CRM"),
    memo_service=Depends(get_memo_service),
):
    """
    Return all memos with deadline for current user,
    categorized: overdue | today | upcoming (7 days) | no_date (has priority, no deadline).
    """
    try:
        user_id = get_current_user_id(request)
        if not user_id or user_id == "anonymous":
            return DeadlineListResponse()
        from common.timezone_config import VIETNAM_TZ
        now_vn = datetime.now(VIETNAM_TZ)
        today_start = now_vn.replace(hour=0, minute=0, second=0, microsecond=0)
        today_end = now_vn.replace(hour=23, minute=59, second=59, microsecond=999999)
        next_7_days = today_end + timedelta(days=7)

        # Get all memos for user and filter in memory (simpler with SQLite)
        memos = await memo_service.list_memos(user_id=user_id, row_status="NORMAL", workspace_id=workspace_id)

        overdue, today, upcoming, no_date = [], [], [], []

        for memo in memos:
            if not memo.deadline and not memo.priority:
                continue

            if not memo.deadline:
                no_date.append(memo)
                continue

            dl = parse_time(memo.deadline) if isinstance(memo.deadline, str) else memo.deadline
            if not dl:
                continue

            dl_vn = dl.astimezone(VIETNAM_TZ) if dl.tzinfo else dl.replace(tzinfo=VIETNAM_TZ)

            if memo.is_completed:
                continue
            elif dl_vn < today_start:
                overdue.append(memo)
            elif dl_vn <= today_end:
                today.append(memo)
            elif dl_vn <= next_7_days:
                upcoming.append(memo)

        total = len(overdue) + len(today) + len(upcoming) + len(no_date)
        return DeadlineListResponse(
            overdue=overdue,
            today=today,
            upcoming=upcoming,
            no_date=no_date,
            total=total,
        )
    except Exception as exc:
        raise HTTPException(status_code=500, 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: str,
    workspace_id: str | None = Query(default=None, description="Workspace filter for isolation check"),
    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, workspace_id=workspace_id)
    except Exception as exc:
        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: str,
    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:
        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: str,
    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:
        raise HTTPException(status_code=400, detail=str(exc)) from exc


@router.get("/{memo_id}/versions", summary="Get memo version history", response_model=MemoVersionResponse)
async def get_memo_versions(
    request: Request,
    memo_id: str,
    memo_service=Depends(get_memo_service),
):
    """Get version history for a memo."""
    try:
        user_id = get_current_user_id(request)
        return await memo_service.get_memo_versions(memo_id, user_id=user_id)
    except Exception as exc:
        raise HTTPException(status_code=404, detail=str(exc)) from exc


@router.post("/{memo_id}/comments", summary="Create comment", response_model=MemoResponse)
async def create_memo_comment(
    request: Request,
    memo_id: str,
    payload: MemoCreate,
    memo_service=Depends(get_memo_service),
    memo_relation_service=Depends(get_memo_relation_service),
):
    """
    Create a comment for a memo.
    - Creates a new memo with parent = memo_id
    - Creates a MemoRelation with type = COMMENT
    - Returns the created comment
    """
    try:
        user_id = get_current_user_id(request)

        original_memo = await memo_service.get_memo(memo_id, user_id=user_id)
        if not original_memo:
            raise HTTPException(status_code=404, detail=f"Memo {memo_id} not found")

        parent_id_str = memo_id

        if payload.anonymous_id or payload.anonymous_name:
            anonymous_id = payload.anonymous_id or f"anonymous_{secrets.token_hex(4)}"
            anonymous_name = payload.anonymous_name

            if anonymous_name:
                import base64
                encoded_name = base64.urlsafe_b64encode(anonymous_name.encode('utf-8')).decode('ascii')
                encoded_name = encoded_name[:50].rstrip('=')
                synthetic_user_id = f"{anonymous_id}_{encoded_name}"
            else:
                synthetic_user_id = anonymous_id
            user_id = synthetic_user_id
        elif user_id is None:
            user_id = f"anonymous_{secrets.token_hex(4)}"

        base_anonymous_id = None
        if user_id and user_id.startswith("anonymous_"):
            parts = user_id.split("_", 2)
            if len(parts) >= 2:
                base_anonymous_id = f"{parts[0]}_{parts[1]}"
            else:
                base_anonymous_id = user_id
            comment_visibility = payload.visibility or "PUBLIC"
        else:
            comment_visibility = payload.visibility or "PUBLIC"

        comment_payload = MemoCreate(
            content=payload.content,
            visibility=comment_visibility,
            tags=payload.tags or [],
            create_time=payload.create_time
        )

        comment = await memo_service.create_memo(
            comment_payload,
            user_id=user_id,
            parent_id=parent_id_str,
            anonymous_id=base_anonymous_id
        )

        await memo_relation_service.create_relation(
            memo_id=comment.id,
            related_memo_id=parent_id_str,
            relation_type="COMMENT"
        )

        try:
            from common.memos_core.services import ActivityService, NotificationService
            activity_service = ActivityService()
            notification_service = NotificationService()

            activity = await activity_service.create_activity(
                activity_type="MEMO_COMMENT",
                creator_id=user_id,
                memo_id=comment.id,
                related_memo_id=parent_id_str
            )

            activity_id = int(activity.name.split("/")[-1])

            parent_creator_id = original_memo.creator_id
            if comment_visibility == "PUBLIC" and parent_creator_id and parent_creator_id != user_id:
                await notification_service.create_notification(
                    recipient_id=parent_creator_id,
                    sender_id=user_id,
                    activity_id=activity_id,
                    notification_type="MEMO_COMMENT"
                )
        except Exception as notify_exc:
            import logging
            logging.warning(f"Failed to create notification: {notify_exc}")

        return comment

    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc


@router.get("/{memo_id}/comments", summary="List comments", response_model=dict)
async def list_memo_comments(
    request: Request,
    memo_id: str,
    anonymous_id: str | None = Query(None, description="Anonymous user ID for filtering PRIVATE comments"),
    memo_service=Depends(get_memo_service),
):
    """
    List all comments for a memo.
    Uses memo_service.list_comments() which handles all filtering.
    """
    try:
        user_id = get_current_user_id(request)
        comments = await memo_service.list_comments(memo_id, user_id=user_id)

        return {
            "memos": comments,
            "nextPageToken": "",
            "totalSize": len(comments)
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc
@router.patch("/{memo_id}/complete", summary="Mark memo as done/undone", response_model=MemoResponse)
async def complete_memo(
    request: Request,
    memo_id: str,
    done: bool = True,
    memo_service=Depends(get_memo_service),
):
    """
    Shortcut to tick/untick completion.
    PATCH /api/v1/memos/{id}/complete?done=true  -> DONE
    PATCH /api/v1/memos/{id}/complete?done=false -> PENDING
    """
    try:
        user_id = get_current_user_id(request)
        return await memo_service.update_memo(
            memo_id,
            MemoUpdate(is_completed=done),
            user_id=user_id,
        )
    except Exception as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc


@router.patch("/{memo_id}/pin", summary="Pin/unpin memo", response_model=MemoResponse)
@router.post("/{memo_id}/pin", summary="Pin/unpin memo (compat)", response_model=MemoResponse)
async def pin_memo(
    request: Request,
    memo_id: str,
    payload: dict = Body(default_factory=dict),
    pinned: bool | None = Query(default=None),
    memo_service=Depends(get_memo_service),
):
    """
    Shortcut to pin/unpin a memo.
    Supports POST/PATCH with payload {"pinned": true/false} or query ?pinned=true
    """
    try:
        user_id = get_current_user_id(request)
        is_pinned = payload.get("pinned", True) if pinned is None else pinned
        return await memo_service.update_memo(
            memo_id,
            MemoUpdate(pinned=is_pinned),
            user_id=user_id,
        )
    except Exception as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc


@router.get("/{memo_id}/comments", summary="Get comments for a memo", response_model=List[MemoResponse])
async def list_memo_comments_simple(
    request: Request,
    memo_id: str,
    memo_service=Depends(get_memo_service),
):
    """Get all comments for a specific memo."""
    try:
        user_id = get_current_user_id(request)
        return await memo_service.list_comments(memo_id, user_id=user_id)
    except Exception as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc


@router.post("/{memo_id}/reactions", summary="Add reaction to memo")
async def add_memo_reaction(
    request: Request,
    memo_id: str,
    payload: dict = Body(...),
    reaction_service=Depends(get_reaction_service),
):
    """Add an emoji reaction to a memo."""
    try:
        user_id = get_current_user_id(request)
        reaction_type = payload.get("reactionType") or payload.get("reaction_type")
        if not reaction_type:
            raise ValueError("Missing reactionType")

        doc = await reaction_service.add_reaction(
            content_id=memo_id,
            reaction_type=reaction_type,
            user_id=user_id,
        )
        return {
            "name": f"memos/{memo_id}/reactions/{doc.get('reaction_type')}",
            "creator": f"users/{doc.get('creator_id')}",
            "contentId": f"memos/{memo_id}",
            "reactionType": doc.get("reaction_type")
        }
    except Exception as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc


@router.delete("/{memo_id}/reactions/{reaction_type}", summary="Remove reaction from memo")
async def remove_memo_reaction(
    request: Request,
    memo_id: str,
    reaction_type: str,
    reaction_service=Depends(get_reaction_service),
):
    """Remove an emoji reaction from a memo."""
    try:
        user_id = get_current_user_id(request)
        await reaction_service.remove_reaction(
            content_id=memo_id,
            reaction_type=reaction_type,
            user_id=user_id,
        )
        return {"status": "success"}
    except Exception as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc
