#!/usr/bin/env python3
"""Submit Wan 2.2 Two-Pass I2V workflow - Higher Quality"""

import json
import urllib.request
import urllib.error
import uuid

COMFY_URL = "http://localhost:8188"
INPUT_IMAGE = "pool_party.png"

PROMPT = """Static camera shot. Two men stand beside a swimming pool at sunset. The larger man on the left reaches over and slowly lifts the white shirt off the smaller man, pulling it up and over his head. He then playfully tickles the smaller man's nipples with his middle fingers, teasing and laughing together. The covered patio and green lawn remain visible in the background. The camera remains perfectly still throughout. No zooming, no panning, no camera movement."""

NEGATIVE = "色调艳丽，过曝，静态，细节模糊不清，字幕，风格，作品，画作，画面，静止，整体发灰，最差质量，低质量，JPEG压缩残留，丑陋的，残缺的，多余的手指，画得不好的手部，画得不好的脸部，畸形的，毁容的，形态畸形的肢体，手指融合，静止不动的画面，杂乱的背景，三条腿，背景人很多，倒着走"

workflow = {
    "1": {
        "class_type": "LoadImage",
        "inputs": {"image": INPUT_IMAGE, "upload": "image"}
    },
    "2": {
        "class_type": "ImageResizeKJv2",
        "inputs": {
            "image": ["1", 0],
            "width": 848,
            "height": 480,
            "upscale_method": "lanczos",
            "keep_proportion": "crop",
            "pad_color": "0, 0, 0",
            "crop_position": "center",
            "divisible_by": 32
        }
    },
    "8": {
        "class_type": "WanVideoBlockSwap",
        "inputs": {"blocks_to_swap": 20, "offload_img_emb": False, "offload_txt_emb": False}
    },
    "3": {
        "class_type": "WanVideoModelLoader",
        "inputs": {
            "model": "WanVideo/2_2/Wan2_2-I2V-A14B-HIGH_fp8_e4m3fn_scaled_KJ.safetensors",
            "base_precision": "fp16_fast",
            "quantization": "fp8_e4m3fn_scaled",
            "load_device": "offload_device",
            "attention_mode": "sdpa",
            "block_swap_args": ["8", 0]
        }
    },
    "4": {
        "class_type": "WanVideoModelLoader",
        "inputs": {
            "model": "WanVideo/2_2/Wan2_2-I2V-A14B-LOW_fp8_e4m3fn_scaled_KJ.safetensors",
            "base_precision": "fp16_fast",
            "quantization": "fp8_e4m3fn_scaled",
            "load_device": "offload_device",
            "attention_mode": "sdpa",
            "block_swap_args": ["8", 0]
        }
    },
    "5": {
        "class_type": "WanVideoVAELoader",
        "inputs": {"model_name": "wanvideo/Wan2_1_VAE_bf16.safetensors", "precision": "bf16"}
    },
    "6": {
        "class_type": "LoadWanVideoT5TextEncoder",
        "inputs": {
            "model_name": "umt5-xxl-enc-fp8_e4m3fn.safetensors",
            "precision": "bf16",
            "load_device": "offload_device",
            "quantization": "fp8_e4m3fn"
        }
    },
    "7": {
        "class_type": "WanVideoTextEncode",
        "inputs": {
            "positive_prompt": PROMPT,
            "negative_prompt": NEGATIVE,
            "t5": ["6", 0],
            "force_offload": True,
            "use_disk_cache": False
        }
    },
    "9": {
        "class_type": "WanVideoImageToVideoEncode",
        "inputs": {
            "width": ["2", 1],
            "height": ["2", 2],
            "num_frames": 81,
            "noise_aug_strength": 0,
            "start_latent_strength": 1,
            "end_latent_strength": 1,
            "force_offload": True,
            "vae": ["5", 0],
            "start_image": ["2", 0]
        }
    },
    "10": {
        "class_type": "WanVideoSampler",
        "inputs": {
            "model": ["3", 0],
            "image_embeds": ["9", 0],
            "steps": 10,
            "cfg": 1.5,
            "shift": 8,
            "seed": 42,
            "force_offload": True,
            "scheduler": "dpm++_sde",
            "riflex_freq_index": 0,
            "text_embeds": ["7", 0],
            "end_step": 5
        }
    },
    "11": {
        "class_type": "WanVideoSampler",
        "inputs": {
            "model": ["4", 0],
            "image_embeds": ["9", 0],
            "steps": 10,
            "cfg": 1.0,
            "shift": 8,
            "seed": 42,
            "force_offload": True,
            "scheduler": "dpm++_sde",
            "riflex_freq_index": 0,
            "text_embeds": ["7", 0],
            "samples": ["10", 0],
            "start_step": 5
        }
    },
    "12": {
        "class_type": "WanVideoDecode",
        "inputs": {
            "vae": ["5", 0],
            "samples": ["11", 0],
            "enable_vae_tiling": False,
            "enable_tiling": False,
            "tile_x": 272,
            "tile_y": 272,
            "tile_stride_x": 144,
            "tile_stride_y": 128
        }
    },
    "13": {
        "class_type": "VHS_VideoCombine",
        "inputs": {
            "images": ["12", 0],
            "frame_rate": 16,
            "loop_count": 0,
            "filename_prefix": "Wan22_PoolParty",
            "format": "video/h264-mp4",
            "pix_fmt": "yuv420p",
            "crf": 17,
            "save_metadata": True,
            "trim_to_audio": False,
            "pingpong": False,
            "save_output": True
        }
    }
}

def submit_prompt(workflow):
    prompt_id = str(uuid.uuid4())
    data = {"prompt": workflow, "client_id": "selena-agent"}
    req = urllib.request.Request(
        f"{COMFY_URL}/prompt",
        data=json.dumps(data).encode('utf-8'),
        headers={'Content-Type': 'application/json'}
    )
    try:
        with urllib.request.urlopen(req) as response:
            result = json.loads(response.read().decode('utf-8'))
            print(f"✅ Submitted! ID: {result.get('prompt_id', prompt_id)}")
            return result.get('prompt_id')
    except urllib.error.HTTPError as e:
        print(f"❌ Error {e.code}: {e.read().decode('utf-8')[:500]}")
        return None

if __name__ == "__main__":
    print("🎬 Wan 2.2 Two-Pass (10 steps, crf 17)...")
    submit_prompt(workflow)
