"""Opik REST 에서 trace 를 시간 창으로 걷어온다 (읽기 전용)."""
import json
import logging
import urllib.parse
import urllib.request
from typing import Any, Dict, List

logger = logging.getLogger(__name__)

PAGE_SIZE = 200


def fetch_traces(
    base_url: str,
    workspace: str,
    project_name: str,
    since: str,
    until: str = "9999",
) -> List[Dict[str, Any]]:
    """start_time 이 [since, until) 인 trace 전부 (최신순 페이지 순회).

    base_url 예: http://192.168.133.87:5173/api
    since/until: ISO 문자열 비교 (Opik start_time 은 ISO·UTC — 문자열
    비교가 시간 순서와 일치한다).
    """
    traces: List[Dict[str, Any]] = []
    page = 1
    while True:
        q = urllib.parse.urlencode({
            "project_name": project_name,
            "size": PAGE_SIZE,
            "page": page,
            "sorting": json.dumps(
                [{"field": "start_time", "direction": "DESC"}]),
        })
        req = urllib.request.Request(
            f"{base_url}/v1/private/traces?{q}",
            headers={"Comet-Workspace": workspace})
        with urllib.request.urlopen(req, timeout=60) as r:
            d = json.loads(r.read())
        content = d.get("content", [])
        if not content:
            break
        stop = False
        for t in content:
            st = t.get("start_time", "")
            if st < since:
                stop = True
                break
            if st < until:
                traces.append(t)
        if stop or page * PAGE_SIZE >= int(d.get("total", 0)):
            break
        page += 1
    logger.info("trace %d건 수집 (since=%s)", len(traces), since)
    return traces


def step_of(trace: Dict[str, Any]) -> str:
    """trace 의 스텝 이름 — litellm 메타의 trace_name 마지막 조각 우선."""
    md = trace.get("metadata") or {}
    tn = md.get("trace_name") if isinstance(md, dict) else None
    if isinstance(tn, str) and ">" in tn:
        return tn.split(">")[-1].strip()
    if isinstance(tn, str) and tn:
        return tn
    return str(trace.get("name") or "?")


def messages_of(trace: Dict[str, Any]) -> Dict[str, str]:
    """input 에서 role 별 텍스트 결합 (system/user). 비텍스트 파트는
    JSON 직렬화 길이로만 세지 않고 문자열화해 포함한다."""
    out = {"system": "", "user": ""}
    inp = trace.get("input")
    if isinstance(inp, list):
        for m in inp:
            if not isinstance(m, dict):
                continue
            role = m.get("role")
            if role not in out:
                continue
            c = m.get("content")
            out[role] += c if isinstance(c, str) else json.dumps(
                c, ensure_ascii=False)
    elif isinstance(inp, dict):
        # record_provider_call 계열 — prompt 필드가 본문이다.
        p = inp.get("prompt")
        if isinstance(p, str):
            out["user"] = p
    return out
