# -*- coding: utf-8 -*-
"""
Utalvany-szintu eladasi adatok lekerese Shoprenter API-bol.

Mit kovet nyomon:
  1. UTALVANY ELADASOK - rendelesi tetelek ahol az eladott termek egy utalvany
     (cimlet alapjan: 10.000, 20.000, 30.000, 40.000, 50.000 Ft)
  2. UTALVANY FELHASZNALASOK - rendelesek ahol utalvanyt valtottak be
     (orderTotals-ban kedvezmenykent jelenik meg)
  3. PLUSZ KOLTES - felhasznalas eseten a rendeles totalja - utalvany erteke

Hasznalat:
  python utalvany_lekerdezes.py --debug                # 1 nap + reszletes debug fajl
  python utalvany_lekerdezes.py --napi 2026-05-19      # egy nap mentese DB-be
  python utalvany_lekerdezes.py --backfill 365         # 1 ev visszamenoleg
"""
import sys, os, sqlite3, argparse, json, time, re
from datetime import datetime, timedelta
from collections import defaultdict

try:
    sys.stdout.reconfigure(encoding="utf-8", errors="replace")
except Exception:
    pass

import requests
import base64

try:
    from config import *
except ImportError:
    print("HIBA: config.py hianyzik!")
    sys.exit(1)

SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
DB_PATH = os.path.join(SCRIPT_DIR, "webshop_adatok.db")
DEBUG_FILE = os.path.join(SCRIPT_DIR, "utalvany_debug.txt")

KIZART_STATUSZOK = {8, 10, 11, 12, 14, 15}
# Az utalvany-VASARLAST csak akkor szamoljuk, ha a rendeles statusza:
#   21 = "Utalvany kesz (szamlazva)" - a kollegak ezt allitjak amikor minden OK volt
VOUCHER_PURCHASE_VALID_STATUSES = {21}
UTALVANY_CIMLETEK = [10000, 20000, 30000, 40000, 50000]
UTALVANY_KULCSSZAVAK = [
    # alapfogalmak
    "utalvany", "utalvány",
    "ajandekutalvany", "ajándékutalvány", "ajandek utalvany", "ajándék utalvány",
    "ajándék utalvány", "ajandekkartya", "ajándékkártya",
    "voucher", "gift card", "gift-card", "giftcard",
    # temas variansok - a "utalvany"/"gift" szo gyakran benne van, de hatha nincs
    # ezeket csak akkor matcheljük ha CIMLET is matchel - igy nem keverjük a sima karacsonyi termekekkel
]
UTALVANY_TEMAS_HINTEK = [
    "karacsonyi", "karácsonyi", "christmas",
    "nevnapi", "névnapi", "birthday",
    "ballagasi", "ballagási", "graduation",
    "siminer", "síminer", "siszezon", "síszezon",
    "anyak napja", "anyák napja", "mothers", "anyanapi",
    "valentin", "valentine",
    "gyermeknapi", "gyermeknap",
    "husveti", "húsvéti", "easter",
]


def get_status_id_from_href(href):
    try:
        b64 = href.rstrip("/").split("/")[-1]
        decoded = base64.b64decode(b64 + "==").decode()
        return int(decoded.split("=")[-1])
    except Exception:
        return None


# ============================================================
# DB
# ============================================================

def init_db():
    con = sqlite3.connect(DB_PATH)
    con.execute("""
        CREATE TABLE IF NOT EXISTS napi_utalvany (
            datum TEXT NOT NULL,
            forras TEXT NOT NULL DEFAULT 'shoprenter',
            tipus TEXT NOT NULL,          -- 'vasarlas' | 'felhasznalas'
            cimlet INTEGER NOT NULL,      -- 10000, 20000, 30000, 40000, 50000 (vagy 0 = ismeretlen)
            db INTEGER NOT NULL DEFAULT 0,
            osszeg REAL NOT NULL DEFAULT 0,        -- utalvanyok namertekenek osszege Ft-ban
            pluszbol_koltott REAL NOT NULL DEFAULT 0, -- csak felhasznalasnal: a felhasznalt rendelesek totaljanak az utalvany ertekenek feletti resze
            PRIMARY KEY (datum, forras, tipus, cimlet)
        )
    """)
    con.commit()
    return con


def save_utalvany(con, datum, tipus, cimlet, db, osszeg, pluszbol_koltott=0):
    con.execute(
        """INSERT OR REPLACE INTO napi_utalvany
        (datum, forras, tipus, cimlet, db, osszeg, pluszbol_koltott)
        VALUES (?, 'shoprenter', ?, ?, ?, ?, ?)""",
        (datum, tipus, int(cimlet), int(db), float(osszeg), float(pluszbol_koltott))
    )


def delete_day_utalvany(con, datum):
    con.execute("DELETE FROM napi_utalvany WHERE datum=?", (datum,))


# ============================================================
# Utalvany felismeres logika
# ============================================================

def is_voucher_product(name, sku="", price=None):
    """Termek-e utalvany? Tobb minta egyutt:

    1. SKU 'utalvany<cimlet>-' formaban (LEGMEGBIZHATOBB - Schneider sajat naming)
    2. Nev tartalmaz 'utalvany'/'voucher' szot
    3. Temas jelzo (karacsonyi, ballagasi, stb) + szabvanyos cimletu ar
    """
    lo = (name or "").lower()
    sku_lo = (sku or "").lower()

    # 1. SKU minta: utalvany10000-... / utalvany20000-... stb.
    if sku_lo.startswith("utalvany") or sku_lo.startswith("utalvány"):
        return True

    # 2. Erős minta: kifejezett utalvany-szó
    for kw in UTALVANY_KULCSSZAVAK:
        if kw in lo or kw in sku_lo:
            return True

    # 3. Gyenge minta: csak temas jelzo + szabvanyos cimlet
    has_thematic = any(kw in lo for kw in UTALVANY_TEMAS_HINTEK)
    if has_thematic and price is not None:
        try:
            p = float(price)
            for n in UTALVANY_CIMLETEK:
                if abs(p - n) <= n * 0.05:
                    return True
        except Exception:
            pass

    return False


def get_voucher_denomination_from_sku(sku):
    """SKU alapjan kinyerhetjuk a cimletet.

    Tobbfele SKU formatumot tamogat:
      - 'utalvany20000-1088'              (sima)
      - 'utalvany-karacsony-30000-2282'   (karacsonyi temas)
      - 'utalvany-ballagasi-40000-...'    (mas temas)
    A barhol megtalalt szabvanyos cimletet adjuk vissza.
    """
    if not sku:
        return 0
    s = sku.lower()
    if "utalv" not in s:
        return 0
    # Nagyobb cimletektol indulunk - hogy a "10000" ne illeszkedjen a "100000"-be (ha lenne)
    for n in sorted(UTALVANY_CIMLETEK, reverse=True):
        if str(n) in s:
            return n
    return 0


def get_voucher_denomination(name, price, sku=""):
    """Cimlet azonositasa: 10000, 20000, 30000, 40000, 50000 Ft.
    Sorrend: SKU > nev > ar.
    """
    # 1. SKU minta (megbizhato)
    c = get_voucher_denomination_from_sku(sku)
    if c:
        return c

    # 2. Probaljuk a nevbol kinyerni (10.000 Ft, 20000Ft, stb.)
    if name:
        text = name.replace(".", "").replace(",", "").replace(" ", "")
        for n in UTALVANY_CIMLETEK:
            if str(n) in text:
                return n

    # 3. Ar alapjan
    try:
        p = float(price or 0)
        for n in UTALVANY_CIMLETEK:
            # +/- 5% tolerancia
            if abs(p - n) <= n * 0.05:
                return n
    except Exception:
        pass

    return 0  # ismeretlen


# ============================================================
# Shoprenter API
# ============================================================

def shop_get_orders_for_day(datum):
    base_url = SHOPRENTER_API_URL.rstrip("/")
    auth = (SHOPRENTER_API_USER, SHOPRENTER_API_PASSWORD)

    def get_page(page):
        for _ in range(3):
            try:
                r = requests.get(f"{base_url}/orders", auth=auth,
                                 headers={"Accept": "application/json"},
                                 params={"page": page, "limit": 25, "full": 1}, timeout=30)
                if r.status_code == 429:
                    time.sleep(10)
                    continue
                return r.json().get("items", [])
            except Exception:
                time.sleep(5)
        return []

    r0 = requests.get(f"{base_url}/orders", auth=auth,
                      headers={"Accept": "application/json"},
                      params={"page": 0, "limit": 25, "full": 1}, timeout=30)
    page_count = int(r0.json().get("pageCount", 1) or 1)

    lo, hi = 0, page_count - 1
    target = None
    while lo <= hi:
        mid = (lo + hi) // 2
        items = get_page(mid)
        if not items:
            break
        dates = [(o.get("dateCreated") or "")[:10] for o in items if o.get("dateCreated")]
        if not dates:
            break
        min_d, max_d = min(dates), max(dates)
        if max_d < datum:
            lo = mid + 1
        elif min_d > datum:
            hi = mid - 1
        else:
            target = mid
            break

    if target is None:
        return [], base_url, auth

    result = []
    for pg in range(max(0, target - 10), min(page_count, target + 11)):
        items = get_page(pg)
        for o in items:
            if (o.get("dateCreated") or "")[:10] != datum:
                continue
            st = o.get("orderStatus")
            status_href = st.get("href", "") if isinstance(st, dict) else ""
            status_id = get_status_id_from_href(status_href)
            if status_id is None or status_id in KIZART_STATUSZOK:
                continue
            result.append(o)
    return result, base_url, auth


def shop_get_order_products(order, auth):
    op_ref = order.get("orderProducts")
    if not isinstance(op_ref, dict) or not op_ref.get("href"):
        return []
    try:
        r = requests.get(op_ref["href"], auth=auth,
                         headers={"Accept": "application/json"},
                         params={"limit": 100, "full": 1}, timeout=30)
        if r.status_code != 200:
            return []
        return r.json().get("items", [])
    except Exception:
        return []


def shop_get_order_totals(order, auth):
    """orderTotals - itt latjuk a kedvezmenyeket / utalvany felhasznalast."""
    ot_ref = order.get("orderTotals")
    if not isinstance(ot_ref, dict) or not ot_ref.get("href"):
        return []
    try:
        r = requests.get(ot_ref["href"], auth=auth,
                         headers={"Accept": "application/json"},
                         params={"limit": 50}, timeout=30)
        if r.status_code != 200:
            return []
        return r.json().get("items", [])
    except Exception:
        return []


# ============================================================
# Foldolgozas
# ============================================================

def process_shop_day(con, datum, debug=False, dry_run=False):
    print(f"\n[Shoprenter utalvany] {datum}")
    orders, base_url, auth = shop_get_orders_for_day(datum)
    print(f"  {len(orders)} rendeles")

    # Akkumulalok
    eladasok = defaultdict(lambda: {"db": 0, "osszeg": 0.0})  # cimlet -> stats
    felhasznalasok = defaultdict(lambda: {"db": 0, "osszeg": 0.0, "pluszbol": 0.0})

    for o in orders:
        # 1) UTALVANY ELADASOK: orderProducts-bol
        op_items = shop_get_order_products(o, auth)
        for op in op_items:
            name = op.get("name", "")
            sku = op.get("sku", "")
            try:
                gross_per_unit = float(op.get("grossPrice", 0) or 0)
            except Exception:
                gross_per_unit = 0
            if not is_voucher_product(name, sku, gross_per_unit):
                continue
            try:
                p = float(op.get("price", 0) or 0)
                t = float(op.get("total", 0) or 0)
                qty = max(1, round(t / p)) if p > 0 else 1
            except Exception:
                qty = 1
            cimlet = get_voucher_denomination(name, gross_per_unit, sku)
            # Csak a kivant cimleteket (10/20/30/40/50k) tartjuk meg
            if cimlet not in UTALVANY_CIMLETEK:
                continue
            eladasok[cimlet]["db"] += qty
            eladasok[cimlet]["osszeg"] += gross_per_unit * qty

        # 2) UTALVANY FELHASZNALASOK: orderTotals-bol
        order_totals = shop_get_order_totals(o, auth)
        order_voucher_used = 0.0
        for ot in order_totals:
            code = (ot.get("code") or "").lower()
            title = (ot.get("title") or "").lower()
            value_raw = ot.get("value", "0") or "0"
            try:
                value = abs(float(value_raw))
            except Exception:
                value = 0
            # Utalvany-szeru kedvezmenyek azonositasa
            if any(kw in code for kw in ("voucher", "utalvany", "gift")) or \
               any(kw in title for kw in UTALVANY_KULCSSZAVAK):
                order_voucher_used += value

        if order_voucher_used > 0:
            # A felhasznalt utalvanyt egy cimletre rendezzuk (5% tolerancia)
            cimlet_id = 0
            for n in UTALVANY_CIMLETEK:
                if abs(order_voucher_used - n) <= n * 0.05:
                    cimlet_id = n
                    break
            # Csak akkor mentjuk, ha szabvanyos cimletre passzol
            if cimlet_id not in UTALVANY_CIMLETEK:
                continue

            try:
                order_total = float(o.get("total", 0) or 0)
            except Exception:
                order_total = 0
            extra_spend = max(0, order_total - order_voucher_used) if order_total > 0 else 0

            felhasznalasok[cimlet_id]["db"] += 1
            felhasznalasok[cimlet_id]["osszeg"] += order_voucher_used
            felhasznalasok[cimlet_id]["pluszbol"] += extra_spend

    # Osszesito kiiratasa
    if eladasok:
        print(f"  ELADAS:")
        for c, v in sorted(eladasok.items()):
            print(f"    {c} Ft: {v['db']} db | {v['osszeg']:,.0f} Ft")
    if felhasznalasok:
        print(f"  FELHASZNALAS:")
        for c, v in sorted(felhasznalasok.items()):
            print(f"    {c} Ft: {v['db']} db | felhasznalva {v['osszeg']:,.0f} Ft | pluszbol koltott {v['pluszbol']:,.0f} Ft")

    if not dry_run:
        delete_day_utalvany(con, datum)
        for c, v in eladasok.items():
            save_utalvany(con, datum, "vasarlas", c, v["db"], v["osszeg"], 0)
        for c, v in felhasznalasok.items():
            save_utalvany(con, datum, "felhasznalas", c, v["db"], v["osszeg"], v["pluszbol"])
        con.commit()
        print(f"  [OK] DB-be mentve")
    return True


# ============================================================
# Utalvany FELHASZNALAS backfill /orders + orderTotals-on at
# ============================================================

def backfill_redemptions_via_orders(con, from_date, to_date=None):
    """Felhasznalt utalvanyok keresese a /orders endpoint vegigjarasaval.

    Strategia:
    - /orders oldalakon visszafele, friss rendelesektol kezdve
    - Csak ahol couponTaxRate != -1 (kupon hasznalva volt)
    - Lekerjuk az orderTotals-t
    - Keressuk type='COUPON' + name tartalmaz 'utalvany' soat
    - abs(value) a felhasznalt utalvany cimlete
    """
    base = SHOPRENTER_API_URL.rstrip("/")
    auth = (SHOPRENTER_API_USER, SHOPRENTER_API_PASSWORD)

    print(f"\n[BACKFILL] Utalvany felhasznalasok keresese /orders + orderTotals-bol")
    print(f"  Idoszak: {from_date} -> {to_date or 'ma'}")

    def get_page(p):
        for _ in range(3):
            try:
                r = requests.get(f"{base}/orders", auth=auth,
                                 headers={"Accept": "application/json"},
                                 params={"limit": 25, "page": p, "full": 1}, timeout=30)
                if r.status_code == 429:
                    time.sleep(10); continue
                if r.status_code != 200:
                    return None
                return r.json()
            except Exception:
                time.sleep(5)
        return None

    info = get_page(0)
    total_pages = info.get("pageCount", 0) if info else 0
    print(f"  Osszesen {total_pages} oldal van az /orders-en")
    if total_pages == 0:
        return

    daily_used = defaultdict(lambda: defaultdict(lambda: {"db": 0, "osszeg": 0.0, "pluszbol": 0.0}))

    pages_processed = 0
    orders_with_coupon = 0
    vouchers_used = 0
    stop_flag = False

    for page in range(total_pages - 1, -1, -1):
        items = (get_page(page) or {}).get("items", [])
        if not items:
            continue
        pages_processed += 1

        oldest_in_page = None
        for o in items:
            d_full = o.get("dateCreated") or ""
            d = d_full[:10]
            if oldest_in_page is None or d < oldest_in_page:
                oldest_in_page = d
            if d < from_date:
                continue
            if to_date and d > to_date:
                continue

            # Csak akkor probaljuk lekerni az orderTotals-t, ha couponTaxRate != -1
            ctax = str(o.get("couponTaxRate", "-1"))
            if ctax in ("-1", "-1.0000"):
                continue

            # Statusz szures (kizart -> visszavont/torolt rendelesek)
            st = o.get("orderStatus")
            status_href = st.get("href", "") if isinstance(st, dict) else ""
            status_id = get_status_id_from_href(status_href)
            if status_id is not None and status_id in KIZART_STATUSZOK:
                continue

            orders_with_coupon += 1

            # orderTotals lekerese - rate-limit-tudo retry (kulonben napi 20+ rendelest
            # silently bukunk; lasd 2026-06-03-i debug)
            ot_ref = o.get("orderTotals")
            ot_href = ot_ref.get("href") if isinstance(ot_ref, dict) else None
            if not ot_href:
                continue
            ot_items = None
            for attempt in range(6):
                try:
                    r = requests.get(ot_href, auth=auth,
                                     headers={"Accept": "application/json"},
                                     params={"limit": 50, "full": 1}, timeout=30)
                    if r.status_code == 429:
                        time.sleep(5 + attempt * 3)
                        continue
                    if r.status_code != 200:
                        time.sleep(2)
                        continue
                    ot_items = r.json().get("items", [])
                    break
                except Exception:
                    time.sleep(2 + attempt)
            if ot_items is None:
                continue

            # Keresunk COUPON tipust amineve tartalmaz 'utalvany'-t
            voucher_value = 0.0
            for it in ot_items:
                t = (it.get("type") or "").upper()
                name = (it.get("name") or "").lower()
                try:
                    val = float(it.get("value", 0) or 0)
                except Exception:
                    val = 0
                if t == "COUPON" and ("utalvány" in name or "utalvany" in name):
                    voucher_value += abs(val)

            if voucher_value <= 0:
                continue

            # Cimlet osztalyozas
            cimlet = 0
            for n in UTALVANY_CIMLETEK:
                if abs(voucher_value - n) <= n * 0.05:
                    cimlet = n
                    break
            if cimlet not in UTALVANY_CIMLETEK:
                # Lehet osszevont (pl. 2x20k = 40k = szabvanyos), vagy reszben (pl. 5k = nem szabvanyos)
                continue

            # Plusz koltes: a teljes kifizetett osszeg (order.total) - amit az ugyfel ténylegesen fizetett
            # az utalvany levonasa utan (beleertve a szallitast is)
            try:
                order_total = float(o.get("total", 0) or 0)
            except Exception:
                order_total = 0
            extra = max(0, order_total)

            daily_used[d][cimlet]["db"] += 1
            daily_used[d][cimlet]["osszeg"] += voucher_value
            daily_used[d][cimlet]["pluszbol"] += extra
            vouchers_used += 1

        if oldest_in_page and oldest_in_page < from_date:
            print(f"  [STOP] Oldal {page}: legregebbi datum = {oldest_in_page} < {from_date}")
            stop_flag = True
            break

        if pages_processed % 20 == 0:
            print(f"  ... {pages_processed} oldal | {orders_with_coupon} kupon-jelolt rendeles | {vouchers_used} utalvany-felhasznalas | epp: {oldest_in_page}")

    print(f"\n[OK] Feldolgozas vege")
    print(f"  Oldalak: {pages_processed} | Kupon-jelolt rendelesek: {orders_with_coupon} | Felhasznalas: {vouchers_used}")
    print(f"  Egyedi napok utalvany-felhasznalassal: {len(daily_used)}")

    # DB-be mentes - csak felhasznalasokat (vasarlasokat nem irjuk felul)
    print(f"  DB-be irjuk...")
    if to_date:
        con.execute("DELETE FROM napi_utalvany WHERE datum >= ? AND datum <= ? AND tipus='felhasznalas'", (from_date, to_date))
    else:
        con.execute("DELETE FROM napi_utalvany WHERE datum >= ? AND tipus='felhasznalas'", (from_date,))
    for d, cimletek in daily_used.items():
        for c, stats in cimletek.items():
            save_utalvany(con, d, "felhasznalas", c, stats["db"], stats["osszeg"], stats["pluszbol"])
    con.commit()
    print(f"  [OK] Mentve")


# ============================================================
# Hatekony backfill /orderProducts-en at
# ============================================================

def backfill_via_orderproducts(con, from_date, to_date=None):
    """Hatekonyabb backfill: a /orderProducts endpoint paginalt vegigjarasaval.

    A Shoprenter /orderProducts elek a teljes tetel-tortenetet adjak, datum szerint
    rendezett oldalakban (oldal 0 = legregebbi). Visszafele megyunk az utolso oldaltol,
    es amint datum < from_date, megallunk. Kliensoldalon szurunk SKU pattern alapjan.
    """
    base = SHOPRENTER_API_URL.rstrip("/")
    auth = (SHOPRENTER_API_USER, SHOPRENTER_API_PASSWORD)

    print(f"\n[BACKFILL] /orderProducts alapu utalvany-keresés")
    print(f"  Idoszak: {from_date} -> {to_date or 'ma'}")

    def get_page(p):
        for _ in range(3):
            try:
                r = requests.get(f"{base}/orderProducts", auth=auth,
                                 headers={"Accept": "application/json"},
                                 params={"limit": 50, "page": p, "full": 1}, timeout=30)
                if r.status_code == 429:
                    time.sleep(10); continue
                if r.status_code != 200:
                    return None
                return r.json()
            except Exception:
                time.sleep(5)
        return None

    # Total page count lekerdezese
    info = get_page(0)
    total_pages = info.get("pageCount", 0) if info else 0
    print(f"  Osszesen {total_pages} oldal van az /orderProducts-en")

    if total_pages == 0:
        print(f"  [!] Nem kaptam pageCount-ot, kilepunk")
        return

    # Akkumulalo: napi cimletenkenti aggregalas
    daily_vouchers = defaultdict(lambda: defaultdict(lambda: {"db": 0, "osszeg": 0.0}))

    # Rendeles-statusz cache (order_href -> status_id)
    order_status_cache = {}

    def get_order_status(order_href):
        if order_href in order_status_cache:
            return order_status_cache[order_href]
        # Robusztus retry + rate-limit kezeles
        for attempt in range(5):
            try:
                r = requests.get(order_href, auth=auth,
                                 headers={"Accept": "application/json"}, timeout=20)
                if r.status_code == 429:
                    time.sleep(5 + attempt * 2)
                    continue
                if r.status_code != 200:
                    time.sleep(1)
                    continue
                o = r.json()
                st = o.get("orderStatus")
                sh = st.get("href", "") if isinstance(st, dict) else ""
                sid = get_status_id_from_href(sh)
                order_status_cache[order_href] = sid
                return sid
            except Exception:
                time.sleep(2 + attempt)
        # 5 sikertelen kiserlet utan - ne cache-eljuk, hogy kesobb meg lehessen probalni
        return None

    # Visszafele iteralunk az utolso oldaltol
    pages_processed = 0
    items_total = 0
    voucher_items = 0
    skipped_status = 0
    stop_flag = False

    for page in range(total_pages - 1, -1, -1):
        items = (get_page(page) or {}).get("items", [])
        if not items:
            continue
        pages_processed += 1
        items_total += len(items)

        # Ezen az oldalon vannak elemek - vegigmegyunk rajtuk
        # Az oldalon belul a sorrend nem mindig garantalt, ezert egesz oldalt vegigjarunk
        oldest_in_page = None
        for it in items:
            d_full = it.get("dateCreated") or ""
            d = d_full[:10]
            if oldest_in_page is None or d < oldest_in_page:
                oldest_in_page = d
            # Tartomany szures
            if d < from_date:
                continue
            if to_date and d > to_date:
                continue

            # Utalvany-e?
            name = it.get("name", "") or ""
            sku = it.get("sku", "") or ""
            try:
                gross = float(it.get("grossPrice", 0) or 0)
            except Exception:
                gross = 0

            if not is_voucher_product(name, sku, gross):
                continue
            cimlet = get_voucher_denomination(name, gross, sku)
            if cimlet not in UTALVANY_CIMLETEK:
                continue

            # Statusz ellenorzes: CSAK az "Utalvany kesz (szamlazva)" allapotu rendeleseket szamoljuk.
            # A kollegak ezt allitjak, amikor minden rendben volt az utalvany eladasaval.
            order_ref = it.get("order")
            order_href = order_ref.get("href") if isinstance(order_ref, dict) else None
            if order_href:
                sid = get_order_status(order_href)
                if sid not in VOUCHER_PURCHASE_VALID_STATUSES:
                    skipped_status += 1
                    continue
            else:
                # Nincs order href - kihagyjuk a biztonsag kedveert
                skipped_status += 1
                continue

            # Quantity szamitas
            try:
                p_net = float(it.get("price", 0) or 0)
                t_net = float(it.get("total", 0) or 0)
                qty = max(1, round(t_net / p_net)) if p_net > 0 else 1
            except Exception:
                qty = 1

            daily_vouchers[d][cimlet]["db"] += qty
            daily_vouchers[d][cimlet]["osszeg"] += gross * qty
            voucher_items += qty

        # Stop-feltetel: ha az oldal legregebbi eleme korabbi mint from_date
        if oldest_in_page and oldest_in_page < from_date:
            print(f"  [STOP] Oldal {page}: legregebbi datum = {oldest_in_page} < {from_date}")
            stop_flag = True
            break

        if pages_processed % 20 == 0:
            print(f"  ... {pages_processed} oldal | {items_total} item | {voucher_items} utalvany | epp: {oldest_in_page}")

    print(f"\n[OK] Feldolgozas vege")
    print(f"  Oldalak: {pages_processed} | Tetelek: {items_total} | Utalvanyok: {voucher_items} (jo)")
    print(f"  Sikertelen/kizart statusz miatt kihagyva: {skipped_status} tetel")
    print(f"  Egyedi napok utalvannyal: {len(daily_vouchers)}")
    print(f"  Stop oldalon: {'igen' if stop_flag else 'nem (vegigert)'}")

    # DB-be mentes - elozetes torlessel
    print(f"\n  DB-be irjuk...")
    if to_date:
        con.execute("DELETE FROM napi_utalvany WHERE datum >= ? AND datum <= ? AND tipus='vasarlas'", (from_date, to_date))
    else:
        con.execute("DELETE FROM napi_utalvany WHERE datum >= ? AND tipus='vasarlas'", (from_date,))
    for d, cimletek in daily_vouchers.items():
        for c, stats in cimletek.items():
            save_utalvany(con, d, "vasarlas", c, stats["db"], stats["osszeg"], 0)
    con.commit()
    print(f"  [OK] Mentve: {sum(len(v) for v in daily_vouchers.values())} sor")


# ============================================================
# Reszletes debug fajl-output
# ============================================================

def write_debug_file(datum):
    lines = []
    lines.append(f"=" * 70)
    lines.append(f"UTALVANY DEBUG - Shoprenter - {datum}")
    lines.append(f"Idopont: {datetime.now().isoformat(timespec='seconds')}")
    lines.append(f"=" * 70)

    try:
        orders, base_url, auth = shop_get_orders_for_day(datum)
        lines.append(f"\nRendeles: {len(orders)}")

        # Vegigjarjuk az osszes rendelest, gyujtjuk a kulcsfontossagu adatokat
        all_product_names = []
        all_total_codes = set()
        all_total_titles = set()
        all_total_samples = []
        voucher_products_found = []
        voucher_totals_found = []

        for i, o in enumerate(orders):
            order_inner_id = o.get("innerId", "?")
            order_total = o.get("total", "0")

            # orderProducts: termekek
            op_items = shop_get_order_products(o, auth)
            for op in op_items:
                name = op.get("name", "")
                sku = op.get("sku", "")
                price = op.get("price", "0")
                gross = op.get("grossPrice", "0")
                all_product_names.append((name, sku, gross))
                if is_voucher_product(name, sku, gross):
                    cimlet = get_voucher_denomination(name, gross)
                    voucher_products_found.append({
                        "rendeles_id": order_inner_id,
                        "termek_nev": name,
                        "sku": sku,
                        "ar_brutto": gross,
                        "becsult_cimlet": cimlet,
                        "szabvanyos": "IGEN" if cimlet in UTALVANY_CIMLETEK else "NEM",
                    })

            # orderTotals: kedvezmenyek
            order_totals = shop_get_order_totals(o, auth)
            for ot in order_totals:
                code = ot.get("code", "")
                title = ot.get("title", "")
                value = ot.get("value", "0")
                all_total_codes.add(code)
                all_total_titles.add(title)
                if i < 3:  # csak az elso 3 rendeles teljes orderTotals-at mentjuk
                    all_total_samples.append({
                        "rendeles_id": order_inner_id,
                        "code": code, "title": title, "value": value
                    })
                # Utalvany-szeru?
                lo_code = (code or "").lower()
                lo_title = (title or "").lower()
                if any(kw in lo_code for kw in ("voucher", "utalvany", "gift")) or \
                   any(kw in lo_title for kw in UTALVANY_KULCSSZAVAK):
                    voucher_totals_found.append({
                        "rendeles_id": order_inner_id,
                        "rendeles_total": order_total,
                        "code": code, "title": title, "value": value
                    })

        # ============= Iratas =============
        lines.append(f"\n\n----- TALALT TERMEKEK ({len(all_product_names)} db) -----")
        for n, sku, gross in all_product_names[:40]:
            mark = " <-- UTALVANY?" if is_voucher_product(n, sku, gross) else ""
            lines.append(f"  {n[:70]} | SKU={sku} | {gross} Ft{mark}")
        if len(all_product_names) > 40:
            lines.append(f"  ... {len(all_product_names)-40} tobbi termek")

        lines.append(f"\n\n----- TALALT UTALVANY ELADASOK ({len(voucher_products_found)} db) -----")
        if not voucher_products_found:
            lines.append("  (nincs - vagy nincs ezen a napon, vagy a felismeresi minta nem talal)")
        for v in voucher_products_found:
            lines.append(f"  Rend.{v['rendeles_id']}: {v['termek_nev']} | SKU={v['sku']} | {v['ar_brutto']} Ft | becsult cimlet: {v['becsult_cimlet']} | szabvanyos: {v['szabvanyos']}")

        lines.append(f"\n\n----- orderTotals EGYEDI 'code' MEZOK ({len(all_total_codes)} db) -----")
        for c in sorted(all_total_codes):
            lines.append(f"  '{c}'")

        lines.append(f"\n\n----- orderTotals EGYEDI 'title' MEZOK ({len(all_total_titles)} db) -----")
        for t in sorted(all_total_titles):
            lines.append(f"  '{t}'")

        lines.append(f"\n\n----- ELSO 3 RENDELES TELJES orderTotals BONTASA -----")
        if all_total_samples:
            current_order = None
            for s in all_total_samples:
                if s["rendeles_id"] != current_order:
                    current_order = s["rendeles_id"]
                    lines.append(f"\n  Rendeles {current_order}:")
                lines.append(f"    code='{s['code']}' | title='{s['title']}' | value={s['value']}")

        lines.append(f"\n\n----- TALALT UTALVANY FELHASZNALASOK ({len(voucher_totals_found)} db) -----")
        if not voucher_totals_found:
            lines.append("  (nincs - vagy nincs ezen a napon, vagy a felismeresi minta nem talal)")
        for v in voucher_totals_found:
            lines.append(f"  Rend.{v['rendeles_id']}: code={v['code']} | title={v['title']} | felhasznalva {v['value']} | rendeles totalja {v['rendeles_total']}")

    except Exception as e:
        lines.append(f"\n[!!] HIBA: {e}")
        import traceback
        lines.append(traceback.format_exc())

    content = "\n".join(lines)
    with open(DEBUG_FILE, "w", encoding="utf-8") as f:
        f.write(content)
    print(f"\n[OK] Debug kimenet: {DEBUG_FILE} ({len(content)/1024:.1f} KB)")


# ============================================================
# Foprogram
# ============================================================

def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--debug", action="store_true", help="Reszletes debug fajl + nincs DB iras")
    ap.add_argument("--napi", help="Egy nap yyyy-mm-dd formatumban")
    ap.add_argument("--backfill", type=int, help="Utolso N nap (nap-szeru iteracio)")
    ap.add_argument("--from-date", help="Honnan kezdve fusson a backfill (nap-szeru iteracio)")
    ap.add_argument("--quick-backfill", help="GYORS backfill /orderProducts paginacioval (yyyy-mm-dd-tol)")
    args = ap.parse_args()

    con = init_db()

    if args.quick_backfill:
        backfill_via_orderproducts(con, args.quick_backfill)
        backfill_redemptions_via_orders(con, args.quick_backfill)
        con.close()
        print("\n[OK] Kesz")
        return

    if args.debug and not (args.napi or args.backfill or args.from_date):
        d = (datetime.today() - timedelta(days=1)).strftime("%Y-%m-%d")
        print(f"=== DEBUG mod: {d} ===")
        write_debug_file(d)
    elif args.napi:
        process_shop_day(con, args.napi, dry_run=args.debug)
    elif args.from_date:
        start = datetime.strptime(args.from_date, "%Y-%m-%d").date()
        end = datetime.today().date() - timedelta(days=1)
        n_days = (end - start).days + 1
        if n_days <= 0:
            print(f"!!! Hibás dátumtartomány: {args.from_date} -> {end}")
            con.close()
            return
        print(f"=== Backfill: {args.from_date} -> {end} ({n_days} nap) ===")
        for i in range(n_days):
            d = (start + timedelta(days=i)).strftime("%Y-%m-%d")
            print(f"\n--- {i+1}/{n_days}: {d} ---")
            try:
                process_shop_day(con, d, dry_run=args.debug)
            except Exception as e:
                print(f"  [!!] {d}: {e}")
    elif args.backfill:
        n = args.backfill
        print(f"=== Backfill: utolso {n} nap ===")
        for i in range(1, n + 1):
            d = (datetime.today() - timedelta(days=i)).strftime("%Y-%m-%d")
            print(f"\n--- {i}/{n}: {d} ---")
            try:
                process_shop_day(con, d, dry_run=args.debug)
            except Exception as e:
                print(f"  [!!] {d}: {e}")
    else:
        ap.print_help()

    con.close()
    print("\n[OK] Kesz")


if __name__ == "__main__":
    main()
