import os
import sys
import time
import requests
import json
from typing import Dict, Any

sys.path.append(os.path.join(os.path.dirname(__file__), '../tools/local/liblibai_controlnet'))
from liblibai_client import LibLibAIClient

# 常量配置 (根据文档)
TEMPLATE_UUID = "e10adc3949ba59abbe56e057f20f883e"  # SD1.5 & SDXL 通用自定义参数模板

# 请确保这是一个有效的 SDXL 模型，这样才能匹配底下的 SDXL Canny 模型
# 这里用的是代码里原本的 Checkpoint ID，请根据你们自己的 Liblib 模型库调整！
DEFAULT_CHECKPOINT_ID = "0ea388c7eb854be3ba3c6f65aac6bfd3"

class LibLibTestRunner:
    def __init__(self):
        self.client = LibLibAIClient()
        self.models = self._load_models_from_json()
        
        # 动态匹配基础算法 XL 的各种控制网模型
        self.sdxl_canny = self._get_model_uuid("线稿类", "Canny（硬边缘）", xl_only=True) or "b6806516962f4e1599a93ac4483c3d23"
        self.sdxl_softedge = self._get_model_uuid("线稿类", "SoftEdge（软边缘）", xl_only=True) or "dda1a0c480bfab9833d9d9a1e4a71fff"
        self.sdxl_lineart = self._get_model_uuid("线稿类", "Lineart（线稿）", xl_only=True) or "a0f01da42bf48b0ba02c86b6c26b5699"
        self.sdxl_openpose = self._get_model_uuid("姿态类", "OpenPose（姿态）", xl_only=True) or "2fe4f992a81c5ccbdf8e9851c8c96ff2"
        
        self._verify_models()
        
    def _load_models_from_json(self):
        json_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "../data/liblibai_controlnet_models.json"))
        if os.path.exists(json_path):
            with open(json_path, "r", encoding="utf-8") as f:
                return json.load(f)
        return {}

    def _get_model_uuid(self, category, subtype, xl_only=True):
        if category in self.models and subtype in self.models[category]:
            for model in self.models[category][subtype]:
                if xl_only and model["base_algorithm"] != "基础算法 XL":
                    continue
                return model["uuid"]
        return None

    def _verify_models(self):
        print("="*50)
        print("校验底模信息 (使用 api/model/version/get)")
        print("="*50)
        
        models_to_verify = {
            "CheckPoint / 底模": DEFAULT_CHECKPOINT_ID,
        }
        
        for name, uuid in models_to_verify.items():
            info = self.client.get_model_version_info(uuid)
            status = f"{info.get('model_name', 'Unknown')} (Base: {info.get('baseAlgo', 'Unknown')})" if info else "Failed to verify"
            print(f"- {name}: [{uuid}] -> {status}")
        print("\n")
        
    def _submit_task(self, payload: dict) -> str:
        url = self.client.generate_auth_url("/api/generate/webui/text2img")
        print(f"Submitting payload...")
        resp = requests.post(url, json=payload, timeout=10)
        data = resp.json()
        if data.get("code") != 0:
            raise Exception(f"Submit task failed: {data.get('msg')} (code: {data.get('code')})")
        return data["data"]["generateUuid"]

    def _wait_and_print_result(self, task_id: str):
        print(f"Task submitted successfully! Task ID: {task_id}")
        print("Waiting for result...")
        timeout = 300
        start_time = time.time()
        while time.time() - start_time < timeout:
            task_data = self.client.query_task_status(task_id)
            status = task_data.get("generateStatus")
            
            if status == 5: # Success
                images = [img["imageUrl"] for img in task_data.get("images", [])]
                print(f"\n[SUCCESSS] Generated images: {images}")
                
                # --- 新增: 自动下载图片 ---
                output_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "output"))
                os.makedirs(output_dir, exist_ok=True)
                for i, img_url in enumerate(images):
                    try:
                        img_resp = requests.get(img_url)
                        img_resp.raise_for_status()
                        timestamp = int(time.time())
                        filename = f"workflow_result_{timestamp}_{i}.png"
                        filepath = os.path.join(output_dir, filename)
                        with open(filepath, "wb") as f:
                            f.write(img_resp.content)
                        print(f"[{i}] 已自动保存到本地: {filepath}")
                    except Exception as e:
                        print(f"图片自动下载失败: {e}")
                return
            elif status in [6, 7]: # Failed or Cancelled
                print(f"\n[FAILED] Task failed. Audit status: {task_data.get('auditStatus')}")
                return
                
            print(".", end="", flush=True)
            time.sleep(5)
            
        print("\n[TIMEOUT] Wait for task timed out.")

    # 1. 纯文生图测试
    def test_text2img(self):
        print("\n" + "="*50)
        print("TEST 1: 纯文生图 (Text to Image)")
        print("="*50)
        
        payload = {
            "templateUuid": TEMPLATE_UUID,
            "generateParams": {
                "checkPointId": DEFAULT_CHECKPOINT_ID,
                "prompt": "1girl, cute, beautiful landscape, masterpiece",
                "negativePrompt": "lowres, bad anatomy, text, error",
                "sampler": 15,
                "steps": 20,
                "cfgScale": 7.0,
                "width": 512,
                "height": 512,
                "imgCount": 1
            }
        }
        task_id = self._submit_task(payload)
        self._wait_and_print_result(task_id)


    # 2. 纯图生图测试
    def test_img2img(self):
        print("\n" + "="*50)
        print("TEST 2: 纯图生图 (Image to Image)")
        print("="*50)
        
        test_img_url = "https://liblibai-airship-temp.oss-cn-beijing.aliyuncs.com/aliyun-cn-prod/73ed6ae42b144d21bf566e05b5a6c138.png"
        
        payload = {
            "templateUuid": TEMPLATE_UUID,
            "generateParams": {
                "checkPointId": DEFAULT_CHECKPOINT_ID,
                "mode": 0,  # 0 代表图生图
                "sourceImage": test_img_url,
                "denoisingStrength": 0.75, # 去噪强度
                "prompt": "white line art, cat",
                "negativePrompt": "lowres, bad anatomy, error",
                "sampler": 15,
                "steps": 20,
                "cfgScale": 7.0,
                "width": 512,
                "height": 512,
                "imgCount": 1
            }
        }
        task_id = self._submit_task(payload)
        self._wait_and_print_result(task_id)


    # 3. 文生图 + ControlNet (Canny) 测试
    def test_text2img_controlnet(self):
        print("\n" + "="*50)
        print("TEST 3: 文生图 + ControlNet (Text2Img with ControlNet Canny)")
        print("="*50)
        print("注意: 如果默认 Checkpoint 是 SD1.5, 下面配置的 SDXL Canny 模型可能会导致访问拒绝!")
        
        test_img_url = "https://liblibai-airship-temp.oss-cn-beijing.aliyuncs.com/aliyun-cn-prod/73ed6ae42b144d21bf566e05b5a6c138.png"
        
        payload = {
            "templateUuid": TEMPLATE_UUID,
            "generateParams": {
                "checkPointId": DEFAULT_CHECKPOINT_ID,
                "prompt": "simple white line art, cat, black background",
                "negativePrompt": "lowres, bad anatomy",
                "sampler": 15,
                "steps": 20,
                "cfgScale": 7.0,
                "width": 512,
                "height": 512,
                "imgCount": 1,
                "controlNet": [{
                    "unitOrder": 1,
                    "sourceImage": test_img_url,
                    "width": 512,
                    "height": 512,
                    "preprocessor": 1,         # 1 = Canny
                    "model": self.sdxl_canny,
                    "controlWeight": 1.0,
                    "startingControlStep": 0.0,
                    "endingControlStep": 1.0,
                    "pixelPerfect": 1,
                    "controlMode": 0,
                    "annotationParameters": {
                        "canny": {
                            "preprocessorResolution": 512,
                            "lowThreshold": 100,
                            "highThreshold": 200
                        }
                    }
                }]
            }
        }
        task_id = self._submit_task(payload)
        self._wait_and_print_result(task_id)


    # 4. 文生图 + 边缘 (SoftEdge/HED)
    def test_text2img_softedge(self):
        print("\n" + "="*50)
        print("TEST 4: 文生图 + SoftEdge (软边缘 控制网)")
        print("="*50)
        
        # 测试用图片
        test_img_url = "https://liblibai-airship-temp.oss-cn-beijing.aliyuncs.com/aliyun-cn-prod/73ed6ae42b144d21bf566e05b5a6c138.png"
        
        payload = {
            "templateUuid": TEMPLATE_UUID,
            "generateParams": {
                "checkPointId": DEFAULT_CHECKPOINT_ID,
                "prompt": "Soft edge artwork, beautiful soft lighting, cat",
                "negativePrompt": "lowres, bad anatomy",
                "sampler": 15,
                "steps": 20,
                "cfgScale": 7.0,
                "width": 512,
                "height": 512,
                "imgCount": 1,
                "controlNet": [{
                    "unitOrder": 1,
                    "sourceImage": test_img_url,
                    "width": 512,
                    "height": 512,
                    "preprocessor": 5,         # 5 = HED / 软边缘
                    "model": self.sdxl_softedge,
                    "controlWeight": 1.0,
                    "startingControlStep": 0.0,
                    "endingControlStep": 1.0,
                    "pixelPerfect": 1,
                    "controlMode": 0,
                    "annotationParameters": {
                        "hed": {
                            "preprocessorResolution": 512
                        }
                    }
                }]
            }
        }
        task_id = self._submit_task(payload)
        self._wait_and_print_result(task_id)


    # 5. 文生图 + 线稿 (Lineart)
    def test_text2img_lineart(self):
        print("\n" + "="*50)
        print("TEST 5: 文生图 + Lineart (线稿 控制网)")
        print("="*50)
        
        test_img_url = "https://liblibai-airship-temp.oss-cn-beijing.aliyuncs.com/aliyun-cn-prod/73ed6ae42b144d21bf566e05b5a6c138.png"
        
        payload = {
            "templateUuid": TEMPLATE_UUID,
            "generateParams": {
                "checkPointId": DEFAULT_CHECKPOINT_ID,
                "prompt": "Detailed coloring, colorful fantasy style, masterpiece, cat",
                "negativePrompt": "lowres",
                "sampler": 15,
                "steps": 20,
                "cfgScale": 7.0,
                "width": 512,
                "height": 512,
                "imgCount": 1,
                "controlNet": [{
                    "unitOrder": 1,
                    "sourceImage": test_img_url,
                    "width": 512,
                    "height": 512,
                    "preprocessor": 32,        # 32 = Lineart Standard
                    "model": self.sdxl_lineart,
                    "controlWeight": 1.0,
                    "startingControlStep": 0.0,
                    "endingControlStep": 1.0,
                    "pixelPerfect": 1,
                    "controlMode": 0,
                    "annotationParameters": {
                        "lineart": {
                            "preprocessorResolution": 512
                        }
                    }
                }]
            }
        }
        task_id = self._submit_task(payload)
        self._wait_and_print_result(task_id)


    # 6. 文生图 + 骨骼 (OpenPose)
    def test_text2img_openpose(self):
        print("\n" + "="*50)
        print("TEST 6: 文生图 + OpenPose (骨骼 控制网)")
        print("="*50)
        
        # 测试用图片（最好使用含有人物动作的图）
        test_img_url = "https://liblibai-airship-temp.oss-cn-beijing.aliyuncs.com/aliyun-cn-prod/73ed6ae42b144d21bf566e05b5a6c138.png"
        
        payload = {
            "templateUuid": TEMPLATE_UUID,
            "generateParams": {
                "checkPointId": DEFAULT_CHECKPOINT_ID,
                "prompt": "1girl, dancing pose, beautiful dress",
                "negativePrompt": "lowres",
                "sampler": 15,
                "steps": 20,
                "cfgScale": 7.0,
                "width": 512,
                "height": 512,
                "imgCount": 1,
                "controlNet": [{
                    "unitOrder": 1,
                    "sourceImage": test_img_url,
                    "width": 512,
                    "height": 512,
                    "preprocessor": 14,        # 14 = OpenPose Full
                    "model": self.sdxl_openpose,
                    "controlWeight": 1.0,
                    "startingControlStep": 0.0,
                    "endingControlStep": 1.0,
                    "pixelPerfect": 1,
                    "controlMode": 0,
                    "annotationParameters": {
                        "openposeFull": {
                            "preprocessorResolution": 512
                        }
                    }
                }]
            }
        }
        task_id = self._submit_task(payload)
        self._wait_and_print_result(task_id)


    # 7. 局部重绘 (Inpaint Mode 4)
    def test_inpaint_mode4(self):
        print("\n" + "="*50)
        print("TEST 7: 局部重绘 (Inpaint Mode 4 蒙版重绘)")
        print("="*50)
        
        test_img_url = "https://liblibai-airship-temp.oss-cn-beijing.aliyuncs.com/aliyun-cn-prod/73ed6ae42b144d21bf566e05b5a6c138.png"
        test_mask_url = test_img_url # 仅作演示，实际应用中应当是一个黑底白色的蒙版图片
        
        payload = {
            # Inpainting 可能需要特殊模板，如不兼容请参考文档
            "templateUuid": TEMPLATE_UUID,
            "generateParams": {
                "checkPointId": DEFAULT_CHECKPOINT_ID,
                "mode": 4,  # 4 = Inpaint 蒙版重绘
                "sourceImage": test_img_url,
                "denoisingStrength": 0.5,
                "prompt": "A completely different background, sci-fi city",
                "negativePrompt": "lowres",
                "sampler": 15,
                "steps": 20,
                "cfgScale": 7.0,
                "width": 512,
                "height": 512,
                "imgCount": 1,
                "inpaintParam": {
                    "maskImage": test_mask_url,
                    "maskBlur": 4,
                    "inpaintArea": 0
                }
            }
        }
        task_id = self._submit_task(payload)
        self._wait_and_print_result(task_id)

    # 8. 人像换脸 (InstantID)
    def test_instantid_faceswap(self):
        print("\n" + "="*50)
        print("TEST 8: 人像换脸 (InstantID)")
        print("="*50)
        
        # Note: InstantID faceswap uses a UNIQUE templateUuid
        INSTANT_ID_TEMPLATE_UUID = "7d888009f81d4252a7c458c874cd017f"
        
        face_img_url = "https://liblibai-online.liblib.cloud/img/081e9f07d9bd4c2ba090efde163518f9/49943c0b-4d79-4e2f-8c55-bc1e5b8c69d8.png"
        pose_img_url = "https://liblibai-online.liblib.cloud/img/081e9f07d9bd4c2ba090efde163518f9/e713676d-baaa-4dac-99b9-d5d814a29f9f.png"
        
        payload = {
            "templateUuid": INSTANT_ID_TEMPLATE_UUID, 
            "generateParams": {
                "checkPointId": DEFAULT_CHECKPOINT_ID, # 仅 XL模型支持人像换脸
                "prompt": "Asian portrait,A young woman wearing a green baseball cap, close shot, background is coffee store, masterpiece, best quality, ultra resolution",
                "width": 768,
                "height": 1152,
                "sampler": 20,
                "steps": 35,
                "cfgScale": 2.0,
                "imgCount": 1,
                "controlNet": [
                    {
                        "unitOrder": 1, # 第一步：先识别要用的人像人脸
                        "sourceImage": face_img_url,
                        "width": 1080,
                        "height": 1432            
                    },
                    {
                        "unitOrder": 2, # 第二步：再识别要参考的人物面部朝向
                        "sourceImage": pose_img_url,
                        "width": 1024,
                        "height": 1024 
                    }
                ]
            }
        }
        task_id = self._submit_task(payload)
        self._wait_and_print_result(task_id)


if __name__ == "__main__":
    try:
        runner = LibLibTestRunner()
        
        print("选择要测试的模式:")
        print("1. 纯文生图 (Text2Img)")
        print("2. 纯图生图 (Img2Img)")
        print("3. 硬边缘控制 (Canny ControlNet)")
        print("4. 软边缘控制 (SoftEdge ControlNet)")
        print("5. 线稿控制 (Lineart ControlNet)")
        print("6. 骨骼控制 (OpenPose ControlNet)")
        print("7. 局部重绘 (Inpaint Mode=4)")
        print("8. 人像换脸 (InstantID)")
        print("9. 全部测试 (All)")
        
        if len(sys.argv) > 1:
            choice = sys.argv[1]
        else:
            # 默认测试文生图以验证 API Key 最基本权限
            choice = "1"
            
        if choice == "1":
            runner.test_text2img()
        elif choice == "2":
            runner.test_img2img()
        elif choice == "3":
            runner.test_text2img_controlnet()
        elif choice == "4":
            runner.test_text2img_softedge()
        elif choice == "5":
            runner.test_text2img_lineart()
        elif choice == "6":
            runner.test_text2img_openpose()
        elif choice == "7":
            runner.test_inpaint_mode4()
        elif choice == "8":
            runner.test_instantid_faceswap()
        elif choice == "9":
            runner.test_text2img()
            runner.test_img2img()
            runner.test_text2img_controlnet()
            # 省略后面的测试避免同时发生太多请求...
        else:
            print("Unknown choice.")
            
    except Exception as e:
        print(f"\n[FATAL ERROR] {e}")
