"""File operations API routes."""

import logging
from typing import TYPE_CHECKING, Any

from fastapi import APIRouter, Depends, HTTPException, Request
from pydantic import BaseModel, Field

from ieum.server.auth import get_request_user_id

if TYPE_CHECKING:
    from ieum.server.services.session_service import SessionService

logger = logging.getLogger(__name__)

router = APIRouter()


def get_session_service(request: Request) -> Any:
    """Dependency to get the session service."""
    return request.app.state.session_service


def _require_owned_session(request: Request, session_service: Any, session_id: str) -> Any:
    """Return session if caller owns it, else raise 404."""
    config = request.app.state.config
    user_id = get_request_user_id(request, required=config.require_user_identity)
    session = session_service.get_session(session_id, user_id=user_id)
    if session is None:
        raise HTTPException(status_code=404, detail=f"Session {session_id} not found")
    return session


class FileNode(BaseModel):
    """File or directory node in the tree."""

    name: str
    path: str
    type: str = Field(description="'file' or 'directory'")
    size: int | None = None
    children: list["FileNode"] | None = None


class FileTreeResponse(BaseModel):
    """File tree response."""

    root: str
    tree: list[FileNode]


class FileContentResponse(BaseModel):
    """File content response."""

    path: str
    content: str
    size: int
    lines: int


class SaveFileRequest(BaseModel):
    """Request to save file content."""

    path: str
    content: str
    overwrite: bool = True  # If False, return 409 if file exists


class CreateFolderRequest(BaseModel):
    """Request to create a folder."""

    path: str
    overwrite: bool = True  # If False, return 409 if folder exists


class RenameFileRequest(BaseModel):
    """Request to rename a file."""

    old_path: str
    new_path: str


class DeleteFileRequest(BaseModel):
    """Request to delete a file."""

    path: str


@router.get("/{session_id}/files", response_model=FileTreeResponse)
async def get_file_tree(
    request: Request,
    session_id: str,
    path: str = "/",
    depth: int = 2,
    show_hidden: bool = False,
    session_service: Any = Depends(get_session_service),
) -> FileTreeResponse:
    """Get the file tree for a session.

    Args:
        session_id: Session ID.
        path: Root path for the tree (default: /).
        depth: Maximum depth to traverse (default: 2).
        show_hidden: Whether to show hidden files (default: False).
        session_service: Injected session service.

    Returns:
        File tree structure.
    """
    session = _require_owned_session(request, session_service, session_id)
    depth = max(0, min(depth, 10))

    try:
        tree = await session_service.get_file_tree(session_id, path, depth, show_hidden)
        # Return working directory name as root for project name display
        root_name = session.working_directory.replace("\\", "/").rstrip("/").split("/")[-1] or "Project"
        return FileTreeResponse(root=root_name, tree=tree)
    except PermissionError as e:
        raise HTTPException(status_code=403, detail=str(e)) from e
    except Exception:
        logger.exception("Unexpected error in file operation")
        raise HTTPException(status_code=500, detail="Internal server error") from None


@router.get("/{session_id}/files/content", response_model=FileContentResponse)
async def get_file_content(
    request: Request,
    session_id: str,
    path: str,
    session_service: Any = Depends(get_session_service),
) -> FileContentResponse:
    """Get the content of a file.

    Args:
        session_id: Session ID.
        path: File path to read.
        session_service: Injected session service.

    Returns:
        File content and metadata.
    """
    _require_owned_session(request, session_service, session_id)

    try:
        content, size = await session_service.get_file_content(session_id, path)
        lines = len(content.splitlines()) if content else 0
        return FileContentResponse(
            path=path,
            content=content,
            size=size,
            lines=lines,
        )
    except PermissionError as e:
        raise HTTPException(status_code=403, detail=str(e)) from e
    except FileNotFoundError as e:
        raise HTTPException(status_code=404, detail=str(e)) from e
    except Exception:
        logger.exception("Unexpected error in file operation")
        raise HTTPException(status_code=500, detail="Internal server error") from None


@router.post("/{session_id}/files/content")
async def save_file_content(
    request: Request,
    session_id: str,
    body: SaveFileRequest,
    session_service: Any = Depends(get_session_service),
) -> dict:
    """Save content to a file.

    Args:
        session_id: Session ID.
        request: Save file request with path and content.
        session_service: Injected session service.

    Returns:
        Success status.
    """
    _require_owned_session(request, session_service, session_id)

    try:
        await session_service.save_file_content(
            session_id, body.path, body.content, overwrite=body.overwrite
        )
        return {"success": True, "path": body.path}
    except PermissionError as e:
        raise HTTPException(status_code=403, detail=str(e)) from e
    except FileExistsError as e:
        raise HTTPException(status_code=409, detail=str(e)) from e
    except Exception:
        logger.exception("Unexpected error in file operation")
        raise HTTPException(status_code=500, detail="Internal server error") from None


@router.post("/{session_id}/files/folder")
async def create_folder(
    request: Request,
    session_id: str,
    body: CreateFolderRequest,
    session_service: Any = Depends(get_session_service),
) -> dict:
    """Create a new folder.

    Args:
        session_id: Session ID.
        request: Create folder request with path.
        session_service: Injected session service.

    Returns:
        Success status.
    """
    _require_owned_session(request, session_service, session_id)

    try:
        await session_service.create_folder(session_id, body.path, overwrite=body.overwrite)
        return {"success": True, "path": body.path}
    except PermissionError as e:
        raise HTTPException(status_code=403, detail=str(e)) from e
    except FileExistsError as e:
        raise HTTPException(status_code=409, detail=str(e)) from e
    except Exception:
        logger.exception("Unexpected error in file operation")
        raise HTTPException(status_code=500, detail="Internal server error") from None


@router.post("/{session_id}/files/rename")
async def rename_file(
    request: Request,
    session_id: str,
    body: RenameFileRequest,
    session_service: Any = Depends(get_session_service),
) -> dict:
    """Rename a file or folder.

    Args:
        session_id: Session ID.
        request: Rename request with old and new paths.
        session_service: Injected session service.

    Returns:
        Success status.
    """
    _require_owned_session(request, session_service, session_id)

    try:
        await session_service.rename_file(session_id, body.old_path, body.new_path)
        return {"success": True, "old_path": body.old_path, "new_path": body.new_path}
    except PermissionError as e:
        raise HTTPException(status_code=403, detail=str(e)) from e
    except FileNotFoundError as e:
        raise HTTPException(status_code=404, detail=str(e)) from e
    except Exception:
        logger.exception("Unexpected error in file operation")
        raise HTTPException(status_code=500, detail="Internal server error") from None


@router.post("/{session_id}/files/delete")
async def delete_file(
    request: Request,
    session_id: str,
    body: DeleteFileRequest,
    session_service: Any = Depends(get_session_service),
) -> dict:
    """Delete a file or folder.

    Args:
        session_id: Session ID.
        request: Delete request with path.
        session_service: Injected session service.

    Returns:
        Success status.
    """
    _require_owned_session(request, session_service, session_id)

    try:
        await session_service.delete_file(session_id, body.path)
        return {"success": True, "path": body.path}
    except PermissionError as e:
        raise HTTPException(status_code=403, detail=str(e)) from e
    except FileNotFoundError as e:
        raise HTTPException(status_code=404, detail=str(e)) from e
    except Exception:
        logger.exception("Unexpected error in file operation")
        raise HTTPException(status_code=500, detail="Internal server error") from None
