// 單元測試：recordAnalytics — 執行統計回寫
// SDD: system-dev/docs/3-specs/arcrun-core-mvp/design.md「執行統計設計」

import { describe, it, expect, beforeEach } from 'vitest';
import { recordAnalytics } from '../src/actions/recordAnalytics';
import type { Bindings } from '../src/types';

// 最小 KV mock（get/put/list，In-memory）
function makeKv() {
  const store = new Map<string, string>();
  return {
    store,
    async get(key: string) { return store.get(key) ?? null; },
    async put(key: string, value: string) { store.set(key, value); },
    async list({ prefix }: { prefix: string }) {
      return { keys: [...store.keys()].filter(k => k.startsWith(prefix)).map(name => ({ name })) };
    },
  };
}

describe('recordAnalytics', () => {
  let submissions: ReturnType<typeof makeKv>;
  let analytics: ReturnType<typeof makeKv>;
  let env: Bindings;

  beforeEach(() => {
    submissions = makeKv();
    analytics = makeKv();
    env = { SUBMISSIONS_KV: submissions, ANALYTICS_KV: analytics } as unknown as Bindings;

    // 種一顆零件（indexOnlyComponent 的記錄形狀）
    submissions.store.set('idx:http_request', 'cmp_abc12345');
    submissions.store.set('comp:cmp_abc12345:v1', JSON.stringify({
      component_hash_id: 'cmp_abc12345',
      canonical_id: 'http_request',
      display_name: 'HTTP Request',
      version: 'v1',
      success_rate: 1,
      avg_duration_ms: 0,
      call_count: 0,
      visibility: 'public',
      status: 'active',
    }));
  });

  it('N 次成功＋M 次失敗 → success_rate = success_runs / total_runs，計數器與 comp 記錄同步', async () => {
    // 3 成功 + 2 失敗
    for (const success of [true, true, true, false, false]) {
      const r = await recordAnalytics({ canonical_id: 'http_request', success, duration_ms: 100 }, env);
      expect(r.ok).toBe(true);
    }

    // 真相源：ANALYTICS_KV 計數器
    const counters = JSON.parse(analytics.store.get('stats:cmp_abc12345:v1')!);
    expect(counters).toEqual({ total_runs: 5, success_runs: 3, total_ms: 500 });

    // 讀取端：comp 記錄被回填衍生值
    const record = JSON.parse(submissions.store.get('comp:cmp_abc12345:v1')!);
    expect(record.success_rate).toBeCloseTo(3 / 5);
    expect(record.avg_duration_ms).toBe(100);
    expect(record.call_count).toBe(5);
  });

  it('接受 cmp_ hash_id 直接記錄', async () => {
    const r = await recordAnalytics({ canonical_id: 'cmp_abc12345', success: true, duration_ms: 50 }, env);
    expect(r.ok).toBe(true);
    expect(r.canonical_id).toBe('http_request');
    expect(r.total_runs).toBe(1);
  });

  it('指定 version 時記到該版本', async () => {
    submissions.store.set('comp:cmp_abc12345:v2', JSON.stringify({
      component_hash_id: 'cmp_abc12345',
      canonical_id: 'http_request',
      version: 'v2',
      success_rate: 1, avg_duration_ms: 0, call_count: 0,
      visibility: 'public', status: 'active',
    }));
    const r = await recordAnalytics({ canonical_id: 'http_request', version: 'v2', success: false, duration_ms: 30 }, env);
    expect(r.ok).toBe(true);
    expect(r.version).toBe('v2');
    expect(analytics.store.has('stats:cmp_abc12345:v2')).toBe(true);
    expect(analytics.store.has('stats:cmp_abc12345:v1')).toBe(false);
  });

  it('不在索引的零件回 ok:false（誠實 404，不假綠）', async () => {
    const r = await recordAnalytics({ canonical_id: 'no_such_component', success: true, duration_ms: 1 }, env);
    expect(r.ok).toBe(false);
    expect(r.error).toContain('不在索引');
  });

  it('tombstone 版本不被記錄', async () => {
    submissions.store.set('comp:cmp_abc12345:v1', JSON.stringify({
      component_hash_id: 'cmp_abc12345', canonical_id: 'http_request', version: 'v1', status: 'tombstone',
    }));
    const r = await recordAnalytics({ canonical_id: 'http_request', success: true, duration_ms: 1 }, env);
    expect(r.ok).toBe(false);
  });
});
