"""
backfill_entry_id.py | v1.0 | 2026-06-08
Dohledá entry_id pro záznamy v jnjemails.db které ho nemají (69k starých emailů
přenesených skriptem v1.1). Prochází celý Outlook MAPI strom a páruje emaily
dle Internet Message-ID.

Spouštět na JNJ PC s běžícím Outlookem.
Bezpečné opakovat — přeskočí záznamy které už entry_id mají.
"""

import sqlite3
import win32com.client
from datetime import datetime

DB_PATH = r"C:\Users\vbuzalka\SQLITE\jnjemails.db"
PR_INTERNET_MESSAGE_ID = "http://schemas.microsoft.com/mapi/proptag/0x1035001E"


def load_missing(conn) -> dict:
    """Vrátí dict {message_id: db_id} pro záznamy bez entry_id."""
    rows = conn.execute(
        "SELECT id, message_id FROM messages WHERE entry_id IS NULL"
    ).fetchall()
    return {r[1]: r[0] for r in rows}


def update_entry_id(conn, db_id: int, entry_id: str):
    conn.execute(
        "UPDATE messages SET entry_id = ? WHERE id = ?",
        (entry_id, db_id)
    )


def scan_folder(conn, folder, lookup: dict, stats: dict, path: str = ""):
    current = f"{path}/{folder.Name}"
    try:
        items = folder.Items
        for item in items:
            try:
                if not item.MessageClass.upper().startswith("IPM.NOTE"):
                    continue

                stats["checked"] += 1

                try:
                    mid = item.PropertyAccessor.GetProperty(PR_INTERNET_MESSAGE_ID)
                except Exception:
                    mid = None
                if not mid:
                    mid = f"entryid:{item.EntryID}"

                if mid in lookup:
                    db_id = lookup.pop(mid)
                    update_entry_id(conn, db_id, item.EntryID)
                    stats["updated"] += 1
                    if stats["updated"] % 100 == 0:
                        conn.commit()
                        print(f"  [{datetime.now().strftime('%H:%M:%S')}] "
                              f"aktualizováno {stats['updated']} | "
                              f"zbývá {len(lookup)} | složka: {current}")

            except Exception as e:
                stats["errors"] += 1

    except Exception as e:
        print(f"  CHYBA složka {current}: {e}")
        stats["errors"] += 1
        return  # nelze ani procházet podsložky

    try:
        subfolders = list(folder.Folders)
    except Exception as e:
        print(f"  CHYBA podsložky {current}: {e}")
        return

    for subfolder in subfolders:
        if not lookup:
            return
        scan_folder(conn, subfolder, lookup, stats, current)


def main():
    print(f"=== backfill_entry_id v1.0 ===")
    print(f"Start: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")

    conn = sqlite3.connect(DB_PATH)
    lookup = load_missing(conn)
    total_missing = len(lookup)
    print(f"Záznamy bez entry_id: {total_missing}")

    if not lookup:
        print("Nic k doplnění.")
        conn.close()
        return

    outlook = win32com.client.Dispatch("Outlook.Application")
    ns = outlook.GetNamespace("MAPI")

    stats = {"checked": 0, "updated": 0, "errors": 0}

    for i in range(1, ns.Folders.Count + 1):
        if not lookup:
            break
        root = ns.Folders.Item(i)
        print(f"\nSložka: {root.Name}")
        scan_folder(conn, root, lookup, stats, "")

    conn.commit()
    conn.close()

    print(f"\n=== Hotovo ===")
    print(f"Zkontrolováno emailů: {stats['checked']}")
    print(f"Doplněno entry_id:    {stats['updated']} / {total_missing}")
    print(f"Nenalezeno:           {len(lookup)}")
    print(f"Chyby:                {stats['errors']}")
    print(f"Konec: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")


if __name__ == "__main__":
    main()
