#!/usr/bin/env python3
from __future__ import annotations

import argparse
import json
import sys
from pathlib import Path

from common import (
    build_agent_entry,
    build_bot_api_account,
    deep_merge_dict,
    default_openclaw_config_path,
    dump_json,
    find_agent_entry,
    find_bot_api_accounts_by_agent_id,
    find_agent_by_workspace,
    is_auto_generate_image_description_enabled,
    normalize_heartbeat_for_openclaw,
    load_agent_definition,
    load_openclaw_config,
    resolve_existing_agent_entry,
    sync_openclaw_auto_image_description_rules,
    write_install_state,
)


def normalized_override(value: str | None) -> str | None:
    if isinstance(value, str):
        stripped = value.strip()
        if stripped:
            return stripped
    return None


def upsert_agent(config: dict, entry: dict) -> str:
    config.setdefault("agents", {})
    agents = config["agents"].setdefault("list", [])

    for index, agent in enumerate(agents):
        if isinstance(agent, dict) and agent.get("id") == entry["id"]:
            agents[index] = deep_merge_dict(agent, entry)
            return "updated"

    agents.append(entry)
    return "created"


def ensure_bot_api(
    config: dict,
    agent_def: dict,
    *,
    target_agent_id: str,
    name_override: str | None = None,
) -> dict[str, object] | None:
    existing_accounts = find_bot_api_accounts_by_agent_id(config, target_agent_id)
    existing_secret = None
    if existing_accounts:
        first_account = next(iter(existing_accounts.values()))
        existing_secret = first_account.get("apiSecret")

    built = build_bot_api_account(
        agent_def,
        agent_id_override=target_agent_id,
        existing_secret=existing_secret,
        name_override=name_override,
    )
    if built is None:
        return None

    account_id, account = built
    plugins = config.setdefault("plugins", {})
    allow = plugins.setdefault("allow", [])
    if "bot-api" not in allow:
        allow.append("bot-api")
    entries = plugins.setdefault("entries", {})
    entries.setdefault("bot-api", {})["enabled"] = True

    channels = config.setdefault("channels", {})
    bot_api = channels.setdefault("bot-api", {})
    accounts = bot_api.setdefault("accounts", {})
    action = "updated" if account_id in accounts else "created"
    accounts[account_id] = account

    return {
        "account_id": account_id,
        "action": action,
        "apiSecret": account["apiSecret"],
    }


def update_openclaw(
    agent_id: str,
    config_path: Path,
    *,
    source_path: Path | None = None,
    openclaw_id_override: str | None = None,
    workspace_override: str | None = None,
    name_override: str | None = None,
) -> dict[str, object]:
    resolved_openclaw_id = normalized_override(openclaw_id_override)
    resolved_workspace = normalized_override(workspace_override)
    resolved_name = normalized_override(name_override)
    agent_def = load_agent_definition(agent_id, source_path)
    config = load_openclaw_config(config_path)
    desired_workspace = resolved_workspace or agent_def.get("install", {}).get("workspace") or agent_def.get("workspace")
    previous = resolve_existing_agent_entry(config_path, config, agent_id, desired_workspace)
    if previous is None and resolved_openclaw_id:
        existing_by_target_id = find_agent_entry(config, resolved_openclaw_id)
        if existing_by_target_id is not None:
            raise ValueError(f"目标 openclaw id 已存在且不属于当前 Agent: {resolved_openclaw_id}")
    if previous is not None:
        target_agent_id = previous.get("id") if previous.get("id") else agent_id
    else:
        target_agent_id = resolved_openclaw_id or agent_id

    entry = build_agent_entry(
        agent_def,
        target_id_override=target_agent_id,
        workspace_override=resolved_workspace,
        name_override=resolved_name,
    )
    agent_action = upsert_agent(config, entry)
    bot_api_result = ensure_bot_api(
        config,
        agent_def,
        target_agent_id=target_agent_id,
        name_override=resolved_name,
    )

    auto_img_desc = is_auto_generate_image_description_enabled(agent_def)
    sync_openclaw_auto_image_description_rules(
        config,
        target_agent_id,
        enabled=auto_img_desc,
    )

    dump_json(config_path, config)
    state_path = write_install_state(
        config_path,
        target_agent_id,
        {
            "agent_id": agent_id,
            "openclaw_id": target_agent_id,
            "version": agent_def["version"],
            "workspace": entry["workspace"],
            "agentDir": entry.get("agentDir"),
        },
    )

    heartbeat_cfg = normalize_heartbeat_for_openclaw(agent_def)

    return {
        "agent_id": agent_id,
        "openclaw_id": target_agent_id,
        "agent_action": agent_action,
        "bot_api": bot_api_result,
        "workspace": entry["workspace"],
        "name": entry.get("name") or entry.get("identity", {}).get("name"),
        "agent_dir": entry.get("agentDir"),
        "previous_workspace": previous.get("workspace") if previous else None,
        "version": agent_def["version"],
        "install_state": str(state_path),
        "auto_generate_image_description": auto_img_desc,
        "heartbeat_configured": heartbeat_cfg is not None,
        "heartbeat": heartbeat_cfg,
    }


def main() -> int:
    parser = argparse.ArgumentParser(description="根据 .config.json 幂等更新 openclaw.json")
    parser.add_argument("--agent-id", required=True, help="Agent ID")
    parser.add_argument("--source-path", help="Agent 下载目录（sophhub agent download 的 --path）")
    parser.add_argument("--openclaw-id", help="目标 openclaw id（resolve_install_params 与流程确认结果）")
    parser.add_argument("--workspace", help="目标 workspace（流程确认结果）")
    parser.add_argument("--name", help="显示名称 agent_name（流程确认结果）")
    parser.add_argument(
        "--config",
        default=str(default_openclaw_config_path()),
        help="openclaw.json 路径",
    )
    args = parser.parse_args()

    result = update_openclaw(
        args.agent_id,
        Path(args.config).expanduser().resolve(),
        source_path=Path(args.source_path).expanduser().resolve() if args.source_path else None,
        openclaw_id_override=args.openclaw_id,
        workspace_override=args.workspace,
        name_override=args.name,
    )
    json.dump(result, sys.stdout, indent=2, ensure_ascii=False)
    sys.stdout.write("\n")
    return 0


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