import { randomUUID } from "node:crypto";
import { join } from "node:path";
import type { ToolContext } from "../agent/tools.js";
import { downloadMessageFile, type FeishuRuntime } from "./client.js";

export interface FeishuMessageResourceArgs {
  readonly messageId: string;
  readonly fileKey: string;
  readonly resourceType: "image" | "file";
}

export interface DownloadedFeishuMessageResource extends FeishuMessageResourceArgs {
  readonly path: string;
}

type DownloadContext = Pick<ToolContext, "boundChatId" | "workspaceDir"> & { readonly workspaceRoot: string };

interface MessageLookupResult {
  readonly data?: {
    readonly message?: { readonly chat_id?: string | undefined } | undefined;
    readonly items?: ReadonlyArray<{ readonly chat_id?: string | undefined }> | undefined;
  } | undefined;
}

/** Download one resource after proving its message belongs to the run's bound chat. */
export async function downloadFeishuMessageResource(
  args: FeishuMessageResourceArgs,
  context: DownloadContext,
  rt: FeishuRuntime,
): Promise<DownloadedFeishuMessageResource> {
  const response = await rt.client.im.v1.message.get({
    path: { message_id: args.messageId },
  }) as MessageLookupResult;
  const message = response.data?.message ?? response.data?.items?.[0];
  if (message === undefined) {
    throw new Error(`Feishu message not found: ${args.messageId}`);
  }
  if (message.chat_id !== context.boundChatId) {
    rt.logger.warn(
      { messageId: args.messageId, boundChatId: context.boundChatId, returnedChatId: message.chat_id },
      "Feishu resource download refused outside bound chat",
    );
    throw new Error(
      `refused Feishu resource download: message ${args.messageId} is not in the current project's bound chat`,
    );
  }

  const extension = args.resourceType === "image" ? ".png" : ".bin";
  const workspaceRelativePath = join(
    ".cph",
    "inbox",
    `feishu-${args.resourceType}-${randomUUID()}${extension}`,
  );
  const savePath = await downloadMessageFile(
    rt,
    args.messageId,
    args.fileKey,
    context.workspaceRoot,
    context.workspaceDir,
    workspaceRelativePath,
    args.resourceType,
  );
  return { ...args, path: savePath };
}
