"""FastAPI REST API for the review system (serves the Angular UI)."""

from __future__ import annotations

import json
import os
from contextlib import asynccontextmanager
from typing import Optional

from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel

from . import db

REVIEW_PORT = int(os.environ.get("REVIEW_PORT", "3200"))


@asynccontextmanager
async def lifespan(_app: FastAPI):
    await db.init_db()
    yield


app = FastAPI(title="Review System API", lifespan=lifespan)

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_methods=["*"],
    allow_headers=["*"],
)


# --------------- Models ---------------


class ReviewCreate(BaseModel):
    author: str = "anonymous"
    text: str
    metadata: Optional[dict] = None
    tag: str = "general"
    parent_id: Optional[int] = None


class ReviewUpdate(BaseModel):
    status: Optional[str] = None
    text: Optional[str] = None
    author: Optional[str] = None
    resolved_by: Optional[str] = None
    metadata: Optional[dict] = None
    tag: Optional[str] = None


# --------------- Helpers ---------------


def _deserialize_row(row: dict) -> dict:
    """Parse the JSON metadata column in a review row."""
    if row.get("metadata"):
        try:
            row["metadata"] = json.loads(row["metadata"])
        except (json.JSONDecodeError, TypeError):
            pass
    return row


# --------------- Endpoints ---------------


@app.get("/api/reviews/summary")
async def summary():
    return await db.get_summary()


@app.get("/api/reviews")
async def all_reviews(status: Optional[str] = None, tag: Optional[str] = None):
    rows = await db.get_reviews(status=status, tag=tag)
    return [_deserialize_row(r) for r in rows]


@app.get("/api/reviews/{page_id:path}")
async def page_reviews(page_id: str, status: Optional[str] = None, tag: Optional[str] = None):
    rows = await db.get_reviews(page_id, status=status, tag=tag)
    return [_deserialize_row(r) for r in rows]


@app.post("/api/reviews/{page_id:path}", status_code=201)
async def create_review(page_id: str, body: ReviewCreate):
    meta_str = json.dumps(body.metadata) if body.metadata else None
    result = await db.insert_review(
        page_id, body.author, body.text, meta_str,
        tag=body.tag, parent_id=body.parent_id,
    )
    return _deserialize_row(result)


@app.patch("/api/review/{review_id}")
async def patch_review(review_id: int, body: ReviewUpdate):
    fields: dict = {}
    if body.status is not None:
        fields["status"] = body.status
        if body.status == "resolved":
            from datetime import datetime, timezone
            fields["resolved_at"] = datetime.now(timezone.utc).isoformat()
            fields["resolved_by"] = body.resolved_by or "user"
        elif body.status == "open":
            fields["resolved_at"] = None
            fields["resolved_by"] = None
    if body.text is not None:
        fields["text"] = body.text
    if body.author is not None:
        fields["author"] = body.author
    if body.metadata is not None:
        fields["metadata"] = json.dumps(body.metadata)
    if body.tag is not None:
        fields["tag"] = body.tag

    result = await db.update_review(review_id, **fields)
    if result is None:
        raise HTTPException(404, "Review not found")
    return _deserialize_row(result)


@app.get("/api/review/{review_id}/replies")
async def get_replies(review_id: int):
    rows = await db.get_replies(review_id)
    return [_deserialize_row(r) for r in rows]


@app.delete("/api/review/{review_id}")
async def remove_review(review_id: int):
    ok = await db.delete_review(review_id)
    if not ok:
        raise HTTPException(404, "Review not found")
    return {"deleted": True}


# --------------- Main ---------------

if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app, host="0.0.0.0", port=REVIEW_PORT)
