/**
 * Implicit telemetry — 對應 SDD .agents/specs/llm-interface/ M1.2
 *
 * 每次 deploy / run / validate 失敗，cypher-executor 自動寫 KBDB block
 * type=agent-telemetry，含 event_type / workflow_name / error_code /
 * duration_ms / api_key_hash / agent_user_agent。
 *
 * 隱私：api_key SHA-256 截 16 字元（不可逆，可聚合），workflow 內容不 log。
 *
 * 設計：不阻擋主流程，fetch fire-and-forget；錯誤只 console.warn 不 throw。
 *
 * 注意：本 module 屬 orchestrator 自身能力（觀測自己），不違反「業務邏輯走 WASM」鐵律。
 *      跟 trigger_workflow / scheduled() 同類，是 cypher-executor 自我管理的一部分。
 */

import type { Bindings, ExecutionContext } from '../types';

export type TelemetryEvent =
  | 'deploy_success'
  | 'deploy_fail'
  | 'run_success'
  | 'run_fail'
  | 'validation_error'
  | 'mcp_tool_call'
  | 'node_success'        // 單一 node 跑完（給 step-level 效能分析用）
  | 'node_failure';       // 單一 node 失敗

export interface TelemetryRecord {
  event_type: TelemetryEvent;
  workflow_name?: string;
  component_id?: string;
  error_code?: string;
  duration_ms: number;
  api_key_hash: string;
  agent_user_agent?: string;
}

/**
 * api_key → SHA-256 hex 截前 16 字元
 * 不可逆，可用來聚合（同一用戶不同 event 統計），不會洩漏原 key
 */
export async function hashApiKey(apiKey: string): Promise<string> {
  if (!apiKey) return 'anon';
  const encoder = new TextEncoder();
  const data = encoder.encode(apiKey);
  const hashBuffer = await crypto.subtle.digest('SHA-256', data);
  const hashArray = Array.from(new Uint8Array(hashBuffer));
  return hashArray
    .slice(0, 8) // 8 bytes = 16 hex chars
    .map(b => b.toString(16).padStart(2, '0'))
    .join('');
}

/**
 * KBDB upsert URL（內部走 workers.dev 避同 zone 自循環）
 * 對應 .claude/rules/03-component-architecture.md
 */
function kbdbCreateBlockUrl(env: Bindings): string {
  const subdomain = env.WORKER_SUBDOMAIN || 'uncle6-me';
  return `https://arcrun-kbdb-create-block.${subdomain}.workers.dev`;
}

/**
 * 寫一筆 telemetry block 到 KBDB。fire-and-forget。
 *
 * 寫不進去也不擋主流程 —— 平台自己的觀測絕不能讓 user-facing 流程失敗。
 *
 * 用 ctx.waitUntil 確保即使主 request 已回，背景仍會跑完。
 */
export function recordTelemetry(
  env: Bindings,
  apiKey: string | undefined,
  record: Omit<TelemetryRecord, 'api_key_hash'>,
  ctx?: ExecutionContext,
): void {
  const promise = (async () => {
    try {
      const api_key_hash = await hashApiKey(apiKey ?? '');
      // platform telemetry 用一個系統 ak（讀 env.PLATFORM_API_KEY），所有 telemetry
      // 都聚集在 platform user_id 下，避免污染用戶自己的 KBDB namespace
      const platformKey = env.PLATFORM_API_KEY || apiKey || '';
      if (!platformKey) {
        // 沒 platform key + 沒用戶 key → 無處可寫，skip
        console.warn('[telemetry] no api_key, skipping');
        return;
      }

      const body = {
        api_key: platformKey,
        type: 'agent-telemetry',
        source: 'cypher-executor',
        user_id: 'platform_telemetry',
        content: JSON.stringify(record),
        metadata_json: JSON.stringify({ ...record, api_key_hash }),
        tags_json: JSON.stringify([
          'agent-telemetry',
          `event:${record.event_type}`,
        ]),
      };

      const res = await fetch(kbdbCreateBlockUrl(env), {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(body),
      });

      if (!res.ok) {
        console.warn(
          '[telemetry] write failed',
          res.status,
          await res.text().catch(() => 'no body'),
        );
      }
    } catch (e) {
      console.warn('[telemetry] exception', e);
    }
  })();

  if (ctx?.waitUntil) {
    ctx.waitUntil(promise);
  }
  // 沒 ctx.waitUntil 的情況（直接從 host function call）也讓 promise 自己跑，可能被 cancel 也接受
}
