# -*- coding: utf-8 -*-
"""Local IPC client for heart Chrome overlay service.

Policy:
- heart service lives outside WS as an independent process on 127.0.0.1:8772.
- Connection failure is a normal waiting state, not an error.
- This module never moves or clicks the mouse.
"""
from __future__ import annotations

import json
import socket
import time
from typing import Any

DEFAULT_HOST = "127.0.0.1"
DEFAULT_PORT = 8772
DEFAULT_TIMEOUT_SEC = 0.35


def _request_heart_service(payload: dict[str, Any], host: str, port: int, timeout_sec: float) -> dict[str, Any]:
    started = time.time()
    try:
        with socket.create_connection((str(host), int(port)), timeout=float(timeout_sec or DEFAULT_TIMEOUT_SEC)) as s:
            s.settimeout(float(timeout_sec or DEFAULT_TIMEOUT_SEC))
            s.sendall((json.dumps(dict(payload or {}), ensure_ascii=False) + "\n").encode("utf-8"))
            data = b""
            while b"\n" not in data and len(data) < 65536:
                chunk = s.recv(4096)
                if not chunk:
                    break
                data += chunk
        if not data:
            return {
                "ok": False,
                "state": "heart_waiting",
                "connected": False,
                "reason": "heart_service_empty_response",
                "normal_wait": True,
                "elapsed_ms": int((time.time() - started) * 1000),
            }
        text = data.split(b"\n", 1)[0].decode("utf-8", errors="replace")
        obj = json.loads(text)
        if not isinstance(obj, dict):
            return {"ok": False, "state": "heart_bad_response", "connected": True, "reason": "response_not_object"}
        obj.setdefault("connected", True)
        obj.setdefault("service", "heart8772")
        return obj
    except (ConnectionRefusedError, TimeoutError, socket.timeout, OSError) as e:
        return {
            "ok": False,
            "state": "heart_waiting",
            "connected": False,
            "reason": "heart_service_not_connected",
            "normal_wait": True,
            "message": "heart 8772 대기중",
            "error_type": type(e).__name__,
            "elapsed_ms": int((time.time() - started) * 1000),
        }
    except Exception as e:
        return {
            "ok": False,
            "state": "heart_ipc_unexpected_error",
            "connected": False,
            "reason": "unexpected_error",
            "error": str(e),
            "error_type": type(e).__name__,
            "elapsed_ms": int((time.time() - started) * 1000),
        }


def get_heart_snapshot(host: str = DEFAULT_HOST, port: int = DEFAULT_PORT, timeout_sec: float = DEFAULT_TIMEOUT_SEC) -> dict[str, Any]:
    return _request_heart_service({"act": "get_snapshot", "v": 1}, host, port, timeout_sec)


def reset_heart_calibration(
    host: str = DEFAULT_HOST,
    port: int = DEFAULT_PORT,
    timeout_sec: float = DEFAULT_TIMEOUT_SEC,
    reason: str = "ipc_reset_calibration",
) -> dict[str, Any]:
    """Reset Heart8772 DOM calibration through localhost IPC.

    This only clears Heart's stored origin/delta/watch-point state.
    It never moves or clicks the mouse.
    """
    return _request_heart_service({"act": "reset_calibration", "v": 1, "reason": str(reason)}, host, port, timeout_sec)


# Backward-compatible name used by older WS/click code.
def get_global_heart_snapshot() -> dict[str, Any]:
    return get_heart_snapshot()
