import getpass
import json
from pathlib import Path
import re
import shutil
import time
from datetime import datetime, timezone
from urllib.error import HTTPError
from urllib.parse import quote
from urllib.request import Request, urlopen
import uuid
import webbrowser

BASE_URL = "https://yyds.seqnode.com"
TASK_ID = ""  # 续查时填入原任务 ID；留空会创建一条视频并计费。
PAYLOAD = {
    "model": "grok-imagine-video-1.5",
    "prompt": "一只橘猫在窗边伸懒腰，晨光柔和，镜头固定，无文字。",
    "duration": 1,
    "resolution": "480p",
    "aspect_ratio": "16:9"
}


def request_json(url, headers, payload=None):
    body = None if payload is None else json.dumps(payload, ensure_ascii=False).encode("utf-8")
    request = Request(url, data=body, headers=headers)
    with urlopen(request, timeout=180 if body else 60) as response:
        return json.load(response)


def main():
    api_key = getpass.getpass("输入绑定 155 分组的 API Key：").strip()
    if not api_key:
        raise ValueError("请输入有效的 API Key。")
    headers = {"Authorization": "Bearer " + api_key, "Content-Type": "application/json; charset=utf-8"}
    task_id = TASK_ID
    if not task_id:
        created = request_json(BASE_URL + "/v1/videos/generations", headers, PAYLOAD)
        task_id = created.get("request_id")
        if not isinstance(task_id, str) or not task_id:
            raise ValueError("未获得任务 ID。先检查使用记录，避免重复创建。")
    print(f"任务 ID：{task_id}（请保存，后续查询使用原 ID）")
    task_url = BASE_URL + "/v1/videos/" + quote(task_id, safe="")
    deadline = time.monotonic() + 300
    while time.monotonic() < deadline:
        result = request_json(task_url, headers)
        status, delivery = result.get("status"), result.get("delivery_status")
        print(f"生成：{status}；进度：{result.get('progress')}；转存：{delivery}")
        if status in ("failed", "expired") or delivery in ("failed", "expired"):
            raise RuntimeError(f"任务 {task_id} 未就绪或已过期。检查原任务和 /content 接口，勿重新创建。")
        if status in ("done", "completed") and delivery == "ready":
            break
        time.sleep(5)
    else:
        raise TimeoutError(f"等待超时。将 {task_id} 填入顶部 TASK_ID 后继续查询。")
    video = result.get("video", {})
    play_url, download_url = video.get("url", ""), video.get("download_url", "")
    if not re.fullmatch(r"https://yyds\.seqnode\.com/(?:video-files/)?[0-9a-f]{32}\.mp4", play_url) or download_url != play_url + "?download=1":
        raise ValueError("视频 URL 格式异常，请检查原任务的响应。")
    expires = datetime.fromtimestamp(video["expires_at"], timezone.utc) if type(video["expires_at"]) is int else datetime.fromisoformat(video["expires_at"].replace("Z", "+00:00"))
    if expires.tzinfo is None or expires <= datetime.now(timezone.utc):
        raise ValueError("视频链接已过期或到期时间格式异常。")
    print(f"在线播放：{play_url}\n到期时间：{expires.astimezone().isoformat()}")
    path = Path.cwd() / ("grok-video-" + uuid.uuid4().hex + ".mp4")
    # 播放和下载直链无需 API Key。
    with urlopen(Request(download_url, headers={"User-Agent": "YM2API-Quickstart/1.0"}), timeout=180) as response:
        if response.status != 200 or response.headers.get_content_type() != "video/mp4":
            raise ValueError("下载结果不是 MP4。保留原任务 ID，稍后重试下载。")
        with path.open("xb") as output:
            try:
                shutil.copyfileobj(response, output)
                if output.tell() == 0:
                    raise ValueError("下载的视频为空。")
            except Exception:
                output.close()
                path.unlink()
                raise
    print(f"视频已保存：{path}")
    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}（已有任务 ID 时请继续查询原任务。）")
        raise SystemExit(1)
