import { Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '@chatapp/database';

@Injectable()
export class AiService {
  constructor(private readonly prisma: PrismaService) {}

  /**
   * Summarize the latest messages of a channel.
   * Simple implementation: take last 50 messages, count mentions, extract key topics.
   */
  async summarizeChannel(channelId: string, wsId: string, userId: string) {
    const channel = await this.prisma.channel.findFirst({
      where: { id: channelId, workspaceId: wsId },
    });
    if (!channel) throw new NotFoundException('Channel not found');

    const messages = await this.prisma.message.findMany({
      where: { channelId, isDeleted: false },
      orderBy: { ts: 'desc' },
      take: 50,
      include: {
        user: { select: { id: true, displayName: true } },
      },
    });

    if (messages.length === 0) {
      return {
        summary: 'No messages found in this channel.',
        key_points: [],
        action_items: [],
        message_count: 0,
        period_start: null,
        period_end: null,
      };
    }

    // Reverse to chronological order for analysis
    const chronological = messages.reverse();

    // Extract key data
    const participants = new Map<string, string>();
    const mentionCounts = new Map<string, number>();
    const words: string[] = [];

    for (const msg of chronological) {
      if (msg.user) {
        participants.set(msg.user.id, msg.user.displayName);
      }
      // Count mentions
      for (const mentionedId of msg.mentionedUsers) {
        mentionCounts.set(mentionedId, (mentionCounts.get(mentionedId) || 0) + 1);
      }
      // Extract words for topic detection
      if (msg.text) {
        const msgWords = msg.text
          .toLowerCase()
          .replace(/[^\w\s]/g, ' ')
          .split(/\s+/)
          .filter(w => w.length > 4 && !this.isStopWord(w));
        words.push(...msgWords);
      }
    }

    // Word frequency for topic extraction
    const wordFreq = new Map<string, number>();
    for (const word of words) {
      wordFreq.set(word, (wordFreq.get(word) || 0) + 1);
    }
    const topWords = Array.from(wordFreq.entries())
      .sort((a, b) => b[1] - a[1])
      .slice(0, 5)
      .map(([word, count]) => ({ word, count }));

    // Build summary text
    const periodStart = chronological[0].ts;
    const periodEnd = chronological[chronological.length - 1].ts;
    const participantList = Array.from(participants.values());

    const summaryText = `Resumen de ${messages.length} mensajes en #${channel.name} entre ${participantList.length} participantes (${participantList.join(', ')}). ` +
      `Período: ${periodStart.toISOString()} a ${periodEnd.toISOString()}. ` +
      `Temas principales detectados: ${topWords.map(t => t.word).join(', ')}.`;

    const keyPoints = topWords.map(t => `Se discutió "${t.word}" (${t.count} menciones)`);
    if (mentionCounts.size > 0) {
      const topMentions = Array.from(mentionCounts.entries())
        .sort((a, b) => b[1] - a[1])
        .slice(0, 3);
      for (const [uid, count] of topMentions) {
        const name = participants.get(uid) || uid;
        keyPoints.push(`${name} fue mencionado ${count} veces`);
      }
    }

    // Save summary to database
    const aiSummary = await this.prisma.aiSummary.create({
      data: {
        workspaceId: wsId,
        type: 'channel',
        targetId: channelId,
        summary: summaryText,
        keyPoints: keyPoints,
        actionItems: { top_words: topWords, participants: participantList },
        periodStart,
        periodEnd,
        generatedFor: userId,
        model: 'simple-stub',
      },
    });

    return {
      id: aiSummary.id,
      summary: summaryText,
      key_points: keyPoints,
      action_items: { top_words: topWords, participants: participantList },
      message_count: messages.length,
      period_start: periodStart,
      period_end: periodEnd,
    };
  }

  /**
   * Summarize a thread by message ID (the root message).
   */
  async summarizeThread(messageId: string, wsId: string, userId: string) {
    const rootMessage = await this.prisma.message.findFirst({
      where: { id: messageId, workspaceId: wsId },
      include: {
        user: { select: { id: true, displayName: true } },
        channel: { select: { id: true, name: true } },
      },
    });
    if (!rootMessage) throw new NotFoundException('Message not found');

    const replies = await this.prisma.message.findMany({
      where: { threadRootId: messageId, isDeleted: false },
      orderBy: { ts: 'asc' },
      take: 50,
      include: {
        user: { select: { id: true, displayName: true } },
      },
    });

    const allMessages = [rootMessage, ...replies];
    const participants = new Map<string, string>();
    const words: string[] = [];

    for (const msg of allMessages) {
      if (msg.user) participants.set(msg.user.id, msg.user.displayName);
      if (msg.text) {
        const msgWords = msg.text
          .toLowerCase()
          .replace(/[^\w\s]/g, ' ')
          .split(/\s+/)
          .filter(w => w.length > 4 && !this.isStopWord(w));
        words.push(...msgWords);
      }
    }

    const wordFreq = new Map<string, number>();
    for (const word of words) {
      wordFreq.set(word, (wordFreq.get(word) || 0) + 1);
    }
    const topWords = Array.from(wordFreq.entries())
      .sort((a, b) => b[1] - a[1])
      .slice(0, 5)
      .map(([word, count]) => ({ word, count }));

    const participantList = Array.from(participants.values());
    const periodStart = allMessages[0].ts;
    const periodEnd = allMessages[allMessages.length - 1].ts;

    const summaryText = `Resumen del thread en #${rootMessage.channel?.name}: ${replies.length} respuestas de ${participantList.length} participantes. ` +
      `Iniciado por ${rootMessage.user?.displayName || 'Usuario'}. ` +
      `Temas: ${topWords.map(t => t.word).join(', ')}.`;

    const keyPoints = [
      `Mensaje original: "${rootMessage.text?.substring(0, 100) || '(sin texto)'}${rootMessage.text && rootMessage.text.length > 100 ? '...' : ''}"`,
      `${replies.length} respuestas`,
      ...topWords.map(t => `Término clave: "${t.word}" (${t.count} veces)`),
    ];

    const aiSummary = await this.prisma.aiSummary.create({
      data: {
        workspaceId: wsId,
        type: 'thread',
        targetId: messageId,
        summary: summaryText,
        keyPoints: keyPoints,
        actionItems: { top_words: topWords, participants: participantList },
        periodStart,
        periodEnd,
        generatedFor: userId,
        model: 'simple-stub',
      },
    });

    return {
      id: aiSummary.id,
      summary: summaryText,
      key_points: keyPoints,
      action_items: { top_words: topWords, participants: participantList },
      reply_count: replies.length,
      period_start: periodStart,
      period_end: periodEnd,
    };
  }

  /**
   * Answer a question about the workspace using simple keyword matching.
   */
  async ask(wsId: string, userId: string, dto: any) {
    const question = dto.question || dto.query || '';
    if (!question) {
      return { answer: 'No se proporcionó una pregunta.' };
    }

    // Search for relevant messages using keyword matching
    const keywords = question
      .toLowerCase()
      .replace(/[^\w\s]/g, ' ')
      .split(/\s+/)
      .filter((w: string) => w.length > 3 && !this.isStopWord(w));

    let relevantMessages: any[] = [];
    if (keywords.length > 0) {
      relevantMessages = await this.prisma.message.findMany({
        where: {
          workspaceId: wsId,
          isDeleted: false,
          text: { contains: keywords[0], mode: 'insensitive' },
        },
        orderBy: { ts: 'desc' },
        take: 20,
        include: {
          user: { select: { id: true, displayName: true } },
          channel: { select: { id: true, name: true } },
        },
      });

      // Further filter by remaining keywords
      if (keywords.length > 1) {
        relevantMessages = relevantMessages.filter(m => {
          const text = (m.text || '').toLowerCase();
          return keywords.slice(1).some((kw: string) => text.includes(kw));
        });
      }
    }

    // Create or update AI conversation
    const conversation = await this.prisma.aiConversation.create({
      data: {
        workspaceId: wsId,
        userId,
        messages: [
          { role: 'user', content: question, timestamp: new Date().toISOString() },
        ],
        contextRefs: relevantMessages.map(m => m.id),
      },
    });

    if (relevantMessages.length === 0) {
      const answer = `No encontré mensajes relevantes para responder tu pregunta: "${question}". Intenta con otros términos de búsqueda.`;
      await this.updateConversation(conversation.id, answer);
      return { conversation_id: conversation.id, answer, sources: [] };
    }

    // Build a simple answer from the relevant messages
    const topMessages = relevantMessages.slice(0, 5);
    const answerParts = topMessages.map(m => {
      const text = m.text ? m.text.substring(0, 200) : '(sin texto)';
      return `En #${m.channel?.name}, ${m.user?.displayName || 'Usuario'} dijo: "${text}${m.text && m.text.length > 200 ? '...' : ''}"`;
    });

    const answer = `Basado en ${relevantMessages.length} mensajes encontrados:\n\n${answerParts.join('\n\n')}`;

    await this.updateConversation(conversation.id, answer);

    return {
      conversation_id: conversation.id,
      answer,
      sources: topMessages.map(m => ({
        message_id: m.id,
        channel_name: m.channel?.name,
        user: m.user?.displayName,
        text: m.text?.substring(0, 100),
        ts: m.ts,
      })),
    };
  }

  private async updateConversation(conversationId: string, answer: string) {
    const existing = await this.prisma.aiConversation.findUnique({
      where: { id: conversationId },
    });
    if (!existing) return;

    const messages = [...(existing.messages as any[]), { role: 'assistant', content: answer, timestamp: new Date().toISOString() }];
    await this.prisma.aiConversation.update({
      where: { id: conversationId },
      data: { messages },
    });
  }

  private isStopWord(word: string): boolean {
    const stopWords = new Set([
      'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for',
      'of', 'with', 'by', 'from', 'is', 'are', 'was', 'were', 'be', 'been',
      'being', 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would',
      'could', 'should', 'may', 'might', 'can', 'this', 'that', 'these',
      'those', 'i', 'you', 'he', 'she', 'it', 'we', 'they', 'what', 'which',
      'who', 'when', 'where', 'why', 'how', 'all', 'each', 'every', 'some',
      'any', 'few', 'more', 'most', 'other', 'into', 'through', 'during',
      'before', 'after', 'above', 'below', 'there', 'here', 'about', 'than',
      'que', 'de', 'la', 'el', 'en', 'y', 'a', 'los', 'del', 'las', 'un',
      'una', 'por', 'con', 'para', 'se', 'su', 'es', 'lo', 'como', 'mas',
      'pero', 'sus', 'le', 'ya', 'o', 'este', 'si', 'porque', 'esta',
      'entre', 'cuando', 'muy', 'sin', 'sobre', 'tambien', 'hasta', 'hay',
    ]);
    return stopWords.has(word);
  }

  // --- Daily Recap ---

  async dailyRecap(wsId: string, userId: string) {
    const since = new Date();
    since.setHours(since.getHours() - 24);

    // Get channels the user is a member of
    const memberships = await this.prisma.channelMember.findMany({
      where: { userId, workspaceId: wsId, leftAt: null },
      select: { channelId: true },
    });
    const channelIds = memberships.map(m => m.channelId);

    if (channelIds.length === 0) {
      return { recap: 'No tienes canales, no hay actividad para resumir.', channels: [] };
    }

    // Get messages from the last 24 hours in those channels
    const messages = await this.prisma.message.findMany({
      where: {
        workspaceId: wsId,
        channelId: { in: channelIds },
        isDeleted: false,
        ts: { gte: since },
      },
      orderBy: { ts: 'asc' },
      include: {
        channel: { select: { id: true, name: true } },
        user: { select: { id: true, displayName: true } },
      },
    });

    // Group by channel
    const byChannel = new Map<string, any[]>();
    for (const msg of messages) {
      const key = msg.channelId;
      if (!byChannel.has(key)) byChannel.set(key, []);
      byChannel.get(key)!.push(msg);
    }

    const channelSummaries = Array.from(byChannel.entries()).map(([chId, msgs]) => {
      const channel = msgs[0].channel;
      const participants = new Set(msgs.map(m => m.user?.displayName).filter(Boolean));
      return {
        channel_id: chId,
        channel_name: channel.name,
        message_count: msgs.length,
        participants: Array.from(participants),
        highlights: msgs.slice(0, 3).map(m => ({
          user: m.user?.displayName,
          text: m.text?.substring(0, 200) || '',
          ts: m.ts,
        })),
      };
    });

    const totalMessages = messages.length;
    const summary = `Resumen de las últimas 24 horas: ${totalMessages} mensajes en ${channelSummaries.length} canales. ` +
      channelSummaries.map(c => `#${c.channel_name}: ${c.message_count} mensajes`).join('. ');

    // Save recap as an AI summary
    const aiSummary = await this.prisma.aiSummary.create({
      data: {
        workspaceId: wsId,
        type: 'daily_recap',
        targetId: userId,
        summary,
        keyPoints: channelSummaries.map(c => `#${c.channel_name}: ${c.message_count} mensajes`),
        actionItems: { channels: channelSummaries },
        periodStart: since,
        periodEnd: new Date(),
        generatedFor: userId,
        model: 'simple-stub',
      },
    });

    return {
      id: aiSummary.id,
      recap: summary,
      channels: channelSummaries,
      total_messages: totalMessages,
      period_start: since,
      period_end: new Date(),
    };
  }

  // --- Translate ---

  async translateMessage(wsId: string, messageId: string, targetLanguage: string) {
    const message = await this.prisma.message.findFirst({
      where: { id: messageId, workspaceId: wsId },
      include: {
        user: { select: { id: true, displayName: true } },
        channel: { select: { id: true, name: true } },
      },
    });

    if (!message) throw new NotFoundException('Message not found');

    // Simple stub translation: detect language keywords and provide a mock translation
    // In production this would call an external translation API
    const originalText = message.text || '';

    // Mock translation based on target language
    const translations: Record<string, string> = {
      en: `[EN] ${originalText}`,
      es: `[ES] ${originalText}`,
      fr: `[FR] ${originalText}`,
      de: `[DE] ${originalText}`,
      ja: `[JA] ${originalText}`,
      zh: `[ZH] ${originalText}`,
      pt: `[PT] ${originalText}`,
      it: `[IT] ${originalText}`,
    };

    const translatedText = translations[targetLanguage.toLowerCase()] || `[${targetLanguage.toUpperCase()}] ${originalText}`;

    return {
      message_id: message.id,
      original_text: originalText,
      translated_text: translatedText,
      target_language: targetLanguage,
      source_channel: message.channel?.name,
      original_user: message.user?.displayName,
    };
  }

  // --- File Summary ---

  async fileSummary(fileId: string, wsId: string, userId: string) {
    const file = await this.prisma.file.findFirst({
      where: { id: fileId, workspaceId: wsId, isDeleted: false },
    });

    if (!file) throw new NotFoundException('File not found');

    // Build a summary based on file metadata
    // In production this would extract text and call an LLM
    const summary = `Archivo: ${file.filename}. Tipo: ${file.fileType}. Tamaño: ${Number(file.sizeBytes)} bytes. ` +
      `Formato: ${file.mimeType}. ` +
      (file.pageCount ? `Páginas: ${file.pageCount}. ` : '') +
      (file.imageWidth && file.imageHeight ? `Dimensiones: ${file.imageWidth}x${file.imageHeight}. ` : '') +
      (file.durationSeconds ? `Duración: ${file.durationSeconds}s. ` : '');

    const keyPoints: string[] = [
      `Nombre: ${file.filename}`,
      `Tipo: ${file.fileType}`,
      `Tamaño: ${Number(file.sizeBytes)} bytes`,
    ];

    if (file.pageCount) keyPoints.push(`Páginas: ${file.pageCount}`);
    if (file.imageWidth && file.imageHeight) keyPoints.push(`Resolución: ${file.imageWidth}x${file.imageHeight}`);

    // Save as AI summary
    const aiSummary = await this.prisma.aiSummary.create({
      data: {
        workspaceId: wsId,
        type: 'file_summary',
        targetId: fileId,
        summary,
        keyPoints,
        actionItems: {
          filename: file.filename,
          fileType: file.fileType,
          sizeBytes: Number(file.sizeBytes),
          pageCount: file.pageCount,
          mimeType: file.mimeType,
        },
        generatedFor: userId,
        model: 'simple-stub',
      },
    });

    return {
      id: aiSummary.id,
      file_id: file.id,
      filename: file.filename,
      summary,
      key_points: keyPoints,
      file_type: file.fileType,
      size: Number(file.sizeBytes),
    };
  }
}