/*
 * SPEC: PJ2026-010403 API契约 draft-2026-06-17-r0; PJ2026-0102 Agent编排 draft-2026-06-17-r0
 * 职责: Cloud runtime durable schema contract。Workbench/Code Agent 投影表必须纳入启动 readiness 和迁移一致性检查。
 */
import { TABLES } from "../protocol/index.mjs";

export const CLOUD_CORE_MIGRATION_ID = "0001_cloud_core_skeleton";
export const CLOUD_RUNTIME_DURABLE_ADAPTER_SCHEMA_VERSION = "runtime-durable-postgres-v5";
export const CLOUD_RUNTIME_DURABLE_MIGRATION_TABLE = "hwlab_schema_migrations";

export const FROZEN_CLOUD_CORE_TABLES = Object.freeze([...TABLES]);

export const CLOUD_RUNTIME_DURABLE_MIGRATION_TABLE_COLUMNS = Object.freeze([
  "id",
  "schema_version",
  "applied_at",
  "migration_json"
]);

export const CLOUD_RUNTIME_DURABLE_TABLE_COLUMNS = Object.freeze({
  users: Object.freeze([
    "id",
    "username",
    "display_name",
    "role",
    "status",
    "password_hash",
    "created_at",
    "updated_at"
  ]),
  user_sessions: Object.freeze([
    "id",
    "user_id",
    "session_token_hash",
    "created_at",
    "last_seen_at",
    "expires_at",
    "revoked_at"
  ]),
  gateway_sessions: Object.freeze([
    "id",
    "project_id",
    "gateway_service_id",
    "status",
    "started_at",
    "ended_at",
    "gateway_session_json"
  ]),
  box_resources: Object.freeze([
    "id",
    "project_id",
    "gateway_session_id",
    "resource_state",
    "labels_json",
    "resource_json",
    "updated_at"
  ]),
  box_capabilities: Object.freeze([
    "id",
    "box_resource_id",
    "capability_type",
    "capability_json",
    "updated_at"
  ]),
  hardware_operations: Object.freeze([
    "id",
    "project_id",
    "requested_by",
    "operation_type",
    "operation_json",
    "status",
    "requested_at",
    "updated_at"
  ]),
  audit_events: Object.freeze([
    "id",
    "request_id",
    "actor",
    "source",
    "operation",
    "target",
    "result",
    "timestamp",
    "event_json"
  ]),
  evidence_records: Object.freeze([
    "id",
    "project_id",
    "operation_id",
    "evidence_type",
    "uri",
    "metadata_json",
    "created_at"
  ]),
  agent_sessions: Object.freeze([
    "id",
    "project_id",
    "agent_id",
    "status",
    "started_at",
    "ended_at",
    "owner_user_id",
    "conversation_id",
    "thread_id",
    "last_trace_id",
    "session_json",
    "updated_at"
  ]),
  account_workspaces: Object.freeze([
    "id",
    "owner_user_id",
    "project_id",
    "name",
    "status",
    "is_default",
    "selected_conversation_id",
    "selected_agent_session_id",
    "active_trace_id",
    "provider_profile",
    "workspace_json",
    "revision",
    "updated_by_session_id",
    "updated_by_client",
    "created_at",
    "updated_at"
  ]),
  worker_sessions: Object.freeze([
    "id",
    "agent_session_id",
    "worker_id",
    "status",
    "started_at",
    "ended_at"
  ]),
  agent_trace_events: Object.freeze([
    "id",
    "trace_id",
    "agent_session_id",
    "worker_session_id",
    "level",
    "message",
    "event_json",
    "occurred_at"
  ]),
  workbench_projection_state: Object.freeze([
    "trace_id",
    "session_id",
    "conversation_id",
    "thread_id",
    "run_id",
    "command_id",
    "last_agentrun_seq",
    "last_projected_seq",
    "upstream_latest_seq",
    "projection_status",
    "projection_health",
    "result_sync_state",
    "last_projected_at",
    "last_result_sync_at",
    "last_error_code",
    "last_error_message",
    "failure_count",
    "next_retry_at",
    "projection_json",
    "created_at",
    "updated_at"
  ]),
  workbench_sessions: Object.freeze([
    "session_id",
    "owner_user_id",
    "project_id",
    "conversation_id",
    "thread_id",
    "status",
    "last_trace_id",
    "projected_seq",
    "source_seq",
    "source_event_id",
    "terminal",
    "sealed",
    "session_json",
    "created_at",
    "updated_at"
  ]),
  workbench_messages: Object.freeze([
    "message_id",
    "session_id",
    "turn_id",
    "trace_id",
    "role",
    "status",
    "projected_seq",
    "source_seq",
    "source_event_id",
    "terminal",
    "sealed",
    "message_json",
    "created_at",
    "updated_at"
  ]),
  workbench_parts: Object.freeze([
    "part_id",
    "message_id",
    "session_id",
    "turn_id",
    "trace_id",
    "part_index",
    "part_type",
    "status",
    "projected_seq",
    "source_seq",
    "source_event_id",
    "terminal",
    "sealed",
    "part_json",
    "created_at",
    "updated_at"
  ]),
  workbench_turns: Object.freeze([
    "turn_id",
    "session_id",
    "trace_id",
    "message_id",
    "status",
    "projected_seq",
    "source_seq",
    "source_event_id",
    "terminal",
    "sealed",
    "final_response_json",
    "diagnostic_json",
    "turn_json",
    "created_at",
    "updated_at"
  ]),
  workbench_trace_events: Object.freeze([
    "id",
    "trace_id",
    "session_id",
    "turn_id",
    "message_id",
    "source_seq",
    "source_event_id",
    "projected_seq",
    "event_type",
    "terminal",
    "sealed",
    "event_json",
    "occurred_at",
    "updated_at"
  ]),
  workbench_projection_checkpoints: Object.freeze([
    "trace_id",
    "session_id",
    "turn_id",
    "run_id",
    "command_id",
    "projected_seq",
    "source_seq",
    "source_event_id",
    "projection_status",
    "projection_health",
    "terminal",
    "sealed",
    "diagnostic_json",
    "checkpoint_json",
    "created_at",
    "updated_at"
  ]),
  workbench_projection_outbox: Object.freeze([
    "outbox_seq",
    "trace_id",
    "session_id",
    "turn_id",
    "message_id",
    "projected_seq",
    "source_seq",
    "source_event_id",
    "commit_type",
    "terminal",
    "sealed",
    "payload_json",
    "created_at"
  ])
});

export const CLOUD_CORE_MIGRATIONS = Object.freeze([
  {
    id: CLOUD_CORE_MIGRATION_ID,
    path: "internal/db/migrations/0001_cloud_core_skeleton.sql",
    tables: FROZEN_CLOUD_CORE_TABLES,
    connectsToDatabase: false,
    runtimeDurableAdapterSchemaVersion: CLOUD_RUNTIME_DURABLE_ADAPTER_SCHEMA_VERSION,
    runtimeDurableMigrationTable: CLOUD_RUNTIME_DURABLE_MIGRATION_TABLE
  }
]);

export function assertFrozenCloudCoreTables(tables = FROZEN_CLOUD_CORE_TABLES) {
  const missing = TABLES.filter((table) => !tables.includes(table));
  if (missing.length > 0) {
    throw new Error(`cloud core schema is missing frozen tables: ${missing.join(", ")}`);
  }
}

export function requiredRuntimeDurableColumns() {
  return Object.entries(CLOUD_RUNTIME_DURABLE_TABLE_COLUMNS).flatMap(([table, columns]) =>
    columns.map((column) => `${table}.${column}`)
  );
}
