// arcrun cypher-executor Worker — AI 工作流執行引擎
import { Hono } from 'hono';
import { cors } from 'hono/cors';
import type { ExecutionContext } from '@cloudflare/workers-types';
import type { Bindings } from './types';
import { handleScheduled } from './scheduled';
import { healthRouter } from './routes/health';
import { executeRouter } from './routes/execute';
import { cypherRouter } from './routes/cypher';
import { validateRouter } from './routes/validate';
import { docsRouter } from './routes/docs';
import { webhooksRouter } from './routes/webhooks';
import { webhooksCrudRouter } from './routes/webhooks-crud';
import { webhooksListRouter } from './routes/webhooks-list';
import { recipesRouter } from './routes/recipes';
import { credentialsRouter } from './routes/credentials';
import { webhooksNamedRouter } from './routes/webhooks-named';
import { authRouter } from './routes/auth';
import { resumeRouter } from './routes/resume';
import { executionsRouter } from './routes/executions';
import { initSeedRouter } from './routes/init-seed';
import { kbdbProxyRouter } from './routes/kbdb-proxy';
import { consoleAuthRouter } from './routes/console-auth';
import { consoleDashboardRouter } from './routes/console-dashboard';
import { portalRouter } from './routes/portal';
import { portalDataRouter } from './routes/portal-data';

const app = new Hono<{ Bindings: Bindings }>();

// 全域 CORS（允許 arcrun.dev landing page 帶 credentials 存取）
//
// 2026-07-21 cypher-ui-split：console/portal UI 搬到 Cloudflare Pages 後，前端與本 API
// **不再同源**，故 UI 站的 origin 必須進白名單，否則所有 fetch 會被瀏覽器擋。
// 允許來源＝上面兩個 landing + UI_ORIGINS（wrangler.toml [vars] 逗號分隔，實例自填
// 自己的 Pages 網域，如 https://arcrun-console-ui.pages.dev）。
// 刻意不用萬用字元：credentials:true 與 `*` 在 CORS 規格上互斥，且 Authorization/
// X-Arcrun-API-Key 是憑證等級標頭，開全域等於誰都能代打。
const STATIC_ORIGINS = ['https://arcrun.dev', 'https://www.arcrun.dev'];

app.use('*', cors({
  origin: (origin, c) => {
    // ⚠️ 非瀏覽器請求（CLI／curl／MCP）沒有 Origin 標頭 → origin 是空字串/undefined。
    //    此時必須原樣放行，不能回 null——回 null 會讓 Hono cors 中介層在後續處理拋錯，
    //    表現為所有 CLI 部署一律 500（2026-07-21 實撞：acr push 全掛，對照組亦然）。
    if (!origin) return origin;
    let extra: string[] = [];
    try {
      extra = String((c.env as Record<string, unknown>).UI_ORIGINS || '')
        .split(',').map((s: string) => s.trim()).filter(Boolean);
    } catch { /* UI_ORIGINS 未設定＝只用靜態白名單 */ }

    // 🔴 2026-08-08 事故根因修復：**同一台實例的 portal 一律自動放行，不再依賴注入**。
    //
    // 那天發生什麼：leo 的 youlin 實例 portal 整個不能用——先是畫面頂端紅字
    // 「設定檔沒載入（config.js）」（UI worker 缺 WORKER_SUBDOMAIN），修好之後**登入仍然失敗**。
    // 瀏覽器 console 實證：
    //   Access to fetch at '…/portal/login' … blocked by CORS policy:
    //   No 'Access-Control-Allow-Origin' header is present
    // 真因＝這台的 `UI_ORIGINS` 沒被設。
    //
    // 兩次同一個病：**這些變數只有安裝器那條路會注入，任何人手動 `wrangler deploy` 就會漏掉——
    // 而漏掉時系統看起來完全正常**（worker 上線、HTTP 200、版本號還是對的），
    // 只有真人點下去才會發現。leo：「這麼危險的問題已經發生 2 次，不可以再有一次。」
    //
    // ⇒ 治法不是「記得要注入」，是**讓它不需要被注入**：
    //    portal 與本 worker 是同一個 workers.dev 子網域下的兄弟，位址推導得出來。
    //    **少一個必須注入的變數，就少一個會被漏掉的東西。**
    //    `UI_ORIGINS` 仍然有效（自訂網域／額外前端還是靠它），只是不再是「登得進去」的前提。
    const sub = String((c.env as Record<string, unknown>).WORKER_SUBDOMAIN || '').trim();
    const sibling = sub ? [`https://arcrun-rag-ui.${sub}.workers.dev`] : [];

    return [...STATIC_ORIGINS, ...sibling, ...extra].includes(origin) ? origin : null;
  },
  allowMethods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
  allowHeaders: ['Content-Type', 'Authorization', 'X-Arcrun-API-Key'],
  credentials: true,
}));

// 掛載所有路由器
app.route('/', docsRouter);
app.route('/', healthRouter);
app.route('/', executeRouter);
app.route('/', cypherRouter);
app.route('/', validateRouter);
app.route('/', webhooksRouter);
app.route('/', webhooksNamedRouter);   // 必須在 webhooksCrudRouter 前（避免 /webhooks/:token 攔截 /webhooks/named）
app.route('/', webhooksCrudRouter);
app.route('/', webhooksListRouter);
app.route('/', recipesRouter);
app.route('/', credentialsRouter);
app.route('/', authRouter);
app.route('/', resumeRouter);
app.route('/', executionsRouter);  // LI SDD M2.1: /executions/* + /workflows/:name/executions
app.route('/', initSeedRouter);    // 薄殼原則：seed recipe 是 API 行為（rule 07，壓測 §4.1）
app.route('/', kbdbProxyRouter);   // kbdb-base 9.5：KBDB 資料層 proxy（讓 CLI 透過 cypher 達 KBDB，純轉發）
app.route('/', consoleAuthRouter); // Arcrun#3 發現②：console 專用簡單 email+password 登入（單一管理員帳密，非多租戶）
app.route('/', consoleDashboardRouter); // T-cockpit ②：駕駛艙 dashboard（聚合 KBDB dash_* entries，無需登入唯讀）
app.route('/', portalRouter);      // portal-auth P2（#24/#25）：RAG Portal 多人授權——用戶模型＋認證 API
app.route('/', portalDataRouter);  // portal-auth P3：/portal/data/* server-side enforce（owner_id＋library 注入，安全核心）

// Worker 導出（fetch + scheduled）
// scheduled handler 對應 wrangler.toml [triggers].crons，每分鐘 tick；
// 邏輯在 src/scheduled.ts。對應 SDD: arcrun.md 三-A P1 #3。
export default {
  fetch: app.fetch,
  scheduled: handleScheduled,
} satisfies ExportedHandler<Bindings>;
