#!/usr/bin/env python3
"""kis-agent CLI Bridge — TypeScript subprocess에서 JSON stdin/stdout으로 통신하는 레이어.

TS GraphQL CLI(cli/)에서 이 스크립트를 subprocess로 실행하여 kis-agent API를 호출합니다.

프로토콜:
    - 입력: stdin으로 JSON 한 줄씩 수신
    - 출력: stdout으로 JSON 한 줄씩 반환
    - 로그: stderr로 출력 (stdout 오염 방지)

명령:
    {"cmd": "init"}                              → Agent 초기화
    {"cmd": "ping"}                              → 연결 확인
    {"cmd": "exit"}                              → 종료
    {"cmd": "list_methods"}                      → 사용 가능 메서드 목록
    {"method": "...", "domain": "...", "args": {}} → API 호출
"""
# Created: 2026-03-20
# Dependencies: kis_agent

import json
import sys
import os
import logging

# 로깅을 stderr로 보내서 stdout JSON 출력을 오염시키지 않음
logging.basicConfig(stream=sys.stderr, level=logging.WARNING)

from dotenv import load_dotenv


def create_agent():
    """환경변수에서 인증 정보를 로드하여 Agent 생성"""
    # .env 파일 탐색: 현재 디렉토리 → 프로젝트 루트
    env_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), ".env")
    load_dotenv(env_path)

    from kis_agent import Agent

    return Agent(
        app_key=os.environ["KIS_APP_KEY"],
        app_secret=os.environ.get("KIS_APP_SECRET", os.environ.get("KIS_SECRET", "")),
        account_no=os.environ["KIS_ACCOUNT_NO"],
        account_code=os.environ.get("KIS_ACCOUNT_CODE", "01"),
        base_url=os.environ.get(
            "KIS_BASE_URL", "https://openapi.koreainvestment.com:9443"
        ),
    )


def handle_request(agent, request: dict) -> dict:
    """단일 요청을 처리하여 결과 반환"""
    method = request.get("method", "")
    args = request.get("args", {})
    domain = request.get("domain", "")

    try:
        # 도메인별 API 객체 선택
        if domain == "overseas":
            target = agent.overseas_api
        elif domain == "futures":
            target = agent.futures_api
        elif domain == "overseas_futures":
            target = agent.overseas_futures_api
        elif domain == "account":
            target = agent.account_api
        elif domain == "stock":
            target = agent.stock_api
        else:
            target = agent

        fn = getattr(target, method, None)
        if fn is None:
            return {"error": f"Unknown method: {domain}.{method}", "code": "METHOD_NOT_FOUND"}

        result = fn(**args)

        if result is None:
            return {"data": None}

        # pandas DataFrame → dict 변환
        import pandas as pd
        if isinstance(result, pd.DataFrame):
            return {"data": result.to_dict(orient="records")}

        return {"data": result}

    except Exception as e:
        return {"error": str(e), "code": type(e).__name__}


def list_methods(agent) -> dict:
    """사용 가능한 메서드 목록 반환 (LLM introspection용)"""
    domains = {
        "agent": agent,
        "stock": agent.stock_api,
        "account": agent.account_api,
        "overseas": agent.overseas_api,
        "futures": agent.futures_api,
    }
    methods = {}
    for domain_name, obj in domains.items():
        methods[domain_name] = [
            m for m in dir(obj)
            if not m.startswith("_") and callable(getattr(obj, m, None))
        ]
    return {"data": methods}


def main():
    """메인 루프: stdin에서 JSON 명령을 읽고 stdout으로 JSON 응답 반환"""
    agent = None

    for line in sys.stdin:
        line = line.strip()
        if not line:
            continue

        try:
            request = json.loads(line)
        except json.JSONDecodeError as e:
            response = {"error": f"Invalid JSON: {e}", "code": "PARSE_ERROR"}
            print(json.dumps(response, ensure_ascii=False), flush=True)
            continue

        # 특수 명령
        cmd = request.get("cmd")

        if cmd == "init":
            try:
                agent = create_agent()
                response = {"status": "ok"}
            except Exception as e:
                response = {"error": str(e), "code": type(e).__name__}
            print(json.dumps(response, ensure_ascii=False), flush=True)
            continue

        if cmd == "ping":
            print(json.dumps({"status": "pong"}), flush=True)
            continue

        if cmd == "exit":
            break

        if cmd == "list_methods":
            if agent is None:
                response = {"error": "Agent not initialized. Send {\"cmd\": \"init\"} first.", "code": "NOT_INITIALIZED"}
            else:
                response = list_methods(agent)
            print(json.dumps(response, ensure_ascii=False), flush=True)
            continue

        # 일반 API 호출
        if agent is None:
            response = {"error": "Agent not initialized. Send {\"cmd\": \"init\"} first.", "code": "NOT_INITIALIZED"}
        else:
            response = handle_request(agent, request)

        print(json.dumps(response, ensure_ascii=False, default=str), flush=True)


if __name__ == "__main__":
    main()
