import os
import blake3
import sys
import json
from tqdm import tqdm

# ==============================
# ⚙️ NASTAVENÍ
# ==============================
LOCAL_ROOT = r"U:\#Syncthing"
CACHE_FILE = "local_hashes.jsonl"
ERROR_LOG = "errors_scan.txt"


def calculate_blake3_hex(file_path):
    h = blake3.blake3()
    # Zde ošetříme chyby při otevírání/čtení souboru
    try:
        with open(file_path, "rb") as f:
            while True:
                chunk = f.read(4 * 1024 * 1024)
                if not chunk: break
                h.update(chunk)
        return h.hexdigest()
    except Exception as e:
        # Vyhodíme výjimku nahoru, abychom ji zachytili v hlavní smyčce i s názvem souboru
        raise e


def count_files(path):
    print("⏳ Sčítám soubory...", end="\r")
    total = 0
    for root, dirs, files in os.walk(path):
        if ".stfolder" in dirs: dirs.remove(".stfolder")
        if ".stversions" in dirs: dirs.remove(".stversions")
        total += len(files)
    print(f"✅ Celkem souborů: {total:,}")
    return total


def load_processed_files(cache_file):
    """Načte cesty souborů, které už máme hotové"""
    processed = set()
    if os.path.exists(cache_file):
        print("📥 Načítám již hotové záznamy pro navázání...")
        try:
            with open(cache_file, "r", encoding="utf-8") as f:
                for line in f:
                    line = line.strip()
                    if not line: continue
                    try:
                        data = json.loads(line)
                        processed.add(data["p"])  # "p" je cesta
                    except:
                        continue
        except Exception as e:
            print(f"⚠️ Chyba při čtení cache (nevadí, jedeme dál): {e}")

    print(f"⏭  Přeskočím {len(processed):,} již hotových souborů.")
    return processed


def main():
    print("🚀 KROK 1: Generování cache (RESUMABLE + SAFE MODE)")
    print(f"📂 Zdroj: {LOCAL_ROOT}")
    print(f"💾 Výstup: {CACHE_FILE}")
    print("===================================")

    # 1. Zjistit celkový počet
    total_files = count_files(LOCAL_ROOT)

    # 2. Zjistit, co už máme hotové
    processed_paths = load_processed_files(CACHE_FILE)

    errors = 0
    newly_processed = 0

    # Otevřeme v režimu 'a' (APPEND) - připisování na konec
    with open(CACHE_FILE, "a", encoding="utf-8") as f_out:

        with tqdm(total=total_files, unit="file", dynamic_ncols=True) as pbar:

            # Pokud už máme nějaká data, aktualizujeme progress bar
            if processed_paths:
                pbar.update(len(processed_paths))

            for root, dirs, files in os.walk(LOCAL_ROOT):
                if ".stfolder" in dirs: dirs.remove(".stfolder")
                if ".stversions" in dirs: dirs.remove(".stversions")

                for filename in files:
                    file_path = os.path.join(root, filename)

                    # === SKIPPER: Pokud už to máme, jdeme dál ===
                    if file_path in processed_paths:
                        continue
                    # ============================================

                    # Pro dlouhé názvy ořízneme text v progress baru
                    short_name = (filename[:30] + '...') if len(filename) > 30 else filename
                    pbar.set_description(f"Hash: {short_name}")

                    # === SAFE BLOCK: Try-Except uvnitř smyčky ===
                    try:
                        hex_hash = calculate_blake3_hex(file_path)

                        if hex_hash:
                            record = {"h": hex_hash, "p": file_path}
                            f_out.write(json.dumps(record, ensure_ascii=False) + "\n")
                            # Flush, aby se to zapsalo na disk hned (pro jistotu)
                            if newly_processed % 100 == 0:
                                f_out.flush()
                            newly_processed += 1

                    except Exception as e:
                        errors += 1
                        error_msg = f"❌ CHYBA: {filename} -> {e}\n"
                        # Zapíšeme chybu do logu, aby to nerušilo output
                        with open(ERROR_LOG, "a", encoding="utf-8") as ferr:
                            ferr.write(error_msg)

                    # Posuneme progress bar
                    pbar.update(1)

    print("\n\n✅ HOTOVO.")
    print(f"📄 Nově přidáno: {newly_processed}")
    print(f"⏭  Přeskočeno:   {len(processed_paths)}")

    if errors > 0:
        print(f"⚠️ Počet chyb: {errors} (Detaily viz soubor '{ERROR_LOG}')")


if __name__ == "__main__":
    main()