"""Admin-managed integration settings.

Reads keys from the DB (app_settings, Fernet-encrypted) first, then falls back
to environment variables. Lets the admin manage OAuth/Razorpay keys from the UI
without touching the server .env file.
"""
import os
import time
import threading

from database import SessionLocal
from models import AppSetting
from security import encrypt_secret, decrypt_secret

# Keys the admin can manage from the panel
MANAGED_KEYS = [
    "GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET",
    "MS_CLIENT_ID", "MS_CLIENT_SECRET", "MS_TENANT",
    "OAUTH_PUBLIC_BASE",
    "RAZORPAY_KEY_ID", "RAZORPAY_KEY_SECRET", "RAZORPAY_WEBHOOK_SECRET",
    "SMTP_HOST", "SMTP_PORT", "SMTP_USER", "SMTP_PASSWORD", "SMTP_FROM", "SMTP_FROM_NAME",
]

# Keys whose values must never be returned in plaintext to the UI
SECRET_KEYS = {"GOOGLE_CLIENT_SECRET", "MS_CLIENT_SECRET",
               "RAZORPAY_KEY_SECRET", "RAZORPAY_WEBHOOK_SECRET", "SMTP_PASSWORD"}

_cache = {}
_loaded = False
_loaded_at = 0.0
_TTL = 30  # seconds; picks up changes made by other workers/pods
_lock = threading.Lock()


def _load_from_db():
    db = SessionLocal()
    try:
        out = {}
        for row in db.query(AppSetting).all():
            if not row.value:
                continue
            try:
                out[row.key] = decrypt_secret(row.value)
            except Exception:
                out[row.key] = ""
        return out
    finally:
        db.close()


def refresh():
    global _loaded, _loaded_at
    with _lock:
        _cache.clear()
        _cache.update(_load_from_db())
        _loaded = True
        _loaded_at = time.time()


def get(key, default=None):
    global _loaded, _loaded_at
    with _lock:
        if not _loaded or (time.time() - _loaded_at) > _TTL:
            _cache.clear()
            _cache.update(_load_from_db())
            _loaded = True
            _loaded_at = time.time()
        val = _cache.get(key)
    if val:
        return val
    return os.environ.get(key, default)


def set_many(values: dict):
    """Persist provided managed keys. For SECRET_KEYS, an empty value is ignored
    (keeps the existing secret); for other keys empty clears the override."""
    db = SessionLocal()
    try:
        for k, v in values.items():
            if k not in MANAGED_KEYS:
                continue
            v = "" if v is None else str(v).strip()
            if k in SECRET_KEYS and v == "":
                continue
            row = db.query(AppSetting).filter(AppSetting.key == k).first()
            if not row:
                row = AppSetting(key=k)
                db.add(row)
            row.value = encrypt_secret(v)
        db.commit()
    finally:
        db.close()
    refresh()


def public_view():
    """Return current values for the admin UI: non-secrets in plaintext,
    secrets masked to a boolean 'is set'."""
    values, secrets_set = {}, {}
    for k in MANAGED_KEYS:
        v = get(k, "") or ""
        if k in SECRET_KEYS:
            secrets_set[k] = bool(v)
        else:
            values[k] = v
    return {"values": values, "secrets_set": secrets_set}
