"""
트리 구조 메모장 API 라우터
"""
from fastapi import APIRouter, Depends, HTTPException, status, Query
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, delete, func, and_, or_
from sqlalchemy.orm import selectinload
from typing import List, Optional
from uuid import UUID

from ...core.database import get_db
from ...models.user import User
from ...models.memo_tree import MemoTree, MemoNode, MemoNodeVersion, MemoTreeShare
from ...schemas.memo_tree import (
    MemoTreeCreate, MemoTreeUpdate, MemoTreeResponse, MemoTreeWithNodes,
    MemoNodeCreate, MemoNodeUpdate, MemoNodeResponse, MemoNodeMove,
    MemoTreeStats, MemoSearchRequest, MemoSearchResult
)
from ..dependencies import get_current_active_user

router = APIRouter(prefix="/memo-trees", tags=["memo-trees"])


# ============================================================================
# 메모 트리 관리
# ============================================================================

@router.get("/", response_model=List[MemoTreeResponse])
async def get_user_memo_trees(
    current_user: User = Depends(get_current_active_user),
    db: AsyncSession = Depends(get_db),
    include_archived: bool = Query(False, description="보관된 트리 포함 여부")
):
    """사용자의 메모 트리 목록 조회"""
    try:
        query = select(MemoTree).where(MemoTree.user_id == current_user.id)
        
        if not include_archived:
            query = query.where(MemoTree.is_archived == False)
        
        query = query.order_by(MemoTree.updated_at.desc())
        
        result = await db.execute(query)
        trees = result.scalars().all()
        
        # 각 트리의 노드 개수 계산
        tree_responses = []
        for tree in trees:
            node_count_result = await db.execute(
                select(func.count(MemoNode.id)).where(MemoNode.tree_id == tree.id)
            )
            node_count = node_count_result.scalar() or 0
            
            tree_dict = {
                "id": str(tree.id),
                "user_id": str(tree.user_id),
                "title": tree.title,
                "description": tree.description,
                "tree_type": tree.tree_type,
                "template_data": tree.template_data,
                "settings": tree.settings,
                "created_at": tree.created_at,
                "updated_at": tree.updated_at,
                "is_public": tree.is_public,
                "is_archived": tree.is_archived,
                "node_count": node_count
            }
            tree_responses.append(MemoTreeResponse(**tree_dict))
        
        return tree_responses
        
    except Exception as e:
        print(f"ERROR in get_user_memo_trees: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to get memo trees: {str(e)}"
        )


@router.post("/", response_model=MemoTreeResponse)
async def create_memo_tree(
    tree_data: MemoTreeCreate,
    current_user: User = Depends(get_current_active_user),
    db: AsyncSession = Depends(get_db)
):
    """새 메모 트리 생성"""
    try:
        new_tree = MemoTree(
            user_id=current_user.id,
            title=tree_data.title,
            description=tree_data.description,
            tree_type=tree_data.tree_type,
            template_data=tree_data.template_data or {},
            settings=tree_data.settings or {},
            is_public=tree_data.is_public
        )
        
        db.add(new_tree)
        await db.commit()
        await db.refresh(new_tree)
        
        tree_dict = {
            "id": str(new_tree.id),
            "user_id": str(new_tree.user_id),
            "title": new_tree.title,
            "description": new_tree.description,
            "tree_type": new_tree.tree_type,
            "template_data": new_tree.template_data,
            "settings": new_tree.settings,
            "created_at": new_tree.created_at,
            "updated_at": new_tree.updated_at,
            "is_public": new_tree.is_public,
            "is_archived": new_tree.is_archived,
            "node_count": 0
        }
        
        return MemoTreeResponse(**tree_dict)
        
    except Exception as e:
        await db.rollback()
        print(f"ERROR in create_memo_tree: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to create memo tree: {str(e)}"
        )


@router.get("/{tree_id}", response_model=MemoTreeResponse)
async def get_memo_tree(
    tree_id: UUID,
    current_user: User = Depends(get_current_active_user),
    db: AsyncSession = Depends(get_db)
):
    """메모 트리 상세 조회"""
    try:
        result = await db.execute(
            select(MemoTree).where(
                and_(
                    MemoTree.id == tree_id,
                    or_(
                        MemoTree.user_id == current_user.id,
                        MemoTree.is_public == True
                    )
                )
            )
        )
        tree = result.scalar_one_or_none()
        
        if not tree:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Memo tree not found"
            )
        
        # 노드 개수 계산
        node_count_result = await db.execute(
            select(func.count(MemoNode.id)).where(MemoNode.tree_id == tree.id)
        )
        node_count = node_count_result.scalar() or 0
        
        tree_dict = {
            "id": str(tree.id),
            "user_id": str(tree.user_id),
            "title": tree.title,
            "description": tree.description,
            "tree_type": tree.tree_type,
            "template_data": tree.template_data,
            "settings": tree.settings,
            "created_at": tree.created_at,
            "updated_at": tree.updated_at,
            "is_public": tree.is_public,
            "is_archived": tree.is_archived,
            "node_count": node_count
        }
        
        return MemoTreeResponse(**tree_dict)
        
    except HTTPException:
        raise
    except Exception as e:
        print(f"ERROR in get_memo_tree: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to get memo tree: {str(e)}"
        )


@router.put("/{tree_id}", response_model=MemoTreeResponse)
async def update_memo_tree(
    tree_id: UUID,
    tree_data: MemoTreeUpdate,
    current_user: User = Depends(get_current_active_user),
    db: AsyncSession = Depends(get_db)
):
    """메모 트리 업데이트"""
    try:
        result = await db.execute(
            select(MemoTree).where(
                and_(
                    MemoTree.id == tree_id,
                    MemoTree.user_id == current_user.id
                )
            )
        )
        tree = result.scalar_one_or_none()
        
        if not tree:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Memo tree not found"
            )
        
        # 업데이트할 필드들 적용
        update_data = tree_data.dict(exclude_unset=True)
        for field, value in update_data.items():
            setattr(tree, field, value)
        
        await db.commit()
        await db.refresh(tree)
        
        # 노드 개수 계산
        node_count_result = await db.execute(
            select(func.count(MemoNode.id)).where(MemoNode.tree_id == tree.id)
        )
        node_count = node_count_result.scalar() or 0
        
        tree_dict = {
            "id": str(tree.id),
            "user_id": str(tree.user_id),
            "title": tree.title,
            "description": tree.description,
            "tree_type": tree.tree_type,
            "template_data": tree.template_data,
            "settings": tree.settings,
            "created_at": tree.created_at,
            "updated_at": tree.updated_at,
            "is_public": tree.is_public,
            "is_archived": tree.is_archived,
            "node_count": node_count
        }
        
        return MemoTreeResponse(**tree_dict)
        
    except HTTPException:
        raise
    except Exception as e:
        await db.rollback()
        print(f"ERROR in update_memo_tree: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to update memo tree: {str(e)}"
        )


@router.delete("/{tree_id}")
async def delete_memo_tree(
    tree_id: UUID,
    current_user: User = Depends(get_current_active_user),
    db: AsyncSession = Depends(get_db)
):
    """메모 트리 삭제"""
    try:
        result = await db.execute(
            select(MemoTree).where(
                and_(
                    MemoTree.id == tree_id,
                    MemoTree.user_id == current_user.id
                )
            )
        )
        tree = result.scalar_one_or_none()
        
        if not tree:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Memo tree not found"
            )
        
        # 트리 삭제 (CASCADE로 관련 노드들도 자동 삭제됨)
        await db.delete(tree)
        await db.commit()
        
        return {"message": "Memo tree deleted successfully"}
        
    except HTTPException:
        raise
    except Exception as e:
        await db.rollback()
        print(f"ERROR in delete_memo_tree: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to delete memo tree: {str(e)}"
        )


# ============================================================================
# 메모 노드 관리
# ============================================================================

@router.get("/{tree_id}/nodes", response_model=List[MemoNodeResponse])
async def get_memo_tree_nodes(
    tree_id: UUID,
    current_user: User = Depends(get_current_active_user),
    db: AsyncSession = Depends(get_db)
):
    """메모 트리의 모든 노드 조회"""
    try:
        # 트리 접근 권한 확인
        tree_result = await db.execute(
            select(MemoTree).where(
                and_(
                    MemoTree.id == tree_id,
                    or_(
                        MemoTree.user_id == current_user.id,
                        MemoTree.is_public == True
                    )
                )
            )
        )
        tree = tree_result.scalar_one_or_none()
        
        if not tree:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Memo tree not found"
            )
        
        # 노드들 조회
        result = await db.execute(
            select(MemoNode)
            .where(MemoNode.tree_id == tree_id)
            .order_by(MemoNode.path, MemoNode.sort_order)
        )
        nodes = result.scalars().all()
        
        # 각 노드의 자식 개수 계산
        node_responses = []
        for node in nodes:
            children_count_result = await db.execute(
                select(func.count(MemoNode.id)).where(MemoNode.parent_id == node.id)
            )
            children_count = children_count_result.scalar() or 0
            
            node_dict = {
                "id": str(node.id),
                "tree_id": str(node.tree_id),
                "parent_id": str(node.parent_id) if node.parent_id else None,
                "user_id": str(node.user_id),
                "title": node.title,
                "content": node.content,
                "node_type": node.node_type,
                "sort_order": node.sort_order,
                "depth_level": node.depth_level,
                "path": node.path,
                "tags": node.tags or [],
                "node_metadata": node.node_metadata or {},
                "status": node.status,
                "word_count": node.word_count,
                "is_canonical": node.is_canonical,
                "canonical_order": node.canonical_order,
                "story_path": node.story_path,
                "created_at": node.created_at,
                "updated_at": node.updated_at,
                "children_count": children_count
            }
            node_responses.append(MemoNodeResponse(**node_dict))
        
        return node_responses
        
    except HTTPException:
        raise
    except Exception as e:
        print(f"ERROR in get_memo_tree_nodes: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to get memo tree nodes: {str(e)}"
        )


@router.post("/{tree_id}/nodes", response_model=MemoNodeResponse)
async def create_memo_node(
    tree_id: UUID,
    node_data: MemoNodeCreate,
    current_user: User = Depends(get_current_active_user),
    db: AsyncSession = Depends(get_db)
):
    """새 메모 노드 생성"""
    try:
        # 트리 접근 권한 확인
        tree_result = await db.execute(
            select(MemoTree).where(
                and_(
                    MemoTree.id == tree_id,
                    MemoTree.user_id == current_user.id
                )
            )
        )
        tree = tree_result.scalar_one_or_none()
        
        if not tree:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Memo tree not found"
            )
        
        # 부모 노드 확인 (있다면)
        if node_data.parent_id:
            parent_result = await db.execute(
                select(MemoNode).where(
                    and_(
                        MemoNode.id == UUID(node_data.parent_id),
                        MemoNode.tree_id == tree_id
                    )
                )
            )
            parent_node = parent_result.scalar_one_or_none()
            if not parent_node:
                raise HTTPException(
                    status_code=status.HTTP_404_NOT_FOUND,
                    detail="Parent node not found"
                )
        
        # 단어 수 계산
        word_count = 0
        if node_data.content:
            word_count = len(node_data.content.replace('\n', ' ').split())
        
        new_node = MemoNode(
            tree_id=tree_id,
            parent_id=UUID(node_data.parent_id) if node_data.parent_id else None,
            user_id=current_user.id,
            title=node_data.title,
            content=node_data.content,
            node_type=node_data.node_type,
            sort_order=node_data.sort_order,
            tags=node_data.tags or [],
            node_metadata=node_data.node_metadata or {},
            status=node_data.status,
            word_count=word_count,
            is_canonical=node_data.is_canonical or False
        )
        
        db.add(new_node)
        await db.commit()
        await db.refresh(new_node)
        
        node_dict = {
            "id": str(new_node.id),
            "tree_id": str(new_node.tree_id),
            "parent_id": str(new_node.parent_id) if new_node.parent_id else None,
            "user_id": str(new_node.user_id),
            "title": new_node.title,
            "content": new_node.content,
            "node_type": new_node.node_type,
            "sort_order": new_node.sort_order,
            "depth_level": new_node.depth_level,
            "path": new_node.path,
            "tags": new_node.tags or [],
            "node_metadata": new_node.node_metadata or {},
            "status": new_node.status,
            "word_count": new_node.word_count,
            "is_canonical": new_node.is_canonical,
            "canonical_order": new_node.canonical_order,
            "story_path": new_node.story_path,
            "created_at": new_node.created_at,
            "updated_at": new_node.updated_at,
            "children_count": 0
        }
        
        return MemoNodeResponse(**node_dict)
        
    except HTTPException:
        raise
    except Exception as e:
        await db.rollback()
        print(f"ERROR in create_memo_node: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to create memo node: {str(e)}"
        )


@router.get("/nodes/{node_id}", response_model=MemoNodeResponse)
async def get_memo_node(
    node_id: UUID,
    current_user: User = Depends(get_current_active_user),
    db: AsyncSession = Depends(get_db)
):
    """메모 노드 상세 조회"""
    try:
        result = await db.execute(
            select(MemoNode)
            .options(selectinload(MemoNode.tree))
            .where(MemoNode.id == node_id)
        )
        node = result.scalar_one_or_none()
        
        if not node:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Memo node not found"
            )
        
        # 접근 권한 확인
        if node.tree.user_id != current_user.id and not node.tree.is_public:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Not enough permissions to access this node"
            )
        
        # 자식 개수 계산
        children_count_result = await db.execute(
            select(func.count(MemoNode.id)).where(MemoNode.parent_id == node.id)
        )
        children_count = children_count_result.scalar() or 0
        
        node_dict = {
            "id": str(node.id),
            "tree_id": str(node.tree_id),
            "parent_id": str(node.parent_id) if node.parent_id else None,
            "user_id": str(node.user_id),
            "title": node.title,
            "content": node.content,
            "node_type": node.node_type,
            "sort_order": node.sort_order,
            "depth_level": node.depth_level,
            "path": node.path,
            "tags": node.tags or [],
            "node_metadata": node.node_metadata or {},
            "status": node.status,
            "word_count": node.word_count,
            "is_canonical": node.is_canonical,
            "canonical_order": node.canonical_order,
            "story_path": node.story_path,
            "created_at": node.created_at,
            "updated_at": node.updated_at,
            "children_count": children_count
        }
        
        return MemoNodeResponse(**node_dict)
        
    except HTTPException:
        raise
    except Exception as e:
        print(f"ERROR in get_memo_node: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to get memo node: {str(e)}"
        )


@router.put("/nodes/{node_id}", response_model=MemoNodeResponse)
async def update_memo_node(
    node_id: UUID,
    node_data: MemoNodeUpdate,
    current_user: User = Depends(get_current_active_user),
    db: AsyncSession = Depends(get_db)
):
    """메모 노드 업데이트"""
    try:
        result = await db.execute(
            select(MemoNode)
            .options(selectinload(MemoNode.tree))
            .where(MemoNode.id == node_id)
        )
        node = result.scalar_one_or_none()
        
        if not node:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Memo node not found"
            )
        
        # 접근 권한 확인 (소유자만 수정 가능)
        if node.tree.user_id != current_user.id:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Not enough permissions to update this node"
            )
        
        # 업데이트할 필드들 적용
        update_data = node_data.dict(exclude_unset=True)
        for field, value in update_data.items():
            if field == "parent_id" and value:
                # 부모 노드 유효성 검사
                parent_result = await db.execute(
                    select(MemoNode).where(
                        and_(
                            MemoNode.id == UUID(value),
                            MemoNode.tree_id == node.tree_id
                        )
                    )
                )
                parent_node = parent_result.scalar_one_or_none()
                if not parent_node:
                    raise HTTPException(
                        status_code=status.HTTP_404_NOT_FOUND,
                        detail="Parent node not found"
                    )
                setattr(node, field, UUID(value))
            elif field == "parent_id" and value is None:
                setattr(node, field, None)
            else:
                setattr(node, field, value)
        
        # 내용이 업데이트되면 단어 수 재계산
        if "content" in update_data:
            word_count = 0
            if node.content:
                word_count = len(node.content.replace('\n', ' ').split())
            node.word_count = word_count
        
        await db.commit()
        await db.refresh(node)
        
        # 자식 개수 계산
        children_count_result = await db.execute(
            select(func.count(MemoNode.id)).where(MemoNode.parent_id == node.id)
        )
        children_count = children_count_result.scalar() or 0
        
        node_dict = {
            "id": str(node.id),
            "tree_id": str(node.tree_id),
            "parent_id": str(node.parent_id) if node.parent_id else None,
            "user_id": str(node.user_id),
            "title": node.title,
            "content": node.content,
            "node_type": node.node_type,
            "sort_order": node.sort_order,
            "depth_level": node.depth_level,
            "path": node.path,
            "tags": node.tags or [],
            "node_metadata": node.node_metadata or {},
            "status": node.status,
            "word_count": node.word_count,
            "is_canonical": node.is_canonical,
            "canonical_order": node.canonical_order,
            "story_path": node.story_path,
            "created_at": node.created_at,
            "updated_at": node.updated_at,
            "children_count": children_count
        }
        
        return MemoNodeResponse(**node_dict)
        
    except HTTPException:
        raise
    except Exception as e:
        await db.rollback()
        print(f"ERROR in update_memo_node: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to update memo node: {str(e)}"
        )


@router.delete("/nodes/{node_id}")
async def delete_memo_node(
    node_id: UUID,
    current_user: User = Depends(get_current_active_user),
    db: AsyncSession = Depends(get_db)
):
    """메모 노드 삭제"""
    try:
        result = await db.execute(
            select(MemoNode)
            .options(selectinload(MemoNode.tree))
            .where(MemoNode.id == node_id)
        )
        node = result.scalar_one_or_none()
        
        if not node:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Memo node not found"
            )
        
        # 접근 권한 확인 (소유자만 삭제 가능)
        if node.tree.user_id != current_user.id:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Not enough permissions to delete this node"
            )
        
        # 노드 삭제 (CASCADE로 자식 노드들도 자동 삭제됨)
        await db.delete(node)
        await db.commit()
        
        return {"message": "Memo node deleted successfully"}
        
    except HTTPException:
        raise
    except Exception as e:
        await db.rollback()
        print(f"ERROR in delete_memo_node: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to delete memo node: {str(e)}"
        )
