"""FastAPI REST 接口：把上面所有能力暴露成 HTTP

运行：
    pip install "fastapi[standard]" "psycopg[binary]" psycopg_pool
    uvicorn code.api:app --host 0.0.0.0 --port 8000 --reload
    # 或直接：python code/api.py

浏览器打开 http://localhost:8000/docs 可看到 Swagger UI。
"""
from __future__ import annotations

import sys
from typing import Optional

try:
    from fastapi import FastAPI, HTTPException, Query
    from pydantic import BaseModel
except ImportError:
    print("[ERROR] 未安装 fastapi，请 pip install 'fastapi[standard]'")
    sys.exit(1)

import auth
import posts as posts_mod
import search_fulltext
import search_trgm
import search_vector
import comments_tree
import refresh_hot


app = FastAPI(title="PG 综合实战 · 博客 API",
              description="第 19 章产物：一个 REST 接口把所有 PG 能力串起来",
              version="1.0.0")


# ------------------------- 数据模型 -------------------------
class SignupIn(BaseModel):
    tenant_id: int = 1
    username: str
    email: str
    password: str


class LoginIn(BaseModel):
    tenant_id: int = 1
    username: str
    password: str


class PublishIn(BaseModel):
    tenant_id: int = 1
    author_id: int
    title: str
    body: str
    tags: list[str] = []


# ------------------------- 健康检查 -------------------------
@app.get("/health")
def health() -> dict:
    from db import fetch_one
    return fetch_one("SELECT version() AS pg, now() AS server_time") or {}


# -------------------------- Auth --------------------------
@app.post("/signup")
def signup(body: SignupIn) -> dict:
    try:
        uid = auth.signup(body.tenant_id, body.username, body.email, body.password)
        return {"user_id": uid}
    except Exception as e:
        raise HTTPException(400, str(e))


@app.post("/login")
def login(body: LoginIn) -> dict:
    uid = auth.login(body.tenant_id, body.username, body.password)
    if not uid:
        raise HTTPException(401, "用户名或密码错误")
    return {"user_id": uid}


# -------------------------- Posts --------------------------
@app.post("/posts")
def publish(body: PublishIn) -> dict:
    pid = posts_mod.publish(body.tenant_id, body.author_id,
                            body.title, body.body, body.tags)
    return {"post_id": pid}


@app.get("/posts/recent")
def recent(tenant_id: int = 1, limit: int = 10) -> list[dict]:
    return posts_mod.list_recent(tenant_id, limit)


@app.get("/posts/by_tag")
def by_tag(tenant_id: int = 1, tag: str = "postgres") -> list[dict]:
    return posts_mod.filter_by_tag(tenant_id, tag)


# -------------------------- Search --------------------------
@app.get("/search/fulltext")
def s_fulltext(q: str = Query(..., min_length=1), tenant_id: int = 1,
               limit: int = 10) -> list[dict]:
    return search_fulltext.search(tenant_id, q, limit)


@app.get("/search/trgm")
def s_trgm(q: str = Query(..., min_length=1), tenant_id: int = 1,
           limit: int = 10) -> list[dict]:
    return search_trgm.search(tenant_id, q, limit)


@app.get("/search/vector")
def s_vector(q: str = Query(..., min_length=1), tenant_id: int = 1,
             limit: int = 5) -> list[dict]:
    return search_vector.search(tenant_id, q, limit)


@app.post("/search/vector/reindex")
def s_vector_reindex(tenant_id: int = 1) -> dict:
    n = search_vector.build_index_for_all(tenant_id)
    return {"new_embeddings": n}


# -------------------------- Comments --------------------------
@app.get("/comments/tree")
def comment_tree(post_id: int) -> list[dict]:
    return comments_tree.build_tree(post_id)


# -------------------------- Hot --------------------------
@app.get("/hot")
def hot(tenant_id: int = 1, n: int = 10) -> list[dict]:
    return refresh_hot.top_n(tenant_id, n)


@app.post("/hot/refresh")
def hot_refresh() -> dict:
    cost = refresh_hot.refresh(concurrent=True)
    return {"cost_sec": round(cost, 3)}


# -------------------------- main --------------------------
if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)
