"""Command-line entry point for the pull-mode Host Agent."""
from __future__ import annotations

import argparse
import os
import sys
import time
import uuid
from pathlib import Path
from typing import Optional, Tuple

from .client import AgentUnauthorized, ControlPlaneClient, ControlPlaneError
from .fingerprint import heartbeat_payload, registration_payload
from .state import AgentState, StateStore


def _execute_dry_run(lease: dict) -> dict:
    """Exercise the distributed worker path without invoking any host command."""

    if lease.get("dry_run") is not True:
        raise RuntimeError("Agent 拒绝执行未注册的真实适配器")
    return {
        "simulated": True,
        "adapter": lease.get("adapter"),
        "template": lease.get("template"),
        "step_key": lease.get("step_key"),
    }


def _process_one_lease(
    client: ControlPlaneClient, state: AgentState
) -> Optional[str]:
    lease = client.lease(state.agent_id, state.token, wait_timeout_s=0)
    if lease is None:
        return None
    step_id = str(lease["step_id"])
    attempt = int(lease["attempt"])
    client.ack(
        state.agent_id,
        state.token,
        step_id,
        attempt,
        str(uuid.uuid4()),
    )
    client.report_events(
        state.agent_id,
        state.token,
        step_id,
        attempt,
        [{"message": "Agent dry-run 正在验证步骤协议", "severity": "INFO"}],
        str(uuid.uuid4()),
    )
    result = _execute_dry_run(lease)
    client.complete(
        state.agent_id,
        state.token,
        step_id,
        attempt,
        status="SUCCEEDED",
        exit_code=0,
        result=result,
        idempotency_key=str(uuid.uuid4()),
    )
    return str(lease.get("step_key") or step_id)


def _parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(description="FlashOps Host Agent")
    parser.add_argument(
        "--server",
        default=os.environ.get("FLASHOPS_AGENT_SERVER", "http://127.0.0.1:8000"),
    )
    parser.add_argument("--host-id", default=os.environ.get("FLASHOPS_AGENT_HOST_ID"))
    parser.add_argument("--host-name", default=os.environ.get("FLASHOPS_AGENT_HOST_NAME"))
    parser.add_argument(
        "--state-path",
        type=Path,
        default=Path(
            os.environ.get(
                "FLASHOPS_AGENT_STATE_PATH",
                str(Path.home() / ".flashops" / "agent-state.json"),
            )
        ),
    )
    parser.add_argument(
        "--enrollment-token",
        default=os.environ.get("FLASHOPS_AGENT_ENROLLMENT_TOKEN"),
    )
    parser.add_argument(
        "--basic-user",
        default=os.environ.get("FLASHOPS_AGENT_BASIC_USER"),
    )
    parser.add_argument(
        "--basic-password",
        default=os.environ.get("FLASHOPS_AGENT_BASIC_PASSWORD"),
    )
    parser.add_argument("--interval", type=float, default=None)
    parser.add_argument("--once", action="store_true")
    return parser


def _basic_auth(user: Optional[str], password: Optional[str]) -> Optional[Tuple[str, str]]:
    if bool(user) != bool(password):
        raise ValueError("Basic Auth 用户名和密码必须同时提供")
    return (user, password) if user and password else None


def _register(
    client: ControlPlaneClient,
    store: StateStore,
    server: str,
    host_id: Optional[str],
    host_name: Optional[str],
) -> AgentState:
    payload = client.register(
        registration_payload(host_id=host_id, host_name=host_name)
    )
    state = AgentState.from_payload(server, payload)
    store.save(state)
    print("Agent 已注册: {0} → Host {1}".format(state.agent_id, state.host_id))
    return state


def main() -> int:
    args = _parser().parse_args()
    server = args.server.rstrip("/")
    store = StateStore(args.state_path)
    try:
        basic_auth = _basic_auth(args.basic_user, args.basic_password)
        with ControlPlaneClient(
            server,
            enrollment_token=args.enrollment_token,
            basic_auth=basic_auth,
        ) as client:
            state = store.load()
            if state is None or state.server != server:
                state = _register(
                    client, store, server, args.host_id, args.host_name
                )

            while True:
                try:
                    response = client.heartbeat(
                        state.agent_id,
                        state.token,
                        heartbeat_payload(),
                    )
                except AgentUnauthorized:
                    state = _register(
                        client, store, server, args.host_id, args.host_name
                    )
                    response = client.heartbeat(
                        state.agent_id,
                        state.token,
                        heartbeat_payload(),
                    )

                print(
                    "心跳已确认: {0} · commands={1}".format(
                        response.get("server_time"),
                        len(response.get("commands", [])),
                    )
                )
                completed_step = _process_one_lease(client, state)
                if completed_step:
                    print("dry-run 步骤已完成: {0}".format(completed_step))
                if args.once:
                    return 0
                interval = args.interval or state.heartbeat_interval_s
                time.sleep(max(0.5, interval))
    except KeyboardInterrupt:
        print("Agent 已停止")
        return 0
    except (ControlPlaneError, OSError, RuntimeError, ValueError) as exc:
        print("Agent 错误: {0}".format(exc), file=sys.stderr)
        return 1


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