#!/usr/bin/env python3
"""OpenFUT save maintenance — inspect and repair fifa17_profile.json offline.

Exists because the pack→club hand-off is not proven. Cards from an opened pack land
in the PENDING pile (`profile["purchased"]`) and only reach the club when the client
sends `PUT ut/%s/item` (FutMoveCard) from the reveal screen's "send to club". Across
every logged session that request has fired **zero** times, while 12 cards sit
pending — so either the flow was never exercised in-game, or the client does not
issue it the way we assume. Same shape as the squad blocker: an assumed client
request that never actually arrives.

Until a live pack-open settles it, this is the manual path.

SAFETY: the client desyncs fatally (logout) if a card exists in BOTH the pending pile
and the club — see docs/CARD_SYSTEM.md and Store.move_items. `--flush-purchased`
therefore MOVES (never copies): each card is removed from `purchased` in the same
transaction that appends it to `items`. Run it with FIFA CLOSED so the client cannot
be holding a stale view of either pile.

Usage:
  fut_admin.py --show                 profile summary (default)
  fut_admin.py --flush-purchased      move every pending card into the club
  fut_admin.py --flush-purchased -n   dry run: show what would move
  fut_admin.py --backup               timestamped copy of the profile
"""
import argparse
import datetime
import json
import os
import shutil
import sys

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from fut_store import STORE                                        # noqa: E402


def _fmt(it):
    return "asset=%-7s rating=%-3s pos=%-4s id=%s" % (
        it.get("assetId"), it.get("rating"), it.get("preferredPosition"), it.get("id"))


def show():
    p = STORE.profile()
    rec = p.get("record", {})
    print("profile      : %s" % STORE.path)
    print("club         : %s (%s)  est %s" % (p.get("clubName"), p.get("clubAbbr"),
                                              p.get("established")))
    print("coins        : %s   points: %s" % (p.get("coins"), p.get("points")))
    print("record       : %s-%s-%s   matches: %s"
          % (rec.get("won", 0), rec.get("draw", 0), rec.get("loss", 0),
             p.get("matchesPlayed", 0)))
    print("club items   : %d" % len(p.get("items", [])))
    print("squads saved : %d" % len(p.get("squads", [])))
    print("packs opened : %s" % p.get("packsOpened", 0))
    print("listings     : %d" % len(p.get("listings", [])))
    print("clientdata   : %s" % (sorted(p.get("clientdata", {})) or "none"))
    pend = p.get("purchased", [])
    print("PENDING pack items: %d%s"
          % (len(pend), "   <-- not in the club; see --flush-purchased" if pend else ""))
    for it in pend[:20]:
        print("    %s" % _fmt(it))
    if len(pend) > 20:
        print("    ... and %d more" % (len(pend) - 20))


def backup():
    dst = "%s.%s.bak" % (STORE.path,
                         datetime.datetime.now().strftime("%Y%m%d-%H%M%S"))
    shutil.copy2(STORE.path, dst)
    print("backup -> %s" % dst)
    return dst


def flush(dry_run):
    pend = list(STORE.profile().get("purchased", []))
    if not pend:
        print("nothing pending — the club already has every pack card")
        return 0
    print("%d pending card(s)%s:" % (len(pend), " (DRY RUN)" if dry_run else ""))
    for it in pend:
        print("    %s" % _fmt(it))
    if dry_run:
        print("\ndry run — nothing written. Re-run without -n to move them.")
        return 0
    backup()
    # Reuse the server's own move path so the pending/club invariant is enforced in
    # exactly one place: move_items() deletes from `purchased` in the same locked
    # transaction that appends to `items`.
    moved = STORE.move_items([{"id": it["id"], "pile": "club"} for it in pend])
    p = STORE.profile()
    print("\nmoved %d card(s) into the club" % len(moved))
    print("club items now: %d   pending now: %d"
          % (len(p.get("items", [])), len(p.get("purchased", []))))
    if p.get("purchased"):
        print("WARNING: %d card(s) did not move — ids missing from the pending pile"
              % len(p["purchased"]))
    return 0


def main(argv=None):
    ap = argparse.ArgumentParser(description=__doc__,
                                 formatter_class=argparse.RawDescriptionHelpFormatter)
    ap.add_argument("--show", action="store_true", help="profile summary (default)")
    ap.add_argument("--flush-purchased", action="store_true",
                    help="move pending pack cards into the club (run with FIFA closed)")
    ap.add_argument("-n", "--dry-run", action="store_true", help="with --flush-purchased")
    ap.add_argument("--backup", action="store_true", help="timestamped profile copy")
    a = ap.parse_args(argv)
    if a.backup:
        backup()
    if a.flush_purchased:
        return flush(a.dry_run)
    show()
    return 0


if __name__ == "__main__":
    sys.exit(main())
