/**
 * WhatsApp Tool - Allows agents to access and process WhatsApp data
 *
 * Purpose:
 * - Read messages from allowed chats/groups
 * - Search across conversations
 * - Download and analyze media/files
 * - Get chat info and participant lists
 * - Filter by date ranges, keywords, media types
 */

import { BaseTool } from './baseTool.js';

class WhatsAppTool extends BaseTool {
  constructor(config = {}, logger = null) {
    super(config, logger);
    this.requiresProject = false;
    this.isAsync = false;
    this.timeout = config.timeout || 60000;

    // Injected dependency
    this.whatsappService = null;
  }

  /**
   * Set the WhatsApp service reference
   */
  setWhatsAppService(service) {
    this.whatsappService = service;
  }

  getDescription() {
    return `WhatsApp Tool: Access and process data from linked WhatsApp chats and groups.

## USAGE

Read messages from a chat (by name):
\`\`\`json
{
  "toolId": "whatsapp",
  "parameters": {
    "action": "get-messages",
    "chatId": "Work Group",
    "limit": 30,
    "after": "2025-01-01",
    "before": "2025-03-01",
    "searchTerm": "meeting notes"
  }
}
\`\`\`

Search across specific chats (by name or ID):
\`\`\`json
{
  "toolId": "whatsapp",
  "parameters": {
    "action": "search",
    "searchTerm": "project deadline",
    "chatIds": ["Work Group", "Alice"],
    "limit": 20,
    "after": "2025-02-01"
  }
}
\`\`\`

List available chats (with optional filtering and pagination):
\`\`\`json
{
  "toolId": "whatsapp",
  "parameters": {
    "action": "list-chats",
    "filter": "work",
    "type": "group",
    "page": 1,
    "pageSize": 20,
    "unreadOnly": false
  }
}
\`\`\`

Get chat info (participants, description):
\`\`\`json
{
  "toolId": "whatsapp",
  "parameters": {
    "action": "chat-info",
    "chatId": "Family Group"
  }
}
\`\`\`

Download media from a message:
\`\`\`json
{
  "toolId": "whatsapp",
  "parameters": {
    "action": "get-media",
    "chatId": "Work Group",
    "messageId": "true_1234567890@g.us_ABCDEF"
  }
}
\`\`\`

Check connection status:
\`\`\`json
{
  "toolId": "whatsapp",
  "parameters": {
    "action": "status"
  }
}
\`\`\`

## PARAMETERS

- **action** (required): One of: \`list-chats\`, \`get-messages\`, \`search\`, \`chat-info\`, \`get-media\`, \`status\`
- **chatId**: Chat/group name or ID (required for get-messages, chat-info, get-media). You can use the human-readable name (e.g. "Work Group") — it will be resolved automatically. If multiple chats match, you'll get suggestions.
- **messageId**: Message ID (required for get-media)
- **searchTerm**: Text to search for (required for search, optional for get-messages)
- **chatIds**: Array of chat names or IDs to search in (optional for search — defaults to all allowed)
- **filter**: Filter chat list by name substring (for list-chats)
- **type**: Filter chat list by type: \`"group"\`, \`"individual"\`, or \`"all"\` (default, for list-chats)
- **page**: Page number for paginated results, 1-based (default: 1, for list-chats)
- **pageSize**: Number of chats per page (default: 20, for list-chats)
- **unreadOnly**: Only show chats with unread messages (default: false, for list-chats)
- **limit**: Max messages to return (default: 50, for get-messages/search)
- **before**: ISO date string — only messages before this date
- **after**: ISO date string — only messages after this date

## RECOMMENDED WORKFLOWS

**Finding a chat by topic or name:**
1. Use \`list-chats\` with \`filter\` to search by name substring: \`"filter": "project"\` finds all chats with "project" in the name
2. Use \`type: "group"\` or \`type: "individual"\` to narrow down
3. If the user mentions a chat by name, you can skip list-chats and use the name directly as \`chatId\`

**Reading a conversation:**
1. Use \`get-messages\` with the chat name directly: \`"chatId": "Work Group"\`
2. Use \`after\`/\`before\` to focus on a time window (e.g., last week, a specific date)
3. Use \`searchTerm\` to filter messages containing specific text within that chat
4. The response includes a \`mediaSummary\` — check it to know if there are files/images to inspect

**Searching across chats:**
1. Use \`search\` with \`searchTerm\` to find messages across all allowed chats
2. Narrow with \`chatIds\` (names work) and date filters to reduce noise
3. Results are grouped by chat for easy scanning

**Analyzing shared files and media:**
1. Messages with \`hasMedia: true\` include \`mediaType\`, \`mimetype\`, and optionally \`fileName\`
2. Use \`get-media\` with the message's \`id\` to download the file
3. The downloaded file path is returned — use the \`filesystem\` tool to read documents, or other tools (pdf, doc, spreadsheet) to parse them
4. Images can be described by reading the file path

**Browsing many chats:**
1. Use \`list-chats\` with pagination: start with page 1, check \`pagination.hasMore\`
2. Use \`pageSize\` to control batch size (default 20)
3. Use \`unreadOnly: true\` to focus on active conversations
4. Combine filters: \`type: "group"\` + \`filter: "team"\` + \`page: 2\`

## NOTES

- **You can use chat names directly** — no need to look up IDs first. E.g. \`"chatId": "Work Group"\` works. Partial names resolve if unique.
- If a name matches multiple chats, you'll get an error listing the matches — use a more specific name or the exact ID.
- Only chats granted access by the user in Settings are available. If you get an access denied error, ask the user to grant access.
- If no access restrictions are set, all chats are accessible.
- Media files are downloaded to a temp directory — use the returned \`filePath\` with other tools (filesystem, pdf, doc, spreadsheet) to read/analyze them.
- Message types include: \`chat\`, \`image\`, \`video\`, \`audio\`, \`document\`, \`sticker\`, \`vcard\`, \`location\`.
- For large searches, prefer narrowing by \`chatIds\` and date range to avoid slow responses.
- Always check \`status\` first if unsure whether WhatsApp is connected.
- The WhatsApp account must be linked by the user via Settings before this tool works.`;
  }

  getSupportedActions() {
    return ['list-chats', 'get-messages', 'search', 'chat-info', 'get-media', 'status'];
  }

  getRequiredParameters() {
    return ['action'];
  }

  getParameterSchema() {
    return {
      type: 'object',
      properties: {
        action: { type: 'string', enum: ['list-chats', 'get-messages', 'search', 'chat-info', 'get-media', 'status'] },
        chatId: { type: 'string' },
        messageId: { type: 'string' },
        searchTerm: { type: 'string' },
        chatIds: { type: 'array', items: { type: 'string' } },
        filter: { type: 'string' },
        type: { type: 'string', enum: ['all', 'group', 'individual'] },
        page: { type: 'number' },
        pageSize: { type: 'number' },
        unreadOnly: { type: 'boolean' },
        limit: { type: 'number' },
        before: { type: 'string' },
        after: { type: 'string' }
      },
      required: ['action']
    };
  }

  customValidateParameters(params) {
    const { action, chatId, messageId, searchTerm } = params;
    const errors = [];

    const needsChat = ['get-messages', 'chat-info', 'get-media'];
    if (needsChat.includes(action) && !chatId) {
      errors.push(`chatId is required for action "${action}"`);
    }

    if (action === 'get-media' && !messageId) {
      errors.push('messageId is required for action "get-media"');
    }

    if (action === 'search' && !searchTerm) {
      errors.push('searchTerm is required for action "search"');
    }

    if (params.limit != null && (params.limit < 1 || params.limit > 500)) {
      errors.push('limit must be between 1 and 500');
    }

    return errors.length > 0
      ? { valid: false, error: errors.join('; ') }
      : { valid: true };
  }

  parseParameters(content) {
    try {
      if (typeof content === 'string' && content.trim().startsWith('{')) {
        const parsed = JSON.parse(content);
        return parsed.parameters || parsed;
      }
      if (typeof content === 'object') {
        return content.parameters || content;
      }
      return { action: 'status' };
    } catch (error) {
      return { action: 'status', parseError: error.message };
    }
  }

  async execute(params, context) {
    // Unwrap TagParser objects
    const unwrapped = {};
    for (const [key, value] of Object.entries(params)) {
      if (value && typeof value === 'object' && 'value' in value && !Array.isArray(value)) {
        unwrapped[key] = value.value;
      } else {
        unwrapped[key] = value;
      }
    }
    params = unwrapped;

    if (!this.whatsappService) {
      return {
        success: false,
        error: 'WhatsApp service is not available. The system may not have whatsapp-web.js installed.',
        guidance: 'Ask the user to install whatsapp-web.js: npm install whatsapp-web.js'
      };
    }

    const { action } = params;

    try {
      switch (action) {
        case 'status':
          return this._handleStatus();

        case 'list-chats':
          return await this._handleListChats(params);

        case 'get-messages':
          return await this._handleGetMessages(params);

        case 'search':
          return await this._handleSearch(params);

        case 'chat-info':
          return await this._handleChatInfo(params);

        case 'get-media':
          return await this._handleGetMedia(params);

        default:
          return {
            success: false,
            error: `Unknown action: ${action}`,
            guidance: 'Supported actions: list-chats, get-messages, search, chat-info, get-media, status'
          };
      }
    } catch (error) {
      let suggestion = null;
      if (error.message.includes('not connected')) {
        suggestion = 'The WhatsApp account is not linked. Ask the user to connect via Settings > WhatsApp.';
      } else if (error.message.includes('Access denied')) {
        suggestion = 'This chat is not in the allowed list. Ask the user to grant access in Settings > WhatsApp.';
      }

      return {
        success: false,
        action,
        error: error.message,
        ...(suggestion && { suggestion })
      };
    }
  }

  // ========================
  // Action handlers
  // ========================

  _handleStatus() {
    const status = this.whatsappService.getStatus();
    return {
      success: true,
      action: 'status',
      ...status,
      guidance: status.connected
        ? 'WhatsApp is connected and ready. Use list-chats to see available conversations.'
        : 'WhatsApp is not connected. Ask the user to link their account in Settings > WhatsApp.'
    };
  }

  async _handleListChats(params = {}) {
    const { filter, type, page, pageSize, unreadOnly } = params;

    const result = await this.whatsappService.listChats({
      filter,
      type: type || 'all',
      page: page || 1,
      pageSize: pageSize || 20,
      unreadOnly: unreadOnly || false
    });

    const { chats, pagination } = result;
    const allowed = chats.filter(c => c.allowed);
    const restricted = chats.filter(c => !c.allowed);

    let guidance;
    if (allowed.length === 0 && pagination.totalChats === 0) {
      guidance = filter
        ? `No chats match "${filter}". Try a different filter or remove it to see all chats.`
        : 'No accessible chats found. The user may need to grant access in Settings > WhatsApp.';
    } else {
      const parts = [`Showing ${allowed.length} chat(s)`];
      if (pagination.totalPages > 1) {
        parts.push(`(page ${pagination.page}/${pagination.totalPages})`);
      }
      parts.push('— use get-messages with a chat name to read messages.');
      if (pagination.hasMore) {
        parts.push(`Use page: ${pagination.page + 1} to see more.`);
      }
      guidance = parts.join(' ');
    }

    return {
      success: true,
      action: 'list-chats',
      totalChats: pagination.totalChats,
      accessibleChats: allowed.length,
      restrictedChats: restricted.length,
      chats: allowed,
      pagination,
      guidance
    };
  }

  async _handleGetMessages(params) {
    const { chatId, limit, before, after, searchTerm } = params;

    const result = await this.whatsappService.getMessages(chatId, {
      limit: limit || 50,
      before,
      after,
      searchTerm
    });

    // Summarize media in messages
    const mediaMessages = result.messages.filter(m => m.hasMedia);
    const mediaTypes = {};
    mediaMessages.forEach(m => {
      const type = m.mediaType || 'unknown';
      mediaTypes[type] = (mediaTypes[type] || 0) + 1;
    });

    return {
      success: true,
      action: 'get-messages',
      chatId,
      chatName: result.chatName,
      messageCount: result.messageCount,
      messages: result.messages,
      mediaSummary: {
        totalMedia: mediaMessages.length,
        byType: mediaTypes
      },
      guidance: mediaMessages.length > 0
        ? `Found ${mediaMessages.length} media messages. Use get-media with the message ID to download and analyze them.`
        : `Retrieved ${result.messageCount} messages from "${result.chatName}".`
    };
  }

  async _handleSearch(params) {
    const { searchTerm, chatIds, limit, before, after } = params;

    const result = await this.whatsappService.searchMessages(searchTerm, {
      chatIds,
      limit: limit || 30,
      before,
      after
    });

    return {
      success: true,
      action: 'search',
      searchTerm,
      totalMatches: result.totalMatches,
      chatsSearched: result.chatsSearched,
      results: result.results,
      guidance: result.totalMatches > 0
        ? `Found ${result.totalMatches} matches across ${result.results.length} chats. Narrow with date ranges or specific chatIds for better results.`
        : `No matches found for "${searchTerm}". Try broader terms or different date ranges.`
    };
  }

  async _handleChatInfo(params) {
    const { chatId } = params;
    const info = await this.whatsappService.getChatInfo(chatId);

    return {
      success: true,
      action: 'chat-info',
      ...info,
      guidance: info.isGroup
        ? `Group "${info.name}" has ${info.participantCount} participants. Use get-messages to read the conversation.`
        : `Individual chat with "${info.name}". Use get-messages to read messages.`
    };
  }

  async _handleGetMedia(params) {
    const { chatId, messageId } = params;
    const media = await this.whatsappService.getMedia(chatId, messageId);

    return {
      success: true,
      action: 'get-media',
      chatId,
      messageId,
      ...media,
      guidance: `Media downloaded to ${media.filePath}. You can use the filesystem tool to read/process this file.`
    };
  }
}

export default WhatsAppTool;
