// Send media tool - allows sending local files as media
import { Type } from '@sinclair/typebox';
import { readFile } from 'fs/promises';
import { basename } from 'node:path';
import { AgentTool, type AgentToolResult } from '@earendil-works/pi-agent-core';
import { checkFileSafety } from '../prompt/safety.js';
import { resolvePathUnderWorkspace } from './tool-paths.js';
import type { MessageBus, OutboundMessage } from '../../infra/bus/index.js';

const SendMediaSchema = Type.Object({
  filePath: Type.String({
    description:
      'File to send. Relative paths are under the current agent workspace; absolute paths are used as given.',
  }),
  mediaType: Type.Optional(Type.Enum({
    photo: 'photo',
    video: 'video',
    audio: 'audio',
    document: 'document',
  }, { description: 'Type of media to send (auto-detected if not specified)' })),
  caption: Type.Optional(Type.String({ description: 'Caption for the media' })),
});

interface MessageContext {
  channel: string;
  chatId: string;
}

type SendMediaParams = {
  filePath: string;
  mediaType?: 'photo' | 'video' | 'audio' | 'document';
  caption?: string;
};

// Detect media type from file extension
function detectMediaType(filePath: string): 'photo' | 'video' | 'audio' | 'document' {
  const ext = filePath.split('.').pop()?.toLowerCase();
  const imageExts = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'svg'];
  const videoExts = ['mp4', 'mov', 'avi', 'webm', 'mkv'];
  const audioExts = ['mp3', 'wav', 'ogg', 'm4a', 'flac'];

  if (imageExts.includes(ext || '')) return 'photo';
  if (videoExts.includes(ext || '')) return 'video';
  if (audioExts.includes(ext || '')) return 'audio';
  return 'document';
}

// Detect MIME type from file extension
function detectMimeType(filePath: string): string {
  const ext = filePath.split('.').pop()?.toLowerCase();
  const mimeMap: Record<string, string> = {
    jpg: 'image/jpeg',
    jpeg: 'image/jpeg',
    png: 'image/png',
    gif: 'image/gif',
    webp: 'image/webp',
    bmp: 'image/bmp',
    svg: 'image/svg+xml',
    mp4: 'video/mp4',
    mov: 'video/quicktime',
    avi: 'video/x-msvideo',
    webm: 'video/webm',
    mp3: 'audio/mpeg',
    wav: 'audio/wav',
    ogg: 'audio/ogg',
    m4a: 'audio/mp4',
    flac: 'audio/flac',
    pdf: 'application/pdf',
    doc: 'application/msword',
    docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
    txt: 'text/plain',
    zip: 'application/zip',
    rar: 'application/x-rar-compressed',
  };
  return mimeMap[ext || ''] || 'application/octet-stream';
}

export function createSendMediaTool(
  workspace: string,
  bus: MessageBus,
  getContext: () => MessageContext | null,
): AgentTool {
  return {
    name: 'send_media',
    description:
      'Send a media file (photo, video, audio, document) to the current conversation. Relative paths resolve to the current agent workspace (same as read_file).',
    parameters: SendMediaSchema,
    label: '📎 Send Media',

    async execute(
      _toolCallId: string,
      params: any,
      _signal?: AbortSignal,
    ): Promise<AgentToolResult<{}>> {
      const p = params as SendMediaParams;
      const ctx = getContext();
      if (!ctx) {
        return {
          content: [{ type: 'text', text: 'Error: No active conversation context' }],
          details: {},
        };
      }

      const resolved = resolvePathUnderWorkspace(p.filePath, workspace);
      const safety = checkFileSafety('read', resolved);
      if (!safety.allowed) {
        return {
          content: [{ type: 'text', text: `🚫 ${safety.message}` }],
          details: {},
        };
      }

      try {
        const fileBuffer = await readFile(resolved);
        const base64 = fileBuffer.toString('base64');
        const mimeType = detectMimeType(resolved);
        const mediaType = p.mediaType || detectMediaType(resolved);

        // Create data URL
        const dataUrl = `data:${mimeType};base64,${base64}`;

        const msg: OutboundMessage = {
          channel: ctx.channel,
          chat_id: ctx.chatId,
          content: p.caption || '',
          mediaUrl: dataUrl,
          mediaType,
        };

        await bus.publishOutbound(msg);

        const fileName = basename(resolved);
        return {
          content: [{ type: 'text', text: `✅ Media sent: ${fileName} (${mediaType})` }],
          details: { filePath: resolved, mediaType },
        };
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        return {
          content: [{ type: 'text', text: `Error sending media: ${errorMessage}` }],
          details: { error: errorMessage },
        };
      }
    },
  } as any;
}
