import type { FastMCP } from 'fastmcp';
import { UserError } from 'fastmcp';
import { z } from 'zod';
import { getDocsClient, getDriveClient, getScriptClient } from '../../clients.js';
import { DocumentIdParameter } from '../../types.js';
import * as GDocsHelpers from '../../googleDocsApiHelpers.js';
import { logger } from '../../logger.js';

export function register(server: FastMCP) {
  server.addTool({
    name: 'insertImage',
    description:
      'Inserts an inline image into a Google Document. Provide either a publicly accessible URL or a local file path. Local files are automatically uploaded to Google Drive before insertion.',
    parameters: DocumentIdParameter.extend({
      imageUrl: z
        .string()
        .url()
        .optional()
        .describe('Publicly accessible URL to the image (http:// or https://).'),
      localImagePath: z
        .string()
        .optional()
        .describe(
          'Absolute path to a local image file (supports .jpg, .jpeg, .png, .gif, .bmp, .webp, .svg). The file will be uploaded to Google Drive.'
        ),
      index: z
        .number()
        .int()
        .min(1)
        .describe(
          "1-based character index in the document body where the image should be inserted. Use readDocument with format='json' to inspect indices."
        ),
      width: z.number().min(1).optional().describe('Width of the image in points.'),
      height: z.number().min(1).optional().describe('Height of the image in points.'),
      tabId: z
        .string()
        .optional()
        .describe(
          'The ID of the specific tab to insert into. Use listDocumentTabs to get tab IDs. If not specified, inserts into the first tab.'
        ),
    })
      .refine((data) => data.imageUrl || data.localImagePath, {
        message: 'Either imageUrl or localImagePath must be provided.',
      })
      .refine((data) => !(data.imageUrl && data.localImagePath), {
        message: 'Provide only one of imageUrl or localImagePath, not both.',
      }),
    execute: async (args, { log }) => {
      const docs = await getDocsClient();
      const appsScriptDeploymentId = process.env.APPS_SCRIPT_DEPLOYMENT_ID;

      try {
        if (args.tabId) {
          const targetTab = await GDocsHelpers.getDocumentTab(docs, args.documentId, args.tabId);
        }

        // --- Apps Script path: local files when APPS_SCRIPT_DEPLOYMENT_ID is set ---
        if (args.localImagePath && appsScriptDeploymentId) {
          const drive = await getDriveClient();
          const scriptClient = await getScriptClient();

          log.info(`[AppsScript] Uploading ${args.localImagePath} to Drive (no public sharing)`);

          let parentFolderId: string | undefined;
          try {
            const docInfo = await drive.files.get({
              fileId: args.documentId,
              fields: 'parents',
              supportsAllDrives: true,
            });
            if (docInfo.data.parents && docInfo.data.parents.length > 0) {
              parentFolderId = docInfo.data.parents[0];
            }
          } catch (folderError) {
            log.warn(
              `Could not determine document's parent folder, using Drive root: ${folderError}`
            );
          }

          const driveFileId = await GDocsHelpers.uploadImageToDrive(
            drive,
            args.localImagePath,
            parentFolderId,
            true // skipPublicSharing
          );

          log.info(
            `[AppsScript] Inserting image via marker at index ${args.index} (fileId: ${driveFileId})`
          );

          await GDocsHelpers.insertImageViaAppsScript(
            docs,
            scriptClient,
            appsScriptDeploymentId,
            args.documentId,
            driveFileId,
            args.index,
            args.tabId
          );

          return `Successfully inserted local image at index ${args.index} via Apps Script${args.tabId ? ` in tab ${args.tabId}` : ''}.`;
        }

        // --- Standard path: public URL insertion via Docs API ---
        let resolvedUrl: string;

        if (args.localImagePath) {
          const drive = await getDriveClient();
          log.info(
            `Uploading local image ${args.localImagePath} and inserting at index ${args.index} in doc ${args.documentId}${args.tabId ? ` (tab: ${args.tabId})` : ''}`
          );

          let parentFolderId: string | undefined;
          try {
            const docInfo = await drive.files.get({
              fileId: args.documentId,
              fields: 'parents',
              supportsAllDrives: true,
            });
            if (docInfo.data.parents && docInfo.data.parents.length > 0) {
              parentFolderId = docInfo.data.parents[0];
            }
          } catch (folderError) {
            log.warn(
              `Could not determine document's parent folder, using Drive root: ${folderError}`
            );
          }

          resolvedUrl = await GDocsHelpers.uploadImageToDrive(
            drive,
            args.localImagePath,
            parentFolderId,
            false // explicit: needs public URL for Docs API insertion
          );
          log.info(`Image uploaded successfully, URL: ${resolvedUrl}`);
        } else {
          resolvedUrl = args.imageUrl!;
          log.info(
            `Inserting image from URL ${resolvedUrl} at index ${args.index} in doc ${args.documentId}${args.tabId ? ` (tab: ${args.tabId})` : ''}`
          );
        }

        await GDocsHelpers.insertInlineImage(
          docs,
          args.documentId,
          resolvedUrl,
          args.index,
          args.width,
          args.height,
          args.tabId
        );

        let sizeInfo = '';
        if (args.width && args.height) {
          sizeInfo = ` with size ${args.width}x${args.height}pt`;
        }

        return `Successfully inserted image at index ${args.index}${sizeInfo}${args.tabId ? ` in tab ${args.tabId}` : ''}.`;
      } catch (error: any) {
        log.error(`Error inserting image in doc ${args.documentId}: ${error.message || error}`);
        if (error instanceof UserError) throw error;
        throw new UserError(`Failed to insert image: ${error.message || 'Unknown error'}`);
      }
    },
  });
}
