/**
 * Attachment tool definitions shared across providers.
 * These definitions describe the metadata and business logic for attachment helpers
 * without binding to a particular agent SDK. Providers can adapt the definitions
 * into concrete tool implementations for their runtime (OpenAI Agents, MCP, etc.).
 */
const DATA_URL_MAX_PREVIEW_CHARS = 512;
export const ATTACHMENT_TOOLS_PREAMBLE = `
  The user can attach files to the conversation using the chat UI.
  Only use the tools "get_last_file", "list_cached_files", and "get_cached_file" to access information about these attachments.
  Do not make up file names or attachment ids; only use ones that have been provided by the tools.
  Never attempt to access or retrieve the contents of a file directly; these tools only provide metadata about the files.
  If the user references a file but does not specify which one, use "get_last_file" to retrieve information about the most recently added attachment.
  If the user wants to see a list of their uploaded files, use "list_cached_files" to get metadata for all attachments in the current conversation.
  To get information about a specific attachment, use "get_cached_file" with the attachment id provided by "list_cached_files".
`;
const LIST_CACHED_FILES_PARAMETERS = {
    type: 'object',
    properties: {},
    required: [],
    additionalProperties: false
};
const GET_CACHED_FILE_PARAMETERS = {
    type: 'object',
    properties: {
        attachmentId: {
            type: 'string',
            description: 'The attachment id returned by list_cached_files.'
        }
    },
    required: ['attachmentId'],
    additionalProperties: false
};
const normalizeAttachmentEntry = (id, attachment) => {
    if (!attachment || typeof attachment !== 'object') {
        return null;
    }
    const normalizedId = attachment.id ?? id;
    return {
        ...attachment,
        id: normalizedId
    };
};
const mergeAttachmentRecord = (target, source) => {
    if (!source || typeof source !== 'object') {
        return;
    }
    for (const [id, attachment] of Object.entries(source)) {
        const normalized = normalizeAttachmentEntry(id, attachment);
        if (normalized) {
            target[normalized.id] = {
                ...target[normalized.id],
                ...normalized
            };
        }
    }
};
const resolveAttachmentLookup = (runtime) => {
    const lookup = {};
    try {
        mergeAttachmentRecord(lookup, runtime.getAttachmentCache?.());
    }
    catch (error) {
        console.warn('Failed to resolve attachment cache for tools', error);
    }
    mergeAttachmentRecord(lookup, runtime.attachments);
    return lookup;
};
const buildDataPreview = (attachment) => {
    const dataUrl = attachment.dataUrl;
    if (typeof dataUrl !== 'string' || dataUrl.length === 0) {
        return null;
    }
    if (dataUrl.length <= DATA_URL_MAX_PREVIEW_CHARS) {
        return dataUrl;
    }
    return `${dataUrl.slice(0, DATA_URL_MAX_PREVIEW_CHARS)}…`;
};
const serializeAttachment = (attachment) => ({
    id: attachment.id,
    name: attachment.name,
    mimeType: attachment.mimeType,
    size: attachment.size,
    sourceUrl: attachment.sourceUrl ?? null
});
const serializeAttachmentWithPreview = (attachment) => ({
    ...serializeAttachment(attachment),
    fileId: attachment.fileId ?? null,
    url: attachment.url ?? null,
    dataPreview: buildDataPreview(attachment)
});
const sortByDateDescending = (entries) => {
    return [...entries].sort((a, b) => {
        const aDate = typeof a.dateAdded === 'number' ? a.dateAdded : Number.NEGATIVE_INFINITY;
        const bDate = typeof b.dateAdded === 'number' ? b.dateAdded : Number.NEGATIVE_INFINITY;
        return bDate - aDate;
    });
};
export const createAttachmentToolDefinitions = () => {
    const listCachedFiles = {
        name: 'list_cached_files',
        description: `
      Use this tool to retrieve a summary of all locally cached attachments provided by the user in the current conversation.
      Returns metadata only (no file data).
    `,
        parameters: LIST_CACHED_FILES_PARAMETERS,
        async handler(_input, runtime) {
            const attachments = resolveAttachmentLookup(runtime);
            const payload = Object.values(attachments).map((attachment) => ({
                ...serializeAttachment(attachment),
                hasFileId: Boolean(attachment.fileId),
                hasSourceUrl: Boolean(attachment.sourceUrl),
                hasDataUrl: Boolean(attachment.dataUrl)
            }));
            return { attachments: payload };
        }
    };
    const getCachedFile = {
        name: 'get_cached_file',
        description: `
      Retrieve metadata for a locally cached attachment by id without returning the file contents.
      Returns an object with id, name, mimeType, size, and sourceUrl (if available).
      The source URL is the link to the uploaded file if available.
    `,
        parameters: GET_CACHED_FILE_PARAMETERS,
        async handler(input, runtime) {
            const attachmentId = typeof input?.attachmentId === 'string' ? input.attachmentId : '';
            if (!attachmentId) {
                return { error: 'Missing required attachmentId parameter.' };
            }
            const attachments = resolveAttachmentLookup(runtime);
            const attachment = attachments[attachmentId];
            if (!attachment) {
                return { error: `Attachment with id "${attachmentId}" was not found.` };
            }
            return serializeAttachmentWithPreview(attachment);
        }
    };
    const getLastFile = {
        name: 'get_last_file',
        description: `
      Use this tool when the user references a locally stored file but does not specify which one.
      Retrieves metadata for the most recently added attachment in the current conversation without returning the file contents.
      Returns an object with id, name, mimeType, size, and sourceUrl.
      The source URL is the link to the uploaded file.
    `,
        parameters: LIST_CACHED_FILES_PARAMETERS,
        async handler(_input, runtime) {
            const attachments = resolveAttachmentLookup(runtime);
            const sorted = sortByDateDescending(Object.values(attachments));
            const attachment = sorted[0];
            if (!attachment) {
                return { error: 'No attachments are available in the current conversation.' };
            }
            return serializeAttachmentWithPreview(attachment);
        }
    };
    return [listCachedFiles, getCachedFile, getLastFile];
};
