#!/usr/bin/env python3
"""
BC-250: Test each ComfyUI component in isolation to find which one hangs.
Run from /home/fabian/ComfyUI with venv active.
"""
import os, sys, time, signal

os.environ["HSA_OVERRIDE_GFX_VERSION"] = "10.1.0"
os.environ["HSA_ENABLE_SDMA"] = "0"
os.environ["HIP_VISIBLE_DEVICES"] = "0"
os.environ["BC250_SOFTMAX_THRESHOLD"] = "512"

sys.path.insert(0, "/home/fabian/ComfyUI")

# Timeout handler
def timeout_handler(signum, frame):
    print(f"\n[TIMEOUT] Operation exceeded time limit!", flush=True)
    os._exit(1)

print("[T] Importing patch...", flush=True)
import bc250_softmax_patch

print("[T] Importing comfy...", flush=True)
t0 = time.time()
import torch
import comfy.sd
import comfy.model_management
import comfy.utils
import comfy.clip_model
import folder_paths
print(f"[T] Imports done in {time.time()-t0:.1f}s", flush=True)
print(f"[T] CUDA: {torch.cuda.is_available()}, Device: {torch.cuda.get_device_name(0)}", flush=True)

# === TEST 1: Load CLIP model ===
print(f"\n{'='*60}", flush=True)
print(f"[T] TEST 1: Load CLIP model (gemma2_2b_lumina2)", flush=True)
signal.alarm(60)  # 60s timeout
t1 = time.time()
try:
    clip_path = os.path.join(folder_paths.get_folder_paths("clip")[0], "gemma2_2b_lumina2.safetensors")
    if not os.path.exists(clip_path):
        # Try text_encoders folder
        for p in folder_paths.get_folder_paths("text_encoders"):
            cp = os.path.join(p, "gemma2_2b_lumina2.safetensors")
            if os.path.exists(cp):
                clip_path = cp
                break
    
    print(f"[T] CLIP path: {clip_path}", flush=True)
    print(f"[T] Loading CLIP...", flush=True)
    
    clip = comfy.sd.load_clip(
        ckpt_paths=[clip_path],
        embedding_directory=None,
        clip_type=comfy.sd.CLIPType.LUMINA2,
    )
    dt = time.time() - t1
    print(f"[T] CLIP loaded in {dt:.1f}s", flush=True)
    print(f"[T] CLIP type: {type(clip).__name__}", flush=True)
    
    # Check GPU memory after CLIP load
    print(f"[T] GPU VRAM after CLIP load:", flush=True)
    print(f"[T]   allocated: {torch.cuda.memory_allocated()/1e6:.1f} MB", flush=True)
    print(f"[T]   reserved: {torch.cuda.memory_reserved()/1e6:.1f} MB", flush=True)
    
except Exception as e:
    print(f"[T] TEST 1 ERROR: {e}", flush=True)
    import traceback
    traceback.print_exc()
    clip = None

signal.alarm(0)

# === TEST 2: Run CLIP text encoding ===
if clip is not None:
    print(f"\n{'='*60}", flush=True)
    print(f"[T] TEST 2: CLIP text encoding", flush=True)
    signal.alarm(120)  # 120s timeout
    t2 = time.time()
    try:
        print(f"[T] Encoding: 'a cat'...", flush=True)
        tokens = clip.tokenize({"g": "a cat"})
        print(f"[T] Tokenized in {time.time()-t2:.3f}s", flush=True)
        
        t2b = time.time()
        print(f"[T] Running CLIP encode (this is the suspected hang point)...", flush=True)
        output = clip.encode_from_tokens_scheduled(tokens)
        cond, pooled = output[:2]
        dt = time.time() - t2b
        print(f"[T] CLIP encoded in {dt:.1f}s", flush=True)
        print(f"[T] Cond shape: {cond.shape}, dtype: {cond.dtype}", flush=True)
        
    except Exception as e:
        print(f"[T] TEST 2 ERROR: {e}", flush=True)
        import traceback
        traceback.print_exc()
    signal.alarm(0)

# === TEST 3: Load GGUF UNet ===
print(f"\n{'='*60}", flush=True)
print(f"[T] TEST 3: Load GGUF UNet", flush=True)
signal.alarm(60)
t3 = time.time()
try:
    # Ensure GGUF patch is applied
    bc250_softmax_patch._try_patch_gguf()
    
    # Import GGUF nodes
    gguf_path = "/home/fabian/ComfyUI/custom_nodes/ComfyUI-GGUF"
    sys.path.insert(0, gguf_path)
    
    # Use the loader directly
    from loader import gguf_sd_loader
    from ops import GGMLOps
    
    unet_path = "/home/fabian/ComfyUI/models/unet/z_image_turbo-Q5_K_S.gguf"
    print(f"[T] Loading GGUF state dict...", flush=True)
    sd, extra = gguf_sd_loader(unet_path)
    print(f"[T] State dict: {len(sd)} keys, arch={extra.get('arch_str')}", flush=True)
    
    # Now load through comfy
    print(f"[T] Creating diffusion model...", flush=True)
    ops = GGMLOps()
    model = comfy.sd.load_diffusion_model_state_dict(
        sd, model_options={"custom_operations": ops},
        metadata=extra.get("metadata", {}),
    )
    dt = time.time() - t3
    print(f"[T] UNet loaded in {dt:.1f}s", flush=True)
    if model is not None:
        print(f"[T] Model type: {type(model).__name__}", flush=True)
    else:
        print(f"[T] WARNING: model is None!", flush=True)
    
except Exception as e:
    print(f"[T] TEST 3 ERROR: {e}", flush=True)
    import traceback
    traceback.print_exc()
signal.alarm(0)

print(f"\n{'='*60}", flush=True)
print(f"[T] ALL TESTS COMPLETE in {time.time()-t0:.1f}s", flush=True)
os._exit(0)
