#!/usr/bin/env python3
"""Opik 트레이스/스팬 조회 스크립트.

사용법:
    # 최근 outlook_extraction 트레이스 조회
    python scripts/opik_query.py traces --tag outlook_extraction --limit 5

    # 특정 트레이스의 스팬(LLM 호출) 조회
    python scripts/opik_query.py spans --trace-id <trace_id>

    # 특정 트레이스의 LLM 입출력 전체 보기
    python scripts/opik_query.py detail --trace-id <trace_id>

    # 날짜 필터
    python scripts/opik_query.py traces --tag outlook_extraction --after "2026-03-26T11:00:00Z"

    # 출력에서 특정 키워드 검색
    python scripts/opik_query.py traces --tag outlook_extraction --grep "C02"
"""
import argparse
import json
import sys
import os

# backend 루트를 path에 추가
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from app.core.config import settings


def get_client():
    import opik
    return opik.Opik(
        api_key=settings.opik_api_key,
        workspace=settings.opik_workspace,
        project_name=settings.opik_project_name,
    )


def cmd_traces(args):
    client = get_client()
    filters = []
    if args.tag:
        filters.append(f'tags contains "{args.tag}"')
    if args.after:
        filters.append(f'start_time >= "{args.after}"')
    if args.before:
        filters.append(f'start_time < "{args.before}"')

    filter_string = " AND ".join(filters) if filters else None
    traces = client.search_traces(
        filter_string=filter_string,
        max_results=args.limit,
        truncate=not args.full,
    )

    for t in traces:
        line = f"{t.start_time}  {t.id[:12]}  {t.name or '-':40s}  tags={t.tags}"
        if args.grep and args.grep not in str(t.output):
            continue
        print(line)
        if args.output:
            out = json.dumps(t.output, ensure_ascii=False, indent=2) if isinstance(t.output, dict) else str(t.output)
            print(f"  output: {out[:500]}")
    print(f"\n총 {len(traces)}건")


def cmd_spans(args):
    client = get_client()
    filters = []
    if args.tag:
        filters.append(f'tags contains "{args.tag}"')
    spans = client.search_spans(
        trace_id=args.trace_id,
        filter_string=" AND ".join(filters) if filters else None,
        max_results=args.limit,
        truncate=not args.full,
    )

    for s in spans:
        line = f"{s.start_time}  {s.id[:12]}  {s.name or '-':40s}  model={getattr(s, 'model', '-')}"
        if args.grep and args.grep not in str(s.output):
            continue
        print(line)
        if args.output:
            out = json.dumps(s.output, ensure_ascii=False, indent=2) if isinstance(s.output, dict) else str(s.output)
            print(f"  output: {out[:1000]}")


def cmd_detail(args):
    """특정 트레이스의 모든 스팬 입출력을 상세히 출력."""
    client = get_client()
    spans = client.search_spans(
        trace_id=args.trace_id,
        max_results=100,
        truncate=False,
    )

    for i, s in enumerate(spans):
        print(f"\n{'='*80}")
        print(f"[{i+1}] {s.name or '-'}  model={getattr(s, 'model', '-')}  {s.start_time}")
        print(f"    id: {s.id}")

        if s.input:
            inp = json.dumps(s.input, ensure_ascii=False, indent=2) if isinstance(s.input, dict) else str(s.input)
            if args.grep and args.grep not in inp and args.grep not in str(s.output):
                continue
            if not args.input_off:
                print(f"\n  ── INPUT ──")
                print(inp[:args.max_chars])

        if s.output:
            out = json.dumps(s.output, ensure_ascii=False, indent=2) if isinstance(s.output, dict) else str(s.output)
            print(f"\n  ── OUTPUT ──")
            print(out[:args.max_chars])


def main():
    parser = argparse.ArgumentParser(description="Opik 트레이스/스팬 조회")
    sub = parser.add_subparsers(dest="cmd")

    # traces
    p_traces = sub.add_parser("traces", help="트레이스 목록 조회")
    p_traces.add_argument("--tag", help="태그 필터 (예: outlook_extraction)")
    p_traces.add_argument("--after", help="시작 시간 이후 (ISO 8601)")
    p_traces.add_argument("--before", help="시작 시간 이전 (ISO 8601)")
    p_traces.add_argument("--limit", type=int, default=10, help="최대 결과 수")
    p_traces.add_argument("--grep", help="출력에서 키워드 검색")
    p_traces.add_argument("--output", action="store_true", help="output 표시")
    p_traces.add_argument("--full", action="store_true", help="truncate 비활성화")

    # spans
    p_spans = sub.add_parser("spans", help="스팬 목록 조회")
    p_spans.add_argument("--trace-id", required=True, help="트레이스 ID")
    p_spans.add_argument("--tag", help="태그 필터")
    p_spans.add_argument("--limit", type=int, default=50, help="최대 결과 수")
    p_spans.add_argument("--grep", help="출력에서 키워드 검색")
    p_spans.add_argument("--output", action="store_true", help="output 표시")
    p_spans.add_argument("--full", action="store_true", help="truncate 비활성화")

    # detail
    p_detail = sub.add_parser("detail", help="트레이스 상세 (모든 스팬 입출력)")
    p_detail.add_argument("--trace-id", required=True, help="트레이스 ID")
    p_detail.add_argument("--grep", help="키워드 필터")
    p_detail.add_argument("--max-chars", type=int, default=3000, help="입출력 최대 글자 수")
    p_detail.add_argument("--input-off", action="store_true", help="입력 숨기기")

    args = parser.parse_args()
    if args.cmd == "traces":
        cmd_traces(args)
    elif args.cmd == "spans":
        cmd_spans(args)
    elif args.cmd == "detail":
        cmd_detail(args)
    else:
        parser.print_help()


if __name__ == "__main__":
    main()
