"""Headless management API at /api — token-authed, on-server only (see
deps.require_api_user). Lets Claude / the CLI create forms, clients, grants, and
invites without a browser session. Returns JSON. Never exposes entry data.
"""

from __future__ import annotations

from fastapi import APIRouter, Depends, HTTPException, Request

import auth
import deps
import services
from db import query_one

router = APIRouter(prefix="/api")


def _form_by_ref(ref: str):
    row = query_one("SELECT * FROM forms WHERE public_key = ?", (ref,))
    if not row and ref.isdigit():
        row = query_one("SELECT * FROM forms WHERE id = ?", (int(ref),))
    return row


def _require_form_access(user: auth.CurrentUser, ref: str):
    form = _form_by_ref(ref)
    if not form:
        raise HTTPException(status_code=404, detail="form not found")
    if not deps.user_can_access_form(user, form):
        raise HTTPException(status_code=403, detail="not your form")
    return form


def _integration(form) -> dict:
    base = deps.APP_BASE_URL
    key = form["public_key"]
    snippet = ('<form data-submitstream="' + key + '">…</form>\n'
               '<script src="' + base + '/embed.js" defer></script>')
    return {"submit_url": f"{base}/f/{key}", "script_snippet": snippet}


def _resolve_grantee(user: auth.CurrentUser, email: str, do_invite: bool) -> dict:
    """Find or create a client user for an email; return its id + optional setup link."""
    existing = services.find_client_by_email(email)
    if existing:
        cid, created = existing["id"], False
    else:
        cid = services.create_user(name=email.split("@")[0], email=email, role="client")
        created = True
    link = services.invite(cid, send_email=do_invite) if (created or do_invite) else None
    return {"client_id": cid, "email": email.strip().lower(), "created": created, "setup_link": link}


@router.get("/whoami")
def whoami(request: Request, user: auth.CurrentUser = Depends(deps.require_api_user)):
    return {"id": user.id, "email": user.email, "name": user.name, "role": user.role}


@router.get("/forms")
def list_forms(request: Request, user: auth.CurrentUser = Depends(deps.require_api_user)):
    forms = deps.forms_for(user)
    return {"forms": [
        {"id": f["id"], "public_key": f["public_key"], "name": f["name"],
         "notify_recipients": f["notify_recipients"], "active": bool(f["active"])}
        for f in forms]}


def _form_detail(form) -> dict:
    return {"id": form["id"], "public_key": form["public_key"], "name": form["name"],
            "notify_recipients": form["notify_recipients"], "allowed_origins": form["allowed_origins"],
            "redirect_url": form["redirect_url"], "active": bool(form["active"]),
            "grantees": [g["email"] for g in services.form_grantees(form["id"])]}


@router.get("/forms/{ref}")
def get_form(ref: str, request: Request, user: auth.CurrentUser = Depends(deps.require_api_user)):
    return _form_detail(_require_form_access(user, ref))


@router.patch("/forms/{ref}")
async def update_form(ref: str, request: Request,
                      user: auth.CurrentUser = Depends(deps.require_api_user)):
    form = _require_form_access(user, ref)
    body = await request.json()
    # Only admins may set a custom From (verified-sender domain).
    if "from_address" in body and not user.is_admin:
        raise HTTPException(status_code=403, detail="only admin can set from_address")
    try:
        services.update_form(form["id"], body)
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    updated = query_one("SELECT * FROM forms WHERE id = ?", (form["id"],))
    deps.log_event(f"form updated via API by {user.email}: {sorted(body.keys())}",
                   form_id=form["id"])
    return _form_detail(updated)


@router.post("/forms")
async def create_form(request: Request, user: auth.CurrentUser = Depends(deps.require_api_user)):
    body = await request.json()
    try:
        created = services.create_form(
            name=body.get("name", ""), creator_id=user.id,
            notify_recipients=body.get("notify_recipients", ""),
            redirect_url=body.get("redirect_url", ""),
            allowed_origins=body.get("allowed_origins"),  # None → default *.demoing.info
        )
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    form = query_one("SELECT * FROM forms WHERE id = ?", (created["id"],))
    grants = [_resolve_grantee(user, e, bool(body.get("invite", True)))
              for e in body.get("grant_emails", []) if e and "@" in e]
    for g in grants:
        services.grant_form(form["id"], g["client_id"])
    deps.log_event(f"form created via API by {user.email}", form_id=form["id"])
    return {"id": form["id"], "public_key": form["public_key"], "name": form["name"],
            "grants": grants, **_integration(form)}


@router.post("/clients")
async def create_client(request: Request, user: auth.CurrentUser = Depends(deps.require_api_user)):
    body = await request.json()
    role = body.get("role", "client")
    if role != "client" and not user.is_admin:
        raise HTTPException(status_code=403, detail="only admin can create manager/admin users")
    try:
        cid = services.create_user(name=body.get("name", ""), email=body.get("email", ""), role=role)
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    # Grant requested forms (must be accessible to the caller).
    granted = []
    for ref in (body.get("form_keys", []) or body.get("form_ids", [])):
        form = _require_form_access(user, str(ref))
        services.grant_form(form["id"], cid)
        granted.append(form["public_key"])
    link = services.invite(cid, send_email=bool(body.get("invite", True)))
    return {"client_id": cid, "email": body.get("email", "").strip().lower(),
            "granted_forms": granted, "setup_link": link}


@router.post("/forms/{ref}/grant")
async def grant(ref: str, request: Request, user: auth.CurrentUser = Depends(deps.require_api_user)):
    form = _require_form_access(user, ref)
    body = await request.json()
    email = (body.get("email") or "").strip().lower()
    if "@" not in email:
        raise HTTPException(status_code=400, detail="valid email required")
    g = _resolve_grantee(user, email, bool(body.get("invite", True)))
    services.grant_form(form["id"], g["client_id"])
    return {"form": form["public_key"], "granted": g}


@router.post("/forms/{ref}/revoke")
async def revoke(ref: str, request: Request, user: auth.CurrentUser = Depends(deps.require_api_user)):
    form = _require_form_access(user, ref)
    body = await request.json()
    existing = services.find_client_by_email((body.get("email") or "").strip().lower())
    if not existing:
        raise HTTPException(status_code=404, detail="user not found")
    services.revoke_form(form["id"], existing["id"])
    return {"form": form["public_key"], "revoked": existing["email"]}


@router.delete("/forms/{ref}")
def delete_form(ref: str, request: Request, user: auth.CurrentUser = Depends(deps.require_api_user)):
    form = _require_form_access(user, ref)
    services.delete_form(form["id"])
    return {"deleted_form": form["public_key"], "name": form["name"]}


@router.delete("/clients/{email}")
def delete_client(email: str, request: Request,
                  user: auth.CurrentUser = Depends(deps.require_api_user)):
    if not user.is_admin:
        raise HTTPException(status_code=403, detail="only admin can delete users")
    existing = services.find_client_by_email(email.strip().lower())
    if not existing:
        raise HTTPException(status_code=404, detail="user not found")
    try:
        services.delete_user(existing["id"], acting_admin_id=user.id)
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    return {"deleted_user": existing["email"]}
