"""Feed and wheel endpoints."""
from __future__ import annotations

import json

from fastapi import APIRouter, Cookie, Depends, HTTPException, Request
from fastapi.responses import FileResponse, JSONResponse

from bincio.serve import deps, tasks
from bincio.serve.models import CurrentUserResponse
from bincio.serve.db import (
    User,
    get_member_tree,
    get_setting,
)

router = APIRouter()


@router.get("/api/me", response_model=CurrentUserResponse)
async def me(bincio_session: str | None = Cookie(default=None)) -> JSONResponse:
    user = deps._current_user(bincio_session)
    if not user:
        raise HTTPException(401, "Not authenticated")
    store_orig = get_setting(deps._get_db(), "store_originals")
    return JSONResponse({
        "handle": user.handle,
        "display_name": user.display_name,
        "is_admin": user.is_admin,
        "wiki_access": user.wiki_access,
        "activity_access": user.activity_access,
        "store_originals_default": store_orig != "false",
        "dem_configured": bool(deps.dem_url),
    })


@router.get("/api/stats")
async def stats() -> JSONResponse:
    """Public endpoint: member count, join dates, and invitation tree."""
    import time as _time
    now = int(_time.time())
    members = get_member_tree(deps._get_db())
    return JSONResponse({
        "user_count": len(members),
        "members": [
            {
                "handle": m["handle"],
                "display_name": m["display_name"],
                "member_since": m["created_at"],
                "member_for_days": (now - m["created_at"]) // 86400,
                "invited_by": m["invited_by"],
            }
            for m in members
        ],
    })


@router.post("/api/internal/rebuild")
async def internal_rebuild(request: Request) -> JSONResponse:
    """Trigger a site rebuild. Authenticated via X-Sync-Secret header.

    Called by the bincio sync-strava systemd timer after syncing new activities.
    Returns 503 if webroot is not configured (rebuild not possible).
    Returns 403 if the secret is missing or wrong.
    """
    if not deps.sync_secret:
        raise HTTPException(503, "Rebuild endpoint not configured (no sync secret set)")
    if request.headers.get("X-Sync-Secret") != deps.sync_secret:
        raise HTTPException(403, "Forbidden")
    if deps.site_dir is None:
        raise HTTPException(503, "No site dir configured")
    tasks._site_rebuild_event.set()
    return JSONResponse({"status": "rebuild queued"})


@router.get("/api/wheel/version")
async def wheel_version() -> JSONResponse:
    """Public endpoint: current bincio wheel version for mobile app update checks."""
    import importlib.metadata
    try:
        version = importlib.metadata.version("bincio")
    except importlib.metadata.PackageNotFoundError:
        version = "0.1.0"
    return JSONResponse({
        "version": version,
        "url": f"/bincio-{version}-py3-none-any.whl",
        "api_url": f"/api/wheel/download",
    })


@router.get("/api/wheel/download")
async def wheel_download() -> FileResponse:
    """Serve the bincio wheel directly (used locally; in prod nginx serves /bincio-*.whl)."""
    import importlib.metadata
    from pathlib import Path
    try:
        version = importlib.metadata.version("bincio")
    except importlib.metadata.PackageNotFoundError:
        version = "0.1.0"
    wheel_name = f"bincio-{version}-py3-none-any.whl"
    # Look in dist/ relative to repo root (two levels up from this file)
    dist_dir = Path(__file__).parent.parent.parent.parent / "dist"
    wheel_path = dist_dir / wheel_name
    if not wheel_path.exists():
        raise HTTPException(status_code=404, detail=f"{wheel_name} not found in dist/")
    return FileResponse(wheel_path, media_type="application/zip", filename=wheel_name)


@router.get("/api/feed")
async def get_feed(user: User = Depends(deps._require_auth)) -> JSONResponse:
    """Return the authenticated user's activity summaries (mobile feed sync).

    _merged/index.json is a shard manifest (activities: []) when the user has
    more than FEED_PAGE_SIZE activities.  Collect from all shard files.
    """
    dd = deps._get_data_dir()
    user_dir = dd / user.handle
    for index_path in (user_dir / "_merged" / "index.json", user_dir / "index.json"):
        if not index_path.exists():
            continue
        index = json.loads(index_path.read_text())
        activities: list[dict] = index.get("activities", [])
        for shard in index.get("shards", []):
            shard_path = index_path.parent / shard["url"]
            if shard_path.exists():
                shard_doc = json.loads(shard_path.read_text())
                activities.extend(shard_doc.get("activities", []))
        return JSONResponse({"activities": activities})
    return JSONResponse({"activities": []})
