"""
storage.py — small JSON-file "database" for settings + the donor leaderboard.
Kept file-based and dependency-free so the app runs with nothing but Flask.
"""
import json
import os
import threading
import time

from parsers import normalize_amount, format_usd

DATA_DIR = os.path.join(os.path.dirname(__file__), "data")
os.makedirs(DATA_DIR, exist_ok=True)

CONFIG_FILE = os.path.join(DATA_DIR, "config.json")
DONORS_FILE = os.path.join(DATA_DIR, "top_donations.json")
RECENT_FILE = os.path.join(DATA_DIR, "recent_alerts.json")

_LOCK = threading.Lock()

DEFAULT_CONFIG = {
    "phone": "",
    "group_id": "",
    "group_title": "",
    "source_username": "PayWayByABA_bot",
    "debug": True,
    "khr_rate": 4000,
    "alert_delay": 0.0,
    "alert_duration": 8.0,
    "alert_theme": "gold",
    "leaderboard_theme": "gold",
    "logo_file": "",
    "sound_file": "",
    "sound_volume": 0.30,
    "tts_enabled": True,
    "tts_voice": "en-US-JennyNeural",
    "tts_format": "New donation! {name} gave {amount} via {provider}!",
    "tts_rate": 0,
    "tts_volume": 10,
    "tts_pitch": 0,
    "logged_in": False,
    "logged_in_as": "",
}


def _read(path, default):
    if os.path.exists(path):
        try:
            with open(path, "r", encoding="utf-8") as f:
                return json.load(f)
        except Exception:
            return default
    return default


def _write_atomic(path, data):
    tmp = path + ".tmp"
    with open(tmp, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=2)
    os.replace(tmp, path)


def load_config():
    cfg = dict(DEFAULT_CONFIG)
    cfg.update(_read(CONFIG_FILE, {}))
    return cfg


def save_config(patch: dict):
    with _LOCK:
        cfg = load_config()
        cfg.update(patch)
        _write_atomic(CONFIG_FILE, cfg)
        return cfg


def load_donors():
    return _read(DONORS_FILE, {"donors": [], "updated": 0}).get("donors", [])


def update_top_donors(sender_display, sender_key, amount_str, khr_rate=4000.0):
    with _LOCK:
        donors = load_donors()
        value = normalize_amount(amount_str, khr_rate)

        entry = next((d for d in donors if d.get("key") == sender_key), None)
        if entry is None:
            entry = {"key": sender_key, "name": sender_display, "count": 0, "total_usd": 0.0}
            donors.append(entry)

        entry["count"] += 1
        entry["total_usd"] = round(entry.get("total_usd", 0.0) + value, 2)
        entry["name"] = sender_display

        donors.sort(key=lambda d: (-d.get("total_usd", 0.0), -d.get("count", 0),
                                    str(d.get("name", "")).lower()))
        top = donors[:25]
        for i, d in enumerate(top):
            d["rank"] = i + 1
            d["total_display"] = format_usd(d.get("total_usd", 0.0))

        _write_atomic(DONORS_FILE, {"donors": top, "updated": int(time.time() * 1000)})

        is_top = bool(top) and top[0].get("key") == sender_key
        rank = next((d["rank"] for d in top if d.get("key") == sender_key), None)
        return {
            "total_usd": entry.get("total_usd", 0.0),
            "total_display": format_usd(entry.get("total_usd", 0.0)),
            "count": entry.get("count", 1),
            "rank": rank,
            "is_top": is_top,
        }


def reset_donors():
    with _LOCK:
        _write_atomic(DONORS_FILE, {"donors": [], "updated": int(time.time() * 1000)})


def load_recent(limit=50):
    return _read(RECENT_FILE, {"items": []}).get("items", [])[:limit]


def push_recent(item, limit=50):
    with _LOCK:
        items = _read(RECENT_FILE, {"items": []}).get("items", [])
        items.insert(0, item)
        items = items[:limit]
        _write_atomic(RECENT_FILE, {"items": items})
        return items
