"""store.py - JSON file-based data persistence layer."""
import json, os, time, threading, secrets, string
from datetime import datetime, timedelta

DATA_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "data")
_lock = threading.Lock()

def _path(name):
    return os.path.join(DATA_DIR, f"{name}.json")

def _load(name, default=None):
    fp = _path(name)
    if not os.path.exists(fp):
        return default if default is not None else {}
    with open(fp, "r", encoding="utf-8") as f:
        return json.load(f)

def _save(name, data):
    os.makedirs(DATA_DIR, exist_ok=True)
    fp = _path(name)
    tmp = fp + ".tmp"
    with _lock:
        with open(tmp, "w", encoding="utf-8") as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
        os.rename(tmp, fp)

# ===== Users =====
def get_users():
    return _load("users", {})

def save_users(users):
    _save("users", users)

def get_user(username):
    return get_users().get(username)

def add_user(username, password_hash, expires_at, card_code):
    users = get_users()
    users[username] = {
        "username": username,
        "password_hash": password_hash,
        "expires_at": expires_at,
        "card_code": card_code,
        "created_at": datetime.utcnow().isoformat(),
    }
    save_users(users)

def update_user(username, **kwargs):
    users = get_users()
    if username in users:
        users[username].update(kwargs)
        save_users(users)

# ===== Cards =====
def get_cards():
    return _load("cards", {})

def save_cards(cards):
    _save("cards", cards)

def get_card(card_code):
    return get_cards().get(card_code)

def add_card(card_code, days):
    cards = get_cards()
    cards[card_code] = {
        "card_code": card_code,
        "days": days,
        "used": False,
        "used_by": None,
        "used_at": None,
    }
    save_cards(cards)

def use_card(card_code, username):
    cards = get_cards()
    if card_code in cards and not cards[card_code]["used"]:
        cards[card_code]["used"] = True
        cards[card_code]["used_by"] = username
        cards[card_code]["used_at"] = datetime.utcnow().isoformat()
        save_cards(cards)
        return True
    return False

def gen_card_code():
    chars = string.ascii_uppercase + string.digits
    parts = ["".join(secrets.choice(chars) for _ in range(4)) for _ in range(4)]
    return "-".join(parts)

# ===== Options =====
DEFAULT_OPTIONS = {
    "workers": 40,
    "mail_stack": "haraka",
    "acme_ca": "selfsigned",
    "tls_key_type": "rsa",
    "enable_mail_tweaks": True,
    "rewrite_received": True,
    "dkim_sign_count": 3,
    "dkim_sign_mode": "mkt_lu_news",
    "dkim_custom_headers": "From, To, Subject, Date, Message-ID, MIME-Version, Content-Type",
    "dkim_selector": "",
    "dmarc_policy": "none",
    "spf_qualifier": "-all",
    "strip_headers": "X-Mailer, X-Mailer-Trace, User-Agent, X-Originating-IP, X-PHP-Originating-Script, X-MSMail-Priority, X-Priority, Importance, Organization, X-OriginatorOrg, Thread-Index, Thread-Topic, X-MS-Has-Attach, X-MS-TNEF-Correlator, X-深情, X-Haraka-Latency, X-Haraka-Auth-User, Feedback-ID, List-Id, List-Unsubscribe, List-Unsubscribe-Post, Precedence, X-Auto-Response-Suppress, Auto-Submitted, X-Entity-Ref-ID, X-Google-Original-From",
    "helo_name": "",
    "outbound_client_mode": "mobile",
    "received_mode": "single",
    "received_ehlo_domains": "",
    "received_mta_labels": "",
    "msgid_domain_mode": "hostname",
    "msgid_domain_custom": "",
    "header_rewrite_rules": "",
    "monitor_auto_minutes": 0,
    "quick_paste": {
        "default_token": "",
        "email_prefix": "admin",
        "ssh_password": "",
        "ip_text": "",
        "domain_text": "",
        "prefix": "",
        "start_number": 1,
        "port": "22",
        "user": "root",
    },
    "deploy_templates": [],
    "active_deploy_template_id": "",
}

def get_options():
    opts = _load("options", None)
    if opts is None:
        opts = DEFAULT_OPTIONS.copy()
        save_options(opts)
    # merge defaults for any missing keys
    merged = DEFAULT_OPTIONS.copy()
    merged.update(opts)
    return merged

def save_options(opts):
    _save("options", opts)

# ===== Servers =====
def get_servers():
    return _load("servers", [])

def save_servers(servers):
    _save("servers", servers)

def clear_servers():
    save_servers([])

def add_servers(new_servers):
    servers = get_servers()
    for ns in new_servers:
        existing = next((s for s in servers if s["ip"] == ns["ip"]), None)
        if existing:
            existing.update(ns)
        else:
            servers.append(ns)
    save_servers(servers)

def update_server(ip, **kwargs):
    servers = get_servers()
    for s in servers:
        if s["ip"] == ip:
            s.update(kwargs)
            break
    save_servers(servers)

# ===== Templates =====
def get_templates():
    return _load("templates", {"templates": [], "active_id": ""})

def save_templates(data):
    _save("templates", data)

def add_template(name, options_snapshot):
    data = get_templates()
    tid = secrets.token_hex(6)
    # build summary from options
    stack_id = options_snapshot.get("mail_stack", "")
    dkim_id = options_snapshot.get("dkim_sign_mode", "")
    count = options_snapshot.get("dkim_sign_count", 1)
    from datetime import datetime as _dt
    data["templates"].append({
        "id": tid,
        "name": name,
        "config": options_snapshot,
        "updated_at": _dt.now().strftime("%Y-%m-%d %H:%M:%S"),
        "summary": f"{stack_id} / {dkim_id} / x{count}",
    })
    data["active_id"] = tid
    save_templates(data)
    return tid

def delete_template(tid):
    data = get_templates()
    data["templates"] = [t for t in data["templates"] if t["id"] != tid]
    if data["active_id"] == tid:
        data["active_id"] = ""
    save_templates(data)

def set_active_template(tid):
    data = get_templates()
    data["active_id"] = tid
    save_templates(data)

# ===== Files metadata =====
def get_files_meta():
    return _load("files", {"files": []})

def save_files_meta(data):
    _save("files", data)