import { getRuntimeEnv } from "../../../lib/runtime-env";
import {
  createMcpHandler,
  McpServer,
  type McpRequestContext,
} from "@modelcontextprotocol/server";
import { z } from "zod/v4";
import {
  FeishuSourceError,
  type FeishuBindings,
} from "../../../lib/feishu-client";
import {
  buildClaimUrl,
  createDistributionTask,
} from "../../../lib/task-service";
import { registerMcpOperationTools } from "../../../lib/mcp-tools";
import type { CollectionMcpBindings } from "../../../lib/mcp-collection-client";

const env = getRuntimeEnv();

type McpBindings = FeishuBindings & CollectionMcpBindings & {
  KOC_MCP_API_KEY?: string;
  KOC_LOOP_MCP_API_KEY?: string;
  KOC_PORTAL_URL?: string;
};

const toolOutputSchema = z.object({
  created: z.boolean(),
  task_id: z.string(),
  task_name: z.string(),
  brand_project: z.string(),
  due_date: z.string(),
  sheet_name: z.string(),
  note_count: z.number().int().nonnegative(),
  platform: z.enum(["小红书", "抖音"]),
  content_format: z.enum(["image_text", "video"]),
  claim_url: z.string().url(),
});

function getBindings() {
  return env as unknown as McpBindings;
}

function createServer(context: McpRequestContext) {
  const bindings = getBindings();
  const origin = context.requestInfo
    ? new URL(context.requestInfo.url).origin
    : "";
  const server = new McpServer(
    { name: "koc-loop", version: "2.0.0" },
    {
      instructions:
        "用于创建和管理 KOC 内容分发任务、数据回收、公开数据采集与账号资源。创建任务前确认飞书链接、任务名和北京时间截止日期；写操作应先向用户说明影响。相同参数的任务创建和采集计划设置支持安全重试。",
    },
  );

  server.registerTool(
    "create_distribution_task",
    {
      title: "创建 KOC 分发任务",
      description:
        "读取飞书电子表格中的标题、正文及图片或视频，在 KOC LOOP 创建小红书/抖音分发任务，并返回可直接发给 KOC 的领取链接。飞书表格若有多个工作表，链接必须包含目标 sheet 参数。",
      inputSchema: z.object({
        feishu_url: z
          .string()
          .url()
          .describe("飞书 Wiki 或电子表格链接，建议包含目标 sheet 参数"),
        task_name: z.string().min(1).max(100).describe("分发任务名称"),
        due_date: z
          .string()
          .regex(/^\d{4}-\d{2}-\d{2}$/)
          .describe("北京时间截止日期，格式为 YYYY-MM-DD"),
        brand_project: z
          .string()
          .min(1)
          .max(100)
          .optional()
          .describe("品牌或项目名称；未提供时系统记录为“未设置项目”"),
        platform: z
          .enum(["小红书", "抖音"])
          .optional()
          .describe("发布平台，默认小红书"),
        content_format: z
          .enum(["image_text", "video"])
          .optional()
          .describe("内容形式：image_text 图文，video 视频；默认图文"),
      }),
      outputSchema: toolOutputSchema,
      annotations: {
        readOnlyHint: false,
        destructiveHint: false,
        idempotentHint: true,
        openWorldHint: true,
      },
    },
    async ({ feishu_url, task_name, due_date, brand_project, platform, content_format }) => {
      try {
        const bindings = getBindings();
        const portalUrl = String(bindings.KOC_PORTAL_URL ?? "").trim();
        if (!portalUrl) {
          throw new Error("KOC 领取站点地址尚未配置");
        }
        const result = await createDistributionTask(
          {
            feishuUrl: feishu_url,
            name: task_name,
            brand: brand_project?.trim() || "未设置项目",
            dueAt: due_date,
            platform: platform ?? "小红书",
            contentFormat: content_format ?? "image_text",
          },
          bindings,
          { deduplicate: true },
        );
        const output = {
          created: result.created,
          task_id: result.taskId,
          task_name: result.name,
          brand_project: result.brand,
          due_date: result.dueAt,
          sheet_name: result.sheetName,
          note_count: result.noteCount,
          platform: result.platform,
          content_format: result.contentFormat,
          claim_url: buildClaimUrl(portalUrl, result.shareToken),
        };
        const actionText = result.created ? "已创建" : "已找到相同任务";
        return {
          content: [
            {
              type: "text",
              text: `${actionText}“${result.name}”，平台：${result.platform}，内容形式：${result.contentFormat === "video" ? "视频" : "图文"}，共 ${result.noteCount} 篇。领取链接：${output.claim_url}`,
            },
          ],
          structuredContent: output,
        };
      } catch (error) {
        const message =
          error instanceof FeishuSourceError
            ? error.message
            : error instanceof Error &&
                [
                  "KOC 领取站点地址尚未配置",
                  "截止日期必须使用 YYYY-MM-DD 格式",
                  "截止日期无效",
                  "请补全飞书链接、任务名称和品牌/项目",
                ].includes(error.message)
              ? error.message
              : "创建任务失败，请稍后重试或联系系统管理员";
        return {
          isError: true,
          content: [{ type: "text", text: message }],
        };
      }
    },
  );

  registerMcpOperationTools(server, { bindings, origin });

  return server;
}

const mcpHandler = createMcpHandler(createServer, {
  legacy: "stateless",
  responseMode: "json",
});

async function secretDigest(value: string) {
  return new Uint8Array(
    await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value)),
  );
}

async function secretsMatch(received: string, expected: string) {
  const [left, right] = await Promise.all([
    secretDigest(received),
    secretDigest(expected),
  ]);
  let difference = left.length ^ right.length;
  for (let index = 0; index < Math.max(left.length, right.length); index += 1) {
    difference |= (left[index] ?? 0) ^ (right[index] ?? 0);
  }
  return difference === 0;
}

function responseHeaders(response: Response, request: Request) {
  const headers = new Headers(response.headers);
  const origin = request.headers.get("Origin");
  if (origin) headers.set("Access-Control-Allow-Origin", origin);
  headers.set("Vary", "Origin");
  headers.set(
    "Access-Control-Expose-Headers",
    "Mcp-Session-Id, WWW-Authenticate",
  );
  return new Response(response.body, {
    status: response.status,
    statusText: response.statusText,
    headers,
  });
}

function originRejected(request: Request) {
  const origin = request.headers.get("Origin");
  return Boolean(origin && origin !== new URL(request.url).origin);
}

async function authorize(request: Request) {
  const bindings = getBindings();
  const expected = String(
    bindings.KOC_MCP_API_KEY ?? bindings.KOC_LOOP_MCP_API_KEY ?? "",
  ).trim();
  const authorization = request.headers.get("Authorization") ?? "";
  const match = authorization.match(/^Bearer\s+(.+)$/i);
  if (!expected || !match || !(await secretsMatch(match[1].trim(), expected))) {
    return new Response("Unauthorized", {
      status: 401,
      headers: { "WWW-Authenticate": 'Bearer realm="KOC LOOP MCP"' },
    });
  }
  return null;
}

async function handle(request: Request) {
  if (originRejected(request)) {
    return new Response("Forbidden origin", { status: 403 });
  }
  const unauthorized = await authorize(request);
  if (unauthorized) return responseHeaders(unauthorized, request);
  return responseHeaders(await mcpHandler.fetch(request), request);
}

export async function OPTIONS(request: Request) {
  if (originRejected(request)) {
    return new Response("Forbidden origin", { status: 403 });
  }
  return new Response(null, {
    status: 204,
    headers: {
      "Access-Control-Allow-Origin":
        request.headers.get("Origin") ?? new URL(request.url).origin,
      "Access-Control-Allow-Methods": "POST, GET, DELETE, OPTIONS",
      "Access-Control-Allow-Headers":
        "Authorization, Content-Type, MCP-Protocol-Version, Mcp-Session-Id, Last-Event-ID, Mcp-Name, Mcp-Method",
      "Access-Control-Max-Age": "86400",
      Vary: "Origin",
    },
  });
}

export const POST = handle;
export const GET = handle;
export const DELETE = handle;
