/**
 * P5 HTTP 接口:本地服务,POST 端点供外部系统/Agent 调用
 * - /convert   数据 → 笔记(run 等价)
 * - /compile   raw → wiki(LLM 编译)
 * - /query     基于 wiki 问答(可选归档)
 * - /session/* 会话记忆生命周期
 * - /memory/*  记忆写入/检索/提炼/确认
 * - /lint      wiki 健康检查
 * 仅监听 127.0.0.1(本地安全),可通过环境变量 WORK_VAULT_PORT 指定端口
 */
import * as http from "http";
import * as path from "path";
import type { Profile } from "./core/types";
import { renderSource } from "./core/engine";
import { FsWriter } from "./core/fsWriter";
import { applyNotes } from "./core/writer";
import { createProvider } from "./core/provider";
import type { LlmProvider } from "./core/provider";
import { compileRaw } from "./core/compiler";
import { queryWiki } from "./core/query";
import { writeClaims } from "./core/ledger";
import { lintWiki } from "./core/lint";
import {
  writeMemory,
  searchMemory,
  listMemory,
  captureMemory,
  confirmPending,
  listPendingMemory,
  sessionStart,
  sessionEnd,
} from "./core/memory";

export interface HttpServerOptions {
  vault: string;
  port?: number;
  profileDir?: string;
}

export function startServer(opts: HttpServerOptions): http.Server {
  const port = opts.port ?? Number(process.env.WORK_VAULT_PORT ?? 34567);

  const server = http.createServer((req, res) => {
    const send = (code: number, body: unknown) => {
      const json = JSON.stringify(body);
      res.writeHead(code, { "Content-Type": "application/json; charset=utf-8" });
      res.end(json);
    };

    if (req.method !== "POST") {
      send(405, { ok: false, error: "method not allowed" });
      return;
    }

    const chunks: Buffer[] = [];
    req.on("data", (c) => chunks.push(c as Buffer));
    req.on("end", async () => {
      try {
        const body = JSON.parse(Buffer.concat(chunks).toString("utf-8"));
        const pathname = (req.url ?? "/").split("?")[0];

        if (pathname === "/compile") {
          await handleCompile(body, send, opts.vault);
          return;
        }
        if (pathname === "/query") {
          await handleQuery(body, send, opts.vault);
          return;
        }
        // ★ 记忆层与健康检查(通用化新增)
        if (pathname === "/session/start") {
          await handleSessionStart(body, send, opts.vault);
          return;
        }
        if (pathname === "/session/end") {
          await handleSessionEnd(body, send, opts.vault);
          return;
        }
        if (pathname === "/memory/write") {
          await handleMemoryWrite(body, send, opts.vault);
          return;
        }
        if (pathname === "/memory/search") {
          await handleMemorySearch(body, send, opts.vault);
          return;
        }
        if (pathname === "/memory/list") {
          await handleMemoryList(body, send, opts.vault);
          return;
        }
        if (pathname === "/memory/capture") {
          await handleMemoryCapture(body, send, opts.vault);
          return;
        }
        if (pathname === "/memory/pending") {
          await handleMemoryPending(body, send, opts.vault);
          return;
        }
        if (pathname === "/lint") {
          await handleLint(body, send, opts.vault);
          return;
        }

        const data = body.data ?? "";
        const profileRef = body.profile ?? "person";
        const dryRun = body.dry_run === true;

        // profile:字符串(内置名)或对象(内联)
        let profile: Profile;
        if (typeof profileRef === "object" && profileRef !== null) {
          profile = profileRef as Profile;
        } else {
          const fs = await import("fs");
          const dirs = opts.profileDir
            ? [opts.profileDir]
            : [path.join(__dirname, "templates", "profiles"), path.join(__dirname, "examples")];
          let found: string | undefined;
          for (const d of dirs) {
            const direct = `${d}/${profileRef}.json`;
            if (fs.existsSync(direct)) { found = direct; break; }
            // examples/<pkg>/profiles/<name>.json
            if (fs.existsSync(d) && fs.statSync(d).isDirectory()) {
              for (const pkg of fs.readdirSync(d)) {
                const cand = path.join(d, pkg, "profiles", `${profileRef}.json`);
                if (fs.existsSync(cand)) { found = cand; break; }
              }
              if (found) break;
            }
          }
          if (!found) {
            send(400, { ok: false, error: `profile 不存在: ${profileRef}` });
            return;
          }
          profile = JSON.parse(fs.readFileSync(found, "utf-8")) as Profile;
        }

        const source = { kind: "json" as const, content: typeof data === "string" ? data : JSON.stringify(data) };
        const { notes, issues, warnings } = renderSource(source, profile);
        if (issues.length > 0) {
          send(400, { ok: false, issues, warnings });
          return;
        }

        const writer = new FsWriter(opts.vault);
        const existing = await writer.listExistingPaths();
        const result = await applyNotes(notes, writer, {
          dryRun,
          conflictStrategy: profile.conflictStrategy ?? "overwrite",
          existingPaths: existing,
        });
        send(200, { ok: true, written: result.written, skipped: result.skipped, errors: result.errors, dryRun });
      } catch (e) {
        send(500, { ok: false, error: (e as Error).message });
      }
    });
  });

  server.listen(port, "127.0.0.1", () => {
    console.log(`[workvault] HTTP 服务已启动: http://127.0.0.1:${port} (vault: ${opts.vault})`);
  });
  return server;
}

// 直接运行时:node dist/http.js --vault <dir> [--port <n>]
if (require.main === module) {
  const args = process.argv.slice(2);
  const vaultIdx = args.indexOf("--vault");
  const portIdx = args.indexOf("--port");
  const vault = vaultIdx >= 0 ? args[vaultIdx + 1] : undefined;
  if (!vault) {
    console.error("用法: node http.js --vault <dir> [--port <n>]");
    process.exit(2);
  }
  startServer({
    vault,
    port: portIdx >= 0 ? Number(args[portIdx + 1]) : undefined,
  });
}

// ===========================================================================
// POST /query:基于 wiki 回答(来源纪律),可选归档
//   body: { question, schema?, provider?, apiBase?, apiKey?, model?,
//           archive?, wikiDir?, dryRun? }
// ===========================================================================
async function handleQuery(
  body: Record<string, unknown>,
  send: (code: number, body: unknown) => void,
  vault: string,
): Promise<void> {
  try {
    const question = String(body.question ?? "").trim();
    if (!question) {
      send(400, { ok: false, error: "需要 question" });
      return;
    }
    let schema = body.schema ? String(body.schema) : "";
    if (!schema) {
      const fs = await import("fs");
      const p = require("path").join(__dirname, "templates", "schemas", "query.AGENTS.md");
      schema = fs.existsSync(p) ? fs.readFileSync(p, "utf-8") : "";
    }
    const provider = createProvider(String(body.provider ?? "echo"), {
      apiBase: body.apiBase ? String(body.apiBase) : undefined,
      apiKey: body.apiKey ? String(body.apiKey) : undefined,
      model: body.model ? String(body.model) : undefined,
    });
    const result = await queryWiki({
      provider,
      vault,
      question,
      schema,
      wikiDir: body.wikiDir ? String(body.wikiDir) : "wiki",
      archive: body.archive === true,
      dryRun: body.dry_run === true,
    });
    send(200, { ok: true, result });
  } catch (e) {
    send(500, { ok: false, error: (e as Error).message });
  }
}

// ===========================================================================
// POST /compile:raw 资料 + schema → LLM 编译 wiki
//   body: { schema(文本), input([{name,content}] 或 {text}),
//           provider?, apiBase?, apiKey?, model?, instruction?, wikiDir?, dryRun? }
// ===========================================================================
async function handleCompile(
  body: Record<string, unknown>,
  send: (code: number, body: unknown) => void,
  vault: string,
): Promise<void> {
  try {
    const schema = String(body.schema ?? "");
    const instruction = body.instruction ? String(body.instruction) : undefined;
    const providerKind = String(body.provider ?? "echo");
    const wikiDir = body.wikiDir ? String(body.wikiDir) : "wiki";
    const dryRun = body.dry_run === true;

    // input:数组 [{name, content}] 或单文本 {text}
    let inputs: Array<{ name: string; content: string }> = [];
    if (Array.isArray(body.input)) {
      inputs = (body.input as Array<Record<string, unknown>>).map((x) => ({
        name: String(x.name ?? "input"),
        content: String(x.content ?? ""),
      }));
    } else if (body.input && typeof body.input === "object" && "text" in (body.input as object)) {
      inputs = [{ name: "input.txt", content: String((body.input as { text: unknown }).text) }];
    }
    if (!schema || inputs.length === 0) {
      send(400, { ok: false, error: "需要 schema 与 input" });
      return;
    }

    const provider = createProvider(providerKind, {
      apiBase: body.apiBase ? String(body.apiBase) : undefined,
      apiKey: body.apiKey ? String(body.apiKey) : undefined,
      model: body.model ? String(body.model) : undefined,
    });

    const result = await compileRaw({
      provider,
      schema,
      inputs,
      instruction,
      vault,
      wikiDir,
      dryRun,
    });
    if (!dryRun && result.claims.length > 0) {
      writeClaims(vault, wikiDir, result.claims);
    }
    send(200, { ok: true, result });
  } catch (e) {
    send(500, { ok: false, error: (e as Error).message });
  }
}

// ===========================================================================
// ★ 记忆层:会话与记忆端点
// ===========================================================================

function httpProvider(body: Record<string, unknown>): LlmProvider {
  return createProvider(String(body.provider ?? "echo"), {
    apiBase: body.apiBase ? String(body.apiBase) : undefined,
    apiKey: body.apiKey ? String(body.apiKey) : undefined,
    model: body.model ? String(body.model) : undefined,
  });
}

/** POST /session/start:注入记忆上下文(纯读取) */
async function handleSessionStart(body: Record<string, unknown>, send: (code: number, body: unknown) => void, vault: string): Promise<void> {
  try {
    const context = sessionStart(vault, {
      project: body.project ? String(body.project) : undefined,
      focus: body.focus ? String(body.focus) : undefined,
      memoryDir: body.memory_dir ? String(body.memory_dir) : undefined,
    });
    send(200, { ok: true, context });
  } catch (e) {
    send(500, { ok: false, error: (e as Error).message });
  }
}

/** POST /session/end:写日志 + 重建概览 + 可选提炼 pending + 可选 git 提交 */
async function handleSessionEnd(body: Record<string, unknown>, send: (code: number, body: unknown) => void, vault: string): Promise<void> {
  try {
    const summary = String(body.summary ?? "").trim();
    if (!summary) {
      send(400, { ok: false, error: "需要 summary" });
      return;
    }
    let provider: LlmProvider | undefined;
    if (body.auto_capture === true) provider = httpProvider(body);
    const result = await sessionEnd(vault, {
      summary,
      project: body.project ? String(body.project) : undefined,
      agent: body.agent ? String(body.agent) : undefined,
      memoryDir: body.memory_dir ? String(body.memory_dir) : undefined,
      provider,
      autoCapture: body.auto_capture === true,
      autoCommit: body.auto_commit === true,
    });
    send(result.ok ? 200 : 500, result);
  } catch (e) {
    send(500, { ok: false, error: (e as Error).message });
  }
}

/** POST /memory/write:写入(或覆盖)一条记忆 */
async function handleMemoryWrite(body: Record<string, unknown>, send: (code: number, body: unknown) => void, vault: string): Promise<void> {
  try {
    const entry = (body.memory ?? body) as Record<string, unknown>;
    const type = String(entry.type ?? "");
    if (!type || !entry.title || !entry.description) {
      send(400, { ok: false, error: "需要 type/title/description" });
      return;
    }
    const r = writeMemory(
      vault,
      {
        type: type as never,
        title: String(entry.title),
        description: String(entry.description),
        content: String(entry.content ?? ""),
        project: entry.project ? String(entry.project) : undefined,
        agent: entry.agent ? String(entry.agent) : undefined,
        source: entry.source ? String(entry.source) : undefined,
        tags: Array.isArray(entry.tags) ? entry.tags.map(String) : undefined,
      },
      { memoryDir: body.memory_dir ? String(body.memory_dir) : undefined, dryRun: body.dry_run === true },
    );
    send(r.ok ? 200 : 409, r);
  } catch (e) {
    send(500, { ok: false, error: (e as Error).message });
  }
}

/** POST /memory/search:关键词检索 */
async function handleMemorySearch(body: Record<string, unknown>, send: (code: number, body: unknown) => void, vault: string): Promise<void> {
  try {
    const hits = searchMemory(
      vault,
      {
        query: body.query ? String(body.query) : undefined,
        type: body.type ? String(body.type) : undefined,
        project: body.project ? String(body.project) : undefined,
        limit: body.limit ? Number(body.limit) : undefined,
      },
      body.memory_dir ? String(body.memory_dir) : undefined,
    );
    send(200, { ok: true, hits });
  } catch (e) {
    send(500, { ok: false, error: (e as Error).message });
  }
}

/** POST /memory/list:列出全部(可按 type/project 过滤) */
async function handleMemoryList(body: Record<string, unknown>, send: (code: number, body: unknown) => void, vault: string): Promise<void> {
  try {
    const entries = listMemory(vault, { type: body.type ? String(body.type) : undefined, project: body.project ? String(body.project) : undefined }, body.memory_dir ? String(body.memory_dir) : undefined);
    send(200, { ok: true, entries });
  } catch (e) {
    send(500, { ok: false, error: (e as Error).message });
  }
}

/** POST /memory/capture:LLM 提炼候选记忆(默认写入 .pending/,preview=true 只预览) */
async function handleMemoryCapture(body: Record<string, unknown>, send: (code: number, body: unknown) => void, vault: string): Promise<void> {
  try {
    const text = String(body.text ?? "").trim();
    if (!text) {
      send(400, { ok: false, error: "需要 text" });
      return;
    }
    const cap = await captureMemory(vault, {
      provider: httpProvider(body),
      text,
      project: body.project ? String(body.project) : undefined,
      agent: body.agent ? String(body.agent) : undefined,
      memoryDir: body.memory_dir ? String(body.memory_dir) : undefined,
      writePending: body.preview !== true,
    });
    send(200, { ok: !cap.error, ...cap });
  } catch (e) {
    send(500, { ok: false, error: (e as Error).message });
  }
}

/** POST /memory/pending:列出挂起(默认);action=confirm 时用 name 确认入库 */
async function handleMemoryPending(body: Record<string, unknown>, send: (code: number, body: unknown) => void, vault: string): Promise<void> {
  try {
    const memoryDir = body.memory_dir ? String(body.memory_dir) : undefined;
    if (body.action === "confirm") {
      const name = String(body.name ?? "");
      if (!name) {
        send(400, { ok: false, error: "confirm 需要 name" });
        return;
      }
      const r = confirmPending(vault, name, { memoryDir });
      send(r.ok ? 200 : 404, r);
      return;
    }
    const pending = listPendingMemory(vault, memoryDir);
    send(200, { ok: true, pending });
  } catch (e) {
    send(500, { ok: false, error: (e as Error).message });
  }
}

/** POST /lint:wiki 健康检查 */
async function handleLint(body: Record<string, unknown>, send: (code: number, body: unknown) => void, vault: string): Promise<void> {
  try {
    const issues = lintWiki(vault, body.wiki_dir ? String(body.wiki_dir) : "wiki");
    send(200, { ok: true, issues });
  } catch (e) {
    send(500, { ok: false, error: (e as Error).message });
  }
}