import { readFile, stat } from "node:fs/promises";
import http, { type OutgoingHttpHeaders } from "node:http";
import path from "node:path";

interface SmokeBundleFixture {
  zipPath: string;
  fileName: string;
  skillId: string;
  skillTitle: string;
  skillDescription: string;
  configVersion: string;
  downloadUrl: string;
}

type SmokeBundleResponseHeaders = OutgoingHttpHeaders & {
  "Content-Type": string;
  "Content-Length": string;
  "Cache-Control": string;
  ETag: string;
  "Last-Modified": string;
}

function extractPromptText(value: unknown): string {
  if (typeof value === "string") {
    return value;
  }
  if (Array.isArray(value)) {
    return value
      .map((item) => extractPromptText(item))
      .filter(Boolean)
      .join("\n");
  }
  if (!value || typeof value !== "object") {
    return "";
  }

  const record = value as Record<string, unknown>;
  if (typeof record.text === "string") {
    return record.text;
  }
  if (typeof record.content === "string") {
    return record.content;
  }
  if (record.content) {
    return extractPromptText(record.content);
  }
  if (record.input) {
    return extractPromptText(record.input);
  }

  return "";
}

function buildSmokeReply(body: Record<string, unknown>): string {
  const messages = Array.isArray(body.messages) ? body.messages : [];
  const prompt = [...messages]
    .reverse()
    .map((message) => extractPromptText(message))
    .find((value) => value.trim().length > 0) || extractPromptText(body.input) || "smoke";

  return `Smoke stream ok: ${prompt.trim()}`;
}

async function pathExists(targetPath: string): Promise<boolean> {
  try {
    await stat(targetPath);
    return true;
  } catch {
    return false;
  }
}

async function resolveSmokeBundleFixture(baseUrl: string, defaultConfigVersion: string): Promise<SmokeBundleFixture | null> {
  const zipPath = process.env.QJCLAW_SMOKE_BUNDLE_ZIP_PATH?.trim();
  if (!zipPath) {
    return null;
  }
  if (!(await pathExists(zipPath))) {
    throw new Error(`Smoke bundle zip does not exist: ${zipPath}`);
  }

  const fileName = process.env.QJCLAW_SMOKE_BUNDLE_FILE_NAME?.trim() || path.basename(zipPath);
  const skillId = process.env.QJCLAW_SMOKE_BUNDLE_SKILL_ID?.trim() || "workspace-bundle";
  const skillTitle = process.env.QJCLAW_SMOKE_BUNDLE_SKILL_TITLE?.trim() || "Workspace Bundle";
  const skillDescription = process.env.QJCLAW_SMOKE_BUNDLE_SKILL_DESCRIPTION?.trim() || "Remote project bundle for smoke validation.";
  const configVersion = process.env.QJCLAW_SMOKE_BUNDLE_CONFIG_VERSION?.trim() || defaultConfigVersion;
  return {
    zipPath,
    fileName,
    skillId,
    skillTitle,
    skillDescription,
    configVersion,
    downloadUrl: `${baseUrl}/downloads/${encodeURIComponent(fileName)}`
  };
}

async function buildSmokeBundleHeaders(bundleFixture: SmokeBundleFixture): Promise<SmokeBundleResponseHeaders> {
  const bundleStat = await stat(bundleFixture.zipPath);
  const etag = `W/"${bundleStat.size.toString(16)}-${Math.trunc(bundleStat.mtimeMs).toString(16)}"`;
  return {
    "Content-Type": "application/zip",
    "Content-Length": String(bundleStat.size),
    "Cache-Control": "no-store",
    ETag: etag,
    "Last-Modified": bundleStat.mtime.toUTCString()
  };
}

export async function startSmokeCloudApiServer(baseUrl: string, token: string, runtimeApiKey = "smoke-runtime-api-key"): Promise<() => Promise<void>> {
  const url = new URL(baseUrl);
  const hostname = url.hostname;
  const port = Number(url.port || (url.protocol === "https:" ? 443 : 80));
  const providerToken = "runtime-provider-token";
  const providerBaseUrl = `${baseUrl}/openai/v1`;
  const defaultConfigVersion = "2026-03-23T20:00:00.000Z";
  const bundleFixture = await resolveSmokeBundleFixture(baseUrl, defaultConfigVersion);
  const currentVersion = bundleFixture?.configVersion ?? defaultConfigVersion;

  const server = http.createServer((req, res) => {
    const requestUrl = new URL(req.url || "/", `${url.protocol}//${url.host}`);
    const authHeader = req.headers.authorization || "";
    const bearerToken = authHeader.startsWith("Bearer ") ? authHeader.slice("Bearer ".length) : "";

    const sendJson = (status: number, payload: unknown) => {
      res.writeHead(status, { "Content-Type": "application/json; charset=utf-8" });
      res.end(JSON.stringify(payload));
    };

    const readJsonBody = async (): Promise<Record<string, unknown>> => {
      const chunks: Buffer[] = [];
      for await (const chunk of req) {
        chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
      }
      if (chunks.length === 0) {
        return {};
      }
      return JSON.parse(Buffer.concat(chunks).toString("utf8")) as Record<string, unknown>;
    };

    const sendChatCompletion = async (body: Record<string, unknown>) => {
      const replyText = buildSmokeReply(body);
      const created = Math.floor(Date.now() / 1000);
      const model = typeof body.model === "string" ? body.model : "gpt-5.4-mini";
      const completionId = `chatcmpl-smoke-${Date.now()}`;

      if (body.stream === true) {
        res.writeHead(200, {
          "Content-Type": "text/event-stream; charset=utf-8",
          "Cache-Control": "no-cache, no-transform",
          Connection: "keep-alive"
        });

        const parts = replyText.match(/.{1,10}/g) ?? [replyText];
        const writeChunk = (payload: unknown) => {
          res.write(`data: ${JSON.stringify(payload)}\n\n`);
        };

        writeChunk({
          id: completionId,
          object: "chat.completion.chunk",
          created,
          model,
          choices: [{ index: 0, delta: { role: "assistant" }, finish_reason: null }]
        });

        for (const part of parts) {
          writeChunk({
            id: completionId,
            object: "chat.completion.chunk",
            created,
            model,
            choices: [{ index: 0, delta: { content: part }, finish_reason: null }]
          });
          await new Promise((resolve) => setTimeout(resolve, 25));
        }

        writeChunk({
          id: completionId,
          object: "chat.completion.chunk",
          created,
          model,
          choices: [{ index: 0, delta: {}, finish_reason: "stop" }]
        });
        res.write("data: [DONE]\n\n");
        res.end();
        return;
      }

      sendJson(200, {
        id: completionId,
        object: "chat.completion",
        created,
        model,
        choices: [
          {
            index: 0,
            message: { role: "assistant", content: replyText },
            finish_reason: "stop"
          }
        ]
      });
    };

    const handleRequest = async () => {
      if ((req.method === "GET" || req.method === "HEAD") && bundleFixture && requestUrl.pathname === `/downloads/${encodeURIComponent(bundleFixture.fileName)}`) {
        const headers = await buildSmokeBundleHeaders(bundleFixture);
        if (req.method === "HEAD") {
          res.writeHead(200, headers);
          res.end();
          return;
        }
        const payload = await readFile(bundleFixture.zipPath);
        res.writeHead(200, headers);
        res.end(payload);
        return;
      }

      if (req.method === "POST" && requestUrl.pathname === "/openclaw-employee-config") {
        const body = await readJsonBody();
        const apiKey = typeof body.api_key === "string" ? body.api_key : "";
        const action = body.action === "init" ? "init" : "sync";
        const configVersion = typeof body.config_version === "string" ? body.config_version : undefined;

        if (apiKey !== runtimeApiKey) {
          sendJson(401, { message: "Invalid api_key or employee not found" });
          return;
        }

        if (action === "sync" && configVersion === currentVersion) {
          sendJson(200, { changed: false, config_version: currentVersion });
          return;
        }

        const remoteSkills = bundleFixture ? [
          {
            binding_id: `binding-${bundleFixture.skillId}`,
            skill_id: bundleFixture.skillId,
            skill_config: {},
            skill: {
              id: bundleFixture.skillId,
              title: bundleFixture.skillTitle,
              description: bundleFixture.skillDescription,
              category: "project",
              file_name: bundleFixture.fileName,
              file_size: (await stat(bundleFixture.zipPath)).size,
              download_url: bundleFixture.downloadUrl
            }
          }
        ] : [
          {
            binding_id: "binding-legal-research",
            skill_id: "legal-research",
            skill_config: {},
            skill: {
              id: "legal-research",
              title: "Legal Research",
              description: "Finds statutes and cases.",
              category: "research",
              file_name: "legal-research.skill.json",
              file_size: 1024,
              download_url: "https://example.invalid/legal-research.skill.json"
            }
          }
        ];

        sendJson(200, {
          changed: true,
          employee_id: "employee-smoke",
          name: "千匠问天 Smoke",
          status: "running",
          deployment_type: "local",
          persona_prompt: "You are 千匠问天, a highly capable general assistant. Help with Excel and spreadsheet analysis, information retrieval, research synthesis, task breakdown, and daily collaboration. When the user explicitly asks for Xiaohongshu or Douyin operations help, you may switch into the corresponding platform expert perspective. Default to the general assistant role unless the user clearly requests a platform-specific expert.",
          welcome_message: "你好，我是千匠问天。可以帮你处理 Excel、整理信息、检索资料、拆解任务；如果你需要，我也可以切换到小红书或抖音运营专家模式，协助你完成内容策划与运营工作。",
          work_hours: {
            start: null,
            end: null,
            is_24h: true
          },
          auto_reply_rules: [],
          resource_quota: {
            max_concurrency: 3
          },
          llm: {
            model_id: "gpt-5.4-mini",
            temperature: 0.2,
            max_tokens: 2048,
            display_name: "GPT-5.4 Mini",
            tier: "standard",
            credit_multiplier: 1,
            max_context_length: 200000,
            provider: {
              name: "Smoke OpenAI Compatible",
              base_url: providerBaseUrl,
              api_key: providerToken,
              provider_type: "openai_compatible"
            }
          },
          skills: remoteSkills,
          channels: [
            {
              id: "channel-web",
              type: "web",
              name: "Smoke Web",
              config: {
                enabled: true
              }
            }
          ],
          endpoints: {
            heartbeat: `${baseUrl}/openclaw-heartbeat`,
            events: `${baseUrl}/openclaw-employee-events`,
            config: `${baseUrl}/openclaw-employee-config`
          },
          config_version: currentVersion
        });
        return;
      }

      if (req.method === "POST" && requestUrl.pathname === "/openclaw-heartbeat") {
        const body = await readJsonBody();
        const apiKey = typeof body.api_key === "string" ? body.api_key : "";
        if (apiKey !== runtimeApiKey) {
          sendJson(401, { message: "Invalid api_key or employee not found" });
          return;
        }
        sendJson(200, {
          ok: true,
          employee_id: "employee-smoke",
          name: "Smoke Lobster",
          status: "running",
          heartbeat_at: new Date().toISOString(),
          billing: {
            success: true,
            token_delta: 0,
            credits_deducted: 0,
            balance_before: 88,
            balance_after: 88
          }
        });
        return;
      }

      if (req.method === "POST" && requestUrl.pathname === "/openclaw-employee-events") {
        const body = await readJsonBody();
        const apiKey = typeof body.api_key === "string" ? body.api_key : "";
        if (apiKey !== runtimeApiKey) {
          sendJson(401, { message: "Invalid api_key or employee not found" });
          return;
        }
        const events = Array.isArray(body.events) ? body.events : [];
        sendJson(200, { ok: true, accepted: events.length, failed: 0 });
        return;
      }

      if (req.method === "POST" && requestUrl.pathname === "/openclaw-daily-report") {
        const body = await readJsonBody();
        const apiKey = typeof body.api_key === "string" ? body.api_key : "";
        if (apiKey !== runtimeApiKey) {
          sendJson(401, { message: "Invalid api_key or employee not found" });
          return;
        }
        sendJson(200, {
          ok: true,
          summary_id: "summary-" + Date.now(),
          employee_id: "employee-smoke",
          summary_date: typeof body.summary_date === "string" ? body.summary_date : new Date().toISOString().slice(0, 10)
        });
        return;
      }

      if (req.method === "GET" && requestUrl.pathname === "/openai/v1/models") {
        if (bearerToken !== providerToken) {
          sendJson(401, { message: "Invalid provider token." });
          return;
        }
        sendJson(200, {
          object: "list",
          data: [
            { id: "gpt-5.4-mini", object: "model", created: 0, owned_by: "smoke" },
            { id: "gpt-5.4", object: "model", created: 0, owned_by: "smoke" }
          ]
        });
        return;
      }

      if (req.method === "POST" && requestUrl.pathname === "/openai/v1/chat/completions") {
        if (bearerToken !== providerToken) {
          sendJson(401, { message: "Invalid provider token." });
          return;
        }
        const body = await readJsonBody();
        await sendChatCompletion(body);
        return;
      }

      if (bearerToken !== token) {
        sendJson(401, { message: "Invalid cloud access token." });
        return;
      }

      if (req.method === "GET" && requestUrl.pathname === "/v1/auth/session") {
        sendJson(200, {
          user: { displayName: "Smoke User", email: "smoke.user@qianjiangclaw.local" },
          organization: { name: "Smoke Org" },
          expiresAt: new Date(Date.now() + 1000 * 60 * 60).toISOString()
        });
        return;
      }

      if (req.method === "GET" && requestUrl.pathname === "/v1/me/profile") {
        sendJson(200, {
          id: "user-smoke",
          displayName: "Smoke User",
          email: "smoke.user@qianjiangclaw.local",
          organizationName: "Smoke Org",
          title: "Installer MVP Tester"
        });
        return;
      }

      if (req.method === "GET" && requestUrl.pathname === "/v1/me/credits") {
        sendJson(200, {
          balance: 88,
          granted: 120,
          used: 32,
          updatedAt: new Date().toISOString(),
          expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24 * 14).toISOString()
        });
        return;
      }

      if (req.method === "GET" && requestUrl.pathname === "/v1/skills") {
        sendJson(200, {
          items: [
            { id: "legal-research", name: "Legal Research", description: "Finds statutes and cases.", category: "research", enabled: true, requiresCredits: 4 },
            { id: "contract-review", name: "Contract Review", description: "Runs clause review workflows.", category: "analysis", enabled: true, requiresCredits: 10 }
          ]
        });
        return;
      }

      if (req.method === "GET" && requestUrl.pathname === "/v1/model-config") {
        sendJson(200, {
          version: "smoke-model-policy-2026-03-23",
          updatedAt: new Date().toISOString(),
          routingMode: "skill-bound",
          fallbackMode: "last-known-cache",
          defaults: {
            chatModelId: "gpt-5.4-mini",
            chatModelLabel: "GPT-5.4 Mini",
            skillModelId: "gpt-5.4",
            skillModelLabel: "GPT-5.4"
          },
          items: [
            {
              id: "gpt-5.4-mini",
              label: "GPT-5.4 Mini",
              provider: "openai",
              family: "gpt-5.4",
              description: "Fast default desktop chat model.",
              enabled: true,
              contextWindow: 200000,
              maxOutputTokens: 32000,
              capabilities: ["chat", "reasoning", "tools"],
              recommendedFor: ["default", "chat"]
            },
            {
              id: "gpt-5.4",
              label: "GPT-5.4",
              provider: "openai",
              family: "gpt-5.4",
              description: "Higher-depth model reserved for curated Skills.",
              enabled: true,
              contextWindow: 200000,
              maxOutputTokens: 32000,
              capabilities: ["chat", "reasoning", "tools"],
              recommendedFor: ["skills", "analysis"]
            }
          ],
          skillBindings: [
            {
              skillId: "legal-research",
              skillName: "Legal Research",
              modelId: "gpt-5.4",
              modelLabel: "GPT-5.4",
              routingMode: "forced"
            },
            {
              skillId: "contract-review",
              skillName: "Contract Review",
              modelId: "gpt-5.4",
              modelLabel: "GPT-5.4",
              routingMode: "forced"
            }
          ]
        });
        return;
      }

      sendJson(404, { message: `Unknown endpoint: ${req.method} ${requestUrl.pathname}` });
    };

    void handleRequest().catch((error) => {
      sendJson(500, { message: error instanceof Error ? error.message : String(error) });
    });
  });

  await new Promise<void>((resolve, reject) => {
    server.once("error", reject);
    server.listen(port, hostname, () => {
      server.off("error", reject);
      resolve();
    });
  });

  return async () => {
    await new Promise<void>((resolve, reject) => {
      server.close((error) => {
        if (error) {
          reject(error);
          return;
        }
        resolve();
      });
    });
  };
}
