from __future__ import annotations

import argparse
import json
import os
import runpy
import sys
import traceback
from pathlib import Path
from typing import Any, Dict

from common.runtime_paths import PROJECT_ROOT
from common.task_runtime import TaskContext


def _source_root() -> Path:
    """返回外置源码根目录，worker 每次启动都从这里读取最新任务代码。"""
    override = os.environ.get("WAWA_HOT_UPDATE_SOURCE_DIR", "").strip()
    if override:
        return Path(override)
    return PROJECT_ROOT


def _resolve_entrypoint(entrypoint: str) -> Path:
    """解析任务入口文件，支持相对 source 的路径和绝对路径。"""
    path = Path(entrypoint)
    if not path.is_absolute():
        path = _source_root() / path
    return path.resolve()


def run_task_from_spec(spec_path: Path) -> int:
    spec: Dict[str, Any] = json.loads(spec_path.read_text(encoding="utf-8-sig"))
    task_dir = Path(str(spec.get("task_dir") or spec_path.parent)).resolve()
    task_dir.mkdir(parents=True, exist_ok=True)
    context = TaskContext(spec, task_dir)
    context.update_status("running", "子进程已启动")
    entrypoint = _resolve_entrypoint(str(spec.get("entrypoint") or ""))
    try:
        if not entrypoint.exists():
            raise FileNotFoundError(f"任务入口不存在: {entrypoint}")
        source_root = str(_source_root())
        if source_root not in sys.path:
            sys.path.insert(0, source_root)
        context.log(f"任务入口: {entrypoint}")
        namespace = runpy.run_path(str(entrypoint))
        runner = namespace.get("run")
        if not callable(runner):
            raise RuntimeError("任务入口缺少 run(context) 函数")
        result = runner(context)
        if isinstance(result, dict):
            context.write_result(result)
        else:
            context.write_result({"result": result})
        context.update_status("success", "任务执行完成")
        return 0
    except Exception as exc:
        context.log("任务执行失败:")
        context.log(traceback.format_exc())
        context.update_status("failed", str(exc))
        return 1


def main(argv: list[str] | None = None) -> int:
    parser = argparse.ArgumentParser(description="WaWaCloud 子进程任务运行器")
    parser.add_argument("task_spec", help="任务 task.json 路径")
    args = parser.parse_args(argv)
    if hasattr(sys.stdout, "reconfigure"):
        sys.stdout.reconfigure(encoding="utf-8", errors="replace", line_buffering=True)
    if hasattr(sys.stderr, "reconfigure"):
        sys.stderr.reconfigure(encoding="utf-8", errors="replace", line_buffering=True)
    return run_task_from_spec(Path(args.task_spec).resolve())


if __name__ == "__main__":
    raise SystemExit(main())
