"""Admin Configuration page API: read/edit the DB-overridable operational settings defined in
app.sysconfig. Secret values (e.g. SMTP password) are write-only — never returned."""
import re

from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session

from app import audit
from app import email as email_mod
from app import sysconfig
from app.audit import AuditAction
from app.db import get_db
from app.models import User
from app.routes.admin import admin_user

router = APIRouter(prefix="/api/admin/config", tags=["admin"])

# Strip URL userinfo (user:pass@) so a non-secret setting that happens to embed credentials —
# e.g. an authenticated egress proxy http://user:pass@host:port — never lands plaintext in the
# audit trail. Non-secret values are shown live in the UI, but the log shouldn't retain creds.
_URL_USERINFO = re.compile(r"(://)[^/@\s]+@")


def _redact(v):
    return _URL_USERINFO.sub(r"\1***@", v) if isinstance(v, str) else v


@router.get("")
def get_config(_: User = Depends(admin_user), db: Session = Depends(get_db)) -> dict:
    return sysconfig.describe(db)


@router.patch("/{key}")
def set_config(
    key: str,
    payload: dict,
    admin: User = Depends(admin_user),
    db: Session = Depends(get_db),
) -> dict:
    s = sysconfig.spec(key)
    if s is None:
        raise HTTPException(status_code=404, detail="Unknown config key")
    if "value" not in payload:
        raise HTTPException(status_code=400, detail="Missing 'value'")
    if s.secret and not sysconfig.secrets_manageable():
        raise HTTPException(
            status_code=400,
            detail="Set TOKEN_ENCRYPTION_KEY to store secrets in the database.",
        )
    old = None if s.secret else sysconfig.get(db, key)
    try:
        sysconfig.set_value(db, key, payload["value"])
    except (TypeError, ValueError) as exc:
        raise HTTPException(status_code=400, detail=str(exc) or "Invalid value")
    # Never log a secret's value — only that it was changed, by whom. Non-secret values are logged
    # but with URL credentials redacted (a proxy/URL setting can embed user:pass). Skip the row when
    # a non-secret value didn't actually change (a no-op re-save shouldn't add trail noise); secrets
    # are write-only so we can't compare — always log.
    new = None if s.secret else sysconfig.get(db, key)
    if s.secret or new != old:
        audit.record(
            db, admin.id, AuditAction.CONFIG_SET, target_type="config", target_id=key,
            summary=f"{key} = (secret updated)" if s.secret else f"{key} = {_redact(new)}",
            before=None if s.secret else {"value": _redact(old)},
            after=None if s.secret else {"value": _redact(new)},
        )
        db.commit()
    return sysconfig.describe(db)


@router.delete("/{key}")
def reset_config(
    key: str,
    admin: User = Depends(admin_user),
    db: Session = Depends(get_db),
) -> dict:
    s = sysconfig.spec(key)
    if s is None:
        raise HTTPException(status_code=404, detail="Unknown config key")
    old = None if s.secret else sysconfig.get(db, key)
    sysconfig.reset(db, key)
    audit.record(
        db, admin.id, AuditAction.CONFIG_RESET, target_type="config", target_id=key,
        summary=f"{key} → default",
        before=None if s.secret else {"value": _redact(old)},
    )
    db.commit()
    return sysconfig.describe(db)


@router.post("/test-email")
def send_test_email(
    user: User = Depends(admin_user),
    db: Session = Depends(get_db),
) -> dict:
    """Send a test email to the requesting admin using the current (DB or env) SMTP config —
    lets the admin verify the settings actually work."""
    if not email_mod.email_enabled():
        raise HTTPException(status_code=400, detail="SMTP is not configured.")
    sent = email_mod.send_test(user.email)
    if not sent:
        raise HTTPException(status_code=422, detail="SMTP send failed — check the settings.")
    return {"sent": True, "to": user.email}
