// Component Registry Worker 型別定義

import { z } from 'zod';

// ── Cloudflare Bindings ──────────────────────────────────────────────────────

export type Bindings = {
  AI: Ai;
  // KV key 格式：
  //   comp:{hash_id}:{version}   → 零件元數據（hash_id = cmp_ + sha256 前 8 碼）
  //   idx:{canonical_id}         → canonical_id → hash_id 反查索引
  SUBMISSIONS_KV: KVNamespace;
  ANALYTICS_KV: KVNamespace;   // 執行統計匯總（key = stats:{hash_id}:{version}）
  ENVIRONMENT: string;
};

// ── Component Contract Schema（Zod）─────────────────────────────────────────

// max_cold_start_ms 上限放寬至 500（從 50）：實測 auth/ai 類零件含 crypto/init 步驟通常 100-300ms
// no_network_syscall / no_filesystem_syscall 都改 optional：auth/api 類零件需要網路 syscall
export const ConstraintsSchema = z.object({
  max_size_kb: z.number().positive().max(8192),
  max_cold_start_ms: z.number().positive().max(500),
  no_network_syscall: z.boolean().optional(),
  no_filesystem_syscall: z.boolean().optional(),
  io_model: z.literal('stdin_stdout_json'),
});

export const GherkinTestSchema = z.object({
  scenario: z.string().min(1),
  given: z.string().min(1),
  then_contains: z.string().min(1),
});

export const ComponentContractSchema = z.object({
  // canonical_id：提交者填寫的可讀名稱（小寫底線），用於搜尋與 workflow 引用
  // component_hash_id：由 Registry 在提交時派發，格式 cmp_{8碼hex}，workflow 引用此 id 才能保證永久不壞
  // 兩者都可以在 workflow 中引用，Registry 會互相解析
  canonical_id: z.string().min(1).regex(/^[a-z][a-z0-9_]*$/, 'canonical_id 必須為小寫底線格式'),
  display_name: z.string().min(1),
  // category 擴充：auth (auth primitive)、ai (Claude/AI 推論)、platform (平台底層 crypto/system)
  category: z.enum(['logic', 'api', 'ui', 'style', 'anim', 'data', 'auth', 'ai', 'platform']),
  version: z.string().min(1).regex(/^v\d+$/, 'version 格式必須為 vN'),
  wasi_target: z.literal('preview1'),
  stability: z.enum(['floating', 'stable', 'pinned']),
  runtime_compat: z.array(z.enum(['cf-workers', 'workerd', 'wazero'])).min(1),
  constraints: ConstraintsSchema,
  input_schema: z.record(z.unknown()),
  output_schema: z.record(z.unknown()),
  gherkin_tests: z.array(GherkinTestSchema).min(2, '至少需要一個 happy path 和一個 error path'),
  // 選填欄位
  component_type: z.enum(['wasm', 'service_binding']).optional(),
  max_size_kb: z.number().optional(),
  max_cold_start_ms: z.number().optional(),
  no_network_syscall: z.boolean().optional(),
  service_binding_key: z.string().optional(),
  description: z.string().optional(),
  // aliases：搜尋同義詞，不作為識別符使用
  // 從 registry/aliases.yaml 的 scope 同義詞表自動合併，也可在 contract 內手動補充
  // 未來接入 KBDB 後，canonical_id 將獲得系統派發的唯一 hash id
  aliases: z.array(z.string()).optional(),
  tags: z.array(z.string()).optional(),
});

export type ComponentContract = z.infer<typeof ComponentContractSchema>;

// ── 沙盒驗收步驟 ─────────────────────────────────────────────────────────────

export type SandboxStep = 'fake_component_scan' | 'size_check' | 'cold_start' | 'syscall_scan' | 'gherkin_tests' | 'runtime_compat';

export interface SandboxResult {
  success: boolean;
  failed_step?: SandboxStep;
  reason?: string;
  guide_anchor?: string;
  // 未真正驗證的步驟（mock，禁假綠 §3c/§7）。success 仍可能為 true，但這些步驟沒實際跑。
  unimplemented_steps?: SandboxStep[];
  // 驗收通過後回傳兩個 id：
  component_hash_id: string;  // cmp_{8碼hex}，workflow 引用用，永久不變
  canonical_id: string;       // 可讀名稱，搜尋用
  version: string;
}

// ── KBDB Block 格式 ──────────────────────────────────────────────────────────

export interface KbdbBlock {
  block_id: string;
  template_id: string;
  user_id?: string;
  page_name?: string;
}

export interface KbdbSlots {
  [key: string]: string;
}

// ── 禁止的 WASM syscall（網路 + 檔案系統）────────────────────────────────────

export const FORBIDDEN_SYSCALLS = [
  'sock_connect',
  'sock_accept',
  'sock_recv',
  'sock_send',
  'sock_shutdown',
  'fd_open',
  'path_open',
  'path_create_directory',
  'path_remove_directory',
  'path_rename',
  'path_unlink_file',
  'path_filestat_get',
  'path_filestat_set_times',
  'path_link',
  'path_readlink',
  'path_symlink',
] as const;
