"""Stateful MFA tools — the MCP stores enrollment in its OWN database (ats_mcp_db).
A project just passes a user_key; the MCP handles secret/OTP storage + verify.
"""
from datetime import datetime, timedelta

import pyotp

from db import get_conn
from tools.email_tools import send_email_otp as _send_email
from tools.mfa_tools import get_qr_code
from tools.policy_tools import get_mfa_policy

OTP_TTL_MIN = 5


def _get(user_key):
    with get_conn() as c, c.cursor() as cur:
        cur.execute("SELECT method, totp_secret, otp_code, otp_created, mfa_enabled "
                    "FROM mfa_users WHERE user_key=%s", (user_key,))
        r = cur.fetchone()
    if not r:
        return None
    return {"method": r[0], "totp_secret": r[1], "otp_code": r[2],
            "otp_created": r[3], "mfa_enabled": r[4]}


def _upsert(user_key, **fields):
    cols = ", ".join(fields.keys())
    vals = list(fields.values())
    sets = ", ".join(f"{k}=EXCLUDED.{k}" for k in fields)
    placeholders = ", ".join(["%s"] * len(fields))
    with get_conn() as c, c.cursor() as cur:
        cur.execute(
            f"INSERT INTO mfa_users (user_key, {cols}, updated_at) "
            f"VALUES (%s, {placeholders}, NOW()) "
            f"ON CONFLICT (user_key) DO UPDATE SET {sets}, updated_at=NOW()",
            [user_key] + vals,
        )
        c.commit()


def mfa_setup(user_key: str, email: str) -> dict:
    """Begin MFA for a user, using the admin's central method. Stores in MCP DB."""
    method = get_mfa_policy().get("method", "email")
    if method == "totp":
        secret = pyotp.random_base32()
        _upsert(user_key, method="totp", totp_secret=secret, mfa_enabled=0)
        return {"method": "totp", "secret": secret, "qr_code": get_qr_code(secret, email)}
    if method == "email":
        r = _send_email(email)                       # generate + email
        _upsert(user_key, method="email", otp_code=r["otp"],
                otp_created=datetime.utcnow(), mfa_enabled=0)
        return {"method": "email", "sent": r["sent"]}
    return {"method": "none"}


def mfa_send_login_otp(user_key: str, email: str) -> dict:
    """For email method: email a fresh login OTP and store it."""
    r = _send_email(email)
    _upsert(user_key, method="email", otp_code=r["otp"], otp_created=datetime.utcnow())
    return {"sent": r["sent"]}


def mfa_verify(user_key: str, code: str) -> bool:
    """Verify a code by the user's stored method. Marks enrolled on success."""
    row = _get(user_key)
    if not row:
        return False
    ok = False
    if row["method"] == "totp":
        ok = bool(row["totp_secret"]) and pyotp.TOTP(row["totp_secret"]).verify(code)
    elif row["method"] == "email":
        if row["otp_code"] and row["otp_code"] == code and row["otp_created"]:
            ok = datetime.utcnow() <= row["otp_created"] + timedelta(minutes=OTP_TTL_MIN)
    if ok:
        _upsert(user_key, mfa_enabled=1, otp_code="")
    return ok


def mfa_status(user_key: str) -> dict:
    """Return the user's MFA status from the MCP DB."""
    row = _get(user_key)
    if not row:
        return {"method": "none", "enabled": False, "enrolled": False}
    return {"method": row["method"], "enabled": bool(row["mfa_enabled"]),
            "enrolled": bool(row["totp_secret"]) or row["method"] == "email"}
