import { env } from '../config/env';
import { prisma } from '../config/database';
import { logger } from '../utils/logger';
import { termuxClient } from './termux.client';
import { eventBus } from './event-bus.service';
import type { SmsResponseType } from '@prisma/client';

// Opt-out keywords (case-insensitive)
const OPT_OUT_KEYWORDS = ['stop', 'unsubscribe', 'cancel', 'quit', 'remove', 'optout', 'opt out', 'end'];
const POSITIVE_KEYWORDS = ['yes', 'yeah', 'yep', 'sure', 'ok', 'okay', 'great', 'thanks', 'thank you', 'sounds good', 'interested', 'count me in'];
const NEGATIVE_KEYWORDS = ['no', 'nah', 'nope', 'not interested', 'no thanks', 'no thank you', 'pass', 'decline'];

/**
 * Classify an inbound SMS response by content
 */
function classifyResponse(text: string): SmsResponseType {
  const lower = text.toLowerCase().trim();

  if (OPT_OUT_KEYWORDS.some((kw) => lower === kw || lower.startsWith(kw + ' '))) {
    return 'OPT_OUT';
  }
  if (POSITIVE_KEYWORDS.some((kw) => lower === kw || lower.startsWith(kw + ' ') || lower.startsWith(kw + '!'))) {
    return 'POSITIVE';
  }
  if (NEGATIVE_KEYWORDS.some((kw) => lower === kw || lower.startsWith(kw + ' '))) {
    return 'NEGATIVE';
  }
  if (lower.includes('?')) {
    return 'QUESTION';
  }
  return 'NEUTRAL';
}

/**
 * Normalize phone to last 10 digits for matching
 */
function normalizeLast10(phone: string): string {
  const digits = phone.replace(/\D/g, '');
  return digits.length >= 10 ? digits.slice(-10) : digits;
}

class SmsResponseSyncService {
  private interval: ReturnType<typeof setInterval> | null = null;
  private lastSyncTimestamp: string | null = null;

  start() {
    if (this.interval) return;

    // Initial sync
    this.sync().catch((err) => {
      logger.warn('Initial SMS response sync failed:', err instanceof Error ? err.message : err);
    });

    this.interval = setInterval(() => {
      this.sync().catch((err) => {
        logger.warn('SMS response sync failed:', err instanceof Error ? err.message : err);
      });
    }, env.SMS_RESPONSE_SYNC_INTERVAL_MS);

    logger.info(`SMS response sync started (interval: ${env.SMS_RESPONSE_SYNC_INTERVAL_MS}ms)`);
  }

  stop() {
    if (this.interval) {
      clearInterval(this.interval);
      this.interval = null;
    }
  }

  async sync() {
    const messages = await termuxClient.getInbox(this.lastSyncTimestamp || undefined, 200);
    if (messages.length === 0) return;

    let processed = 0;

    for (const msg of messages) {
      if (!msg.number || !msg.body) continue;

      const phone10 = normalizeLast10(msg.number);
      if (phone10.length < 10) continue;

      // Check if we already have this message (dedup by phone + body + date)
      const existingMsg = await prisma.smsMessage.findFirst({
        where: {
          phone: { endsWith: phone10 },
          direction: 'INBOUND',
          message: msg.body,
          sentAt: msg.date ? new Date(msg.date) : undefined,
        },
      });
      if (existingMsg) continue;

      // Find matching conversation(s) — by normalized phone suffix
      const conversations = await prisma.smsConversation.findMany({
        where: {
          phone: { endsWith: phone10 },
          status: { not: 'CLOSED' },
        },
        orderBy: { lastMessageAt: 'desc' },
        take: 1,
      });

      const conversation = conversations[0] || null;
      const responseType = classifyResponse(msg.body);

      // Create inbound message record
      const smsMessage = await prisma.smsMessage.create({
        data: {
          phone: msg.number,
          message: msg.body,
          direction: 'INBOUND',
          status: 'DELIVERED',
          responseType,
          campaignId: conversation?.campaignId || undefined,
          conversationId: conversation?.id || undefined,
          sentAt: msg.date ? new Date(msg.date) : new Date(),
        },
      });

      eventBus.publish('sms.message.received', {
        messageId: smsMessage.id,
        conversationId: conversation?.id || '',
        phone: msg.number,
        body: msg.body,
        responseType,
      });

      // Update conversation stats if we have one
      if (conversation) {
        const updates: Record<string, unknown> = {
          totalMessages: { increment: 1 },
          totalResponses: { increment: 1 },
          unreadCount: { increment: 1 },
          lastMessageAt: smsMessage.sentAt,
          lastResponseAt: smsMessage.sentAt,
        };

        // Handle opt-out
        if (responseType === 'OPT_OUT') {
          updates.status = 'OPTED_OUT';
        }

        // Auto-link conversation to CRM contact by phone number
        if (!conversation.contactId) {
          try {
            const contactPhone = await prisma.contactPhone.findFirst({
              where: { phone: { endsWith: phone10 } },
              select: { contactId: true },
            });
            if (contactPhone) {
              updates.contactId = contactPhone.contactId;
              logger.debug(`Auto-linked conversation ${conversation.id} to contact ${contactPhone.contactId}`);
            }
          } catch (err) {
            logger.debug('Failed to auto-link conversation to contact:', err);
          }
        }

        await prisma.smsConversation.update({
          where: { id: conversation.id },
          data: updates,
        });

        // Record inbound SMS as ContactActivity if conversation has a contactId
        const updatedContactId = (updates.contactId as string) || conversation.contactId;
        if (updatedContactId) {
          try {
            await prisma.contactActivity.create({
              data: {
                contactId: updatedContactId,
                type: 'SMS_RECEIVED',
                title: 'SMS received',
                description: msg.body.length > 200 ? msg.body.slice(0, 200) + '...' : msg.body,
                metadata: {
                  phone: msg.number,
                  responseType,
                  conversationId: conversation.id,
                  campaignId: conversation.campaignId || null,
                },
              },
            });
          } catch (err) {
            logger.debug('Failed to record inbound SMS ContactActivity:', err);
          }
        }

        // Increment campaign totalResponded
        if (conversation.campaignId) {
          await prisma.smsCampaign.update({
            where: { id: conversation.campaignId },
            data: { totalResponded: { increment: 1 } },
          });
        }
      }

      processed++;
    }

    // Update last sync timestamp
    if (messages.length > 0) {
      const latestDate = messages
        .filter((m) => m.date)
        .map((m) => new Date(m.date).getTime())
        .sort((a, b) => b - a)[0];
      if (latestDate) {
        this.lastSyncTimestamp = new Date(latestDate).toISOString();
      }
    }

    if (processed > 0) {
      logger.info(`SMS response sync: processed ${processed} new inbound messages`);
    }
  }
}

export const smsResponseSyncService = new SmsResponseSyncService();
