"""FastAPI web application for serving wiki."""

import json
import os
from pathlib import Path
from typing import AsyncIterator, Optional

from fastapi import FastAPI, Query
from fastapi.responses import HTMLResponse, JSONResponse, StreamingResponse
from fastapi.staticfiles import StaticFiles

app = FastAPI(
    title="NanoWiki",
    description="AI-powered project documentation",
    version="0.1.0",
)

# Global state for wiki directory and project path
_wiki_dir: Optional[Path] = None
_project_path: Optional[Path] = None
_chatbot = None


def _init_from_env() -> None:
    """Initialize global state from environment variables (for reload mode)."""
    global _wiki_dir, _project_path, _chatbot

    wiki_dir_env = os.environ.get("NANOWIKI_WIKI_DIR")
    project_path_env = os.environ.get("NANOWIKI_PROJECT_PATH")

    if wiki_dir_env and project_path_env:
        _wiki_dir = Path(wiki_dir_env)
        _project_path = Path(project_path_env)

        # Initialize chatbot if not already done
        if _chatbot is None:
            from ..agents.chatbot import WikiChatbot
            _chatbot = WikiChatbot(_project_path, _wiki_dir)


# Try to initialize from environment on module load (for reload mode)
_init_from_env()


def start_server(
    wiki_dir: Path,
    project_path: Path,
    host: str = "127.0.0.1",
    port: int = 8000,
    reload: bool = False,
) -> None:
    """Start the web server.

    Args:
        wiki_dir: Path to the wiki directory
        project_path: Path to the project
        host: Host to bind to
        port: Port to bind to
        reload: Enable auto-reload
    """
    global _wiki_dir, _project_path, _chatbot
    _wiki_dir = wiki_dir
    _project_path = project_path

    # Set environment variables for reload mode
    os.environ["NANOWIKI_WIKI_DIR"] = str(wiki_dir)
    os.environ["NANOWIKI_PROJECT_PATH"] = str(project_path)

    # Initialize chatbot
    from ..agents.chatbot import WikiChatbot
    _chatbot = WikiChatbot(project_path, wiki_dir)

    import uvicorn

    uvicorn.run(
        "nanowiki.web.app:app",
        host=host,
        port=port,
        reload=reload,
    )


def get_wiki_dir() -> Path:
    """Get the current wiki directory.

    Returns:
        Path to wiki directory

    Raises:
        RuntimeError: If wiki_dir not set
    """
    if _wiki_dir is None:
        raise RuntimeError("Wiki directory not set")
    return _wiki_dir


@app.get("/", response_class=HTMLResponse)
async def serve_index() -> str:
    """Serve the SPA index page."""
    static_dir = Path(__file__).parent / "static"
    index_path = static_dir / "index.html"

    if not index_path.exists():
        return HTMLResponse(
            content="""
            <!DOCTYPE html>
            <html>
            <head><title>NanoWiki - Build Required</title></head>
            <body style="font-family: system-ui; padding: 2rem; text-align: center;">
                <h1>Frontend not built</h1>
                <p>Please build the frontend first:</p>
                <pre style="background: #f1f5f9; padding: 1rem; border-radius: 0.5rem;">
cd src/nanowiki/web/frontend
pnpm install
pnpm build
                </pre>
            </body>
            </html>
            """,
            status_code=500,
        )

    return index_path.read_text(encoding="utf-8")


@app.get("/api/page/{page_path:path}")
async def get_page(page_path: str) -> JSONResponse:
    """Get a wiki page's content.

    Args:
        page_path: Path to the page (e.g., "overview.md", "architecture.md")

    Returns:
        JSON response with page content
    """
    wiki_dir = get_wiki_dir()
    page_file = wiki_dir / page_path

    if not page_file.exists():
        return JSONResponse(
            {"error": f"Page not found: {page_path}"},
            status_code=404,
        )

    content = page_file.read_text(encoding="utf-8")
    return JSONResponse({"content": content, "path": page_path})


@app.get("/api/pages")
async def list_pages() -> JSONResponse:
    """List all wiki pages.

    Returns:
        JSON response with list of page paths
    """
    wiki_dir = get_wiki_dir()
    pages = []

    for md_file in wiki_dir.rglob("*.md"):
        rel_path = md_file.relative_to(wiki_dir)
        pages.append(str(rel_path))

    return JSONResponse({"pages": sorted(pages)})


@app.get("/api/info")
async def get_wiki_info() -> JSONResponse:
    """Get wiki metadata.

    Returns:
        JSON response with wiki info (project_path, created_at, updated_at)
    """
    wiki_dir = get_wiki_dir()
    cache_file = wiki_dir / "cache.json"

    if cache_file.exists():
        try:
            data = json.loads(cache_file.read_text(encoding="utf-8"))
            return JSONResponse({
                "project_path": data.get("project_path", ""),
                "created_at": data.get("created_at"),
                "updated_at": data.get("updated_at"),
            })
        except Exception:
            pass

    return JSONResponse(
        {"error": "Wiki info not found"},
        status_code=404,
    )


@app.get("/api/chat")
async def chat(question: str = Query(..., description="Question to ask")) -> StreamingResponse:
    """Chat endpoint with Server-Sent Events.

    Args:
        question: User's question about the project

    Returns:
        StreamingResponse with SSE
    """
    global _chatbot

    if _chatbot is None:
        # Fallback if chatbot not initialized
        async def generate_error() -> AsyncIterator[str]:
            yield f"data: {json.dumps({'content': 'Chatbot not initialized. Please restart the server.', 'done': True})}\n\n"

        return StreamingResponse(
            generate_error(),
            media_type="text/event-stream",
        )

    async def generate() -> AsyncIterator[str]:
        """Generate SSE stream using Claude Agent."""
        try:
            async for response_chunk in _chatbot.answer_stream(question):
                yield f"data: {json.dumps(response_chunk)}\n\n"
        except Exception as e:
            yield f"data: {json.dumps({'content': f'Error: {str(e)}', 'done': True})}\n\n"

    return StreamingResponse(
        generate(),
        media_type="text/event-stream",
        headers={
            "Cache-Control": "no-cache",
            "Connection": "keep-alive",
        },
    )


# Mount static files for CSS/JS
_static_dir = Path(__file__).parent / "static"
if _static_dir.exists():
    app.mount("/static", StaticFiles(directory=str(_static_dir)), name="static")
