import base64
import getpass
import json
from pathlib import Path
import sys
from urllib.error import HTTPError
from urllib.request import Request, urlopen
import uuid
import webbrowser

BASE_URL = "https://yyds.seqnode.com/v1"
USER_AGENT = "YM2API-Quickstart/1.0"
# 不带参数：文生图 2K 16:9；带一个本地图片路径：图生图 4K（1:1）。
# 省略 response_format 时默认返回图片链接（url）；需要 Base64 时加 "response_format": "b64_json"。
# 更快、更便宜可把 model 改为 "gpt-image-2.5-banana2"（香蕉 2.0，USD 0.05/张）。
GENERATE = {
    "model": "gpt-image-2.5-banana2.1",
    "prompt": "雨后的城市街角咖啡馆，木质招牌写着'CAFE 1897'，暖色灯光，电影感。",
    "size": "2048x1152",
    "n": 1
}
EDIT = {
    "model": "gpt-image-2.5-banana2.1",
    "prompt": "保留参考图的主体、构图和文字，改成冬夜雪景，细节清晰。",
    "size": "4K",
    "n": "1"
}


def post(path, api_key, body, content_type):
    headers = {"Authorization": "Bearer " + api_key, "Content-Type": content_type, "User-Agent": USER_AGENT}
    with urlopen(Request(BASE_URL + path, data=body, headers=headers), timeout=300) as response:
        return json.load(response)


def multipart(fields, image_path):
    boundary = "----ym2api" + uuid.uuid4().hex
    chunks = []
    for name, value in fields.items():
        chunks.append(f'--{boundary}\r\nContent-Disposition: form-data; name="{name}"\r\n\r\n{value}\r\n'.encode("utf-8"))
    data = image_path.read_bytes()
    if data.startswith(b"\x89PNG\r\n\x1a\n"):
        mime, filename = "image/png", "reference.png"
    elif data.startswith(b"\xff\xd8\xff"):
        mime, filename = "image/jpeg", "reference.jpg"
    elif len(data) >= 12 and data[:4] == b"RIFF" and data[8:12] == b"WEBP":
        mime, filename = "image/webp", "reference.webp"
    else:
        raise ValueError("参考图需为 PNG、JPEG 或 WebP。")
    chunks.append(f'--{boundary}\r\nContent-Disposition: form-data; name="image"; filename="{filename}"\r\n'
                  f"Content-Type: {mime}\r\n\r\n".encode("utf-8") + data + b"\r\n")
    chunks.append(f"--{boundary}--\r\n".encode("utf-8"))
    return b"".join(chunks), "multipart/form-data; boundary=" + boundary


def main():
    api_key = getpass.getpass("输入 API Key：").strip()
    if not api_key:
        raise ValueError("请输入有效的 API Key。")
    if len(sys.argv) > 1:
        body, content_type = multipart(EDIT, Path(sys.argv[1]))
        result = post("/images/edits", api_key, body, content_type)
    else:
        body = json.dumps(GENERATE, ensure_ascii=False).encode("utf-8")
        result = post("/images/generations", api_key, body, "application/json; charset=utf-8")
    item = next(iter(result.get("data") or []), {})
    if item.get("url"):
        # 图片链接保留 1 小时；下载时不要携带 API Key。
        with urlopen(Request(item["url"], headers={"User-Agent": USER_AGENT}), timeout=120) as response:
            data = response.read()
    elif item.get("b64_json"):
        data = base64.b64decode(item["b64_json"], validate=True)
    else:
        raise ValueError("响应没有最终图片。请检查响应和使用记录，再决定是否重试。")
    if data.startswith(b"\x89PNG\r\n\x1a\n"):
        extension = ".png"
    elif data.startswith(b"\xff\xd8\xff"):
        extension = ".jpg"
    elif len(data) >= 12 and data[:4] == b"RIFF" and data[8:12] == b"WEBP":
        extension = ".webp"
    else:
        raise ValueError("返回数据不是可识别的 PNG、JPEG 或 WebP。")
    path = Path.cwd() / ("gpt-banana21-" + uuid.uuid4().hex + extension)
    with path.open("xb") as output:
        output.write(data)
    print(f"图片已保存：{path}（实际尺寸 {result.get('size', '未知')}）")
    if not webbrowser.open(path.as_uri()):
        print("请到以上路径手动打开图片。")


if __name__ == "__main__":
    try:
        main()
    except HTTPError as error:
        print(f"HTTP {error.code}：{error.read(2000).decode('utf-8', errors='replace')}")
        raise SystemExit(1)
    except Exception as error:
        print(f"运行失败：{error}")
        raise SystemExit(1)
