import { mutation } from "../_generated/server";
import { v } from "convex/values";
import {
  conversationStatusValidator,
  messageSenderValidator,
} from "../schema/whatsapp";

/**
 * Update WhatsApp config on a user record (connect / disconnect).
 * Called from /api/integrations/whatsapp and connect/disconnect routes.
 */
export const updateWhatsappConfig = mutation({
  args: {
    email: v.string(),
    whatsappConnected: v.boolean(),
    whatsappNumber: v.optional(v.string()),
    whatsappConnectedAt: v.optional(v.number()),
    n8nWebhookUrl: v.optional(v.string()),
    n8nWorkflowId: v.optional(v.string()),
  },
  handler: async (ctx, args) => {
    const user = await ctx.db
      .query("users")
      .withIndex("by_email", (q) => q.eq("email", args.email))
      .unique();
    if (!user) throw new Error(`User not found for email: ${args.email}`);

    const updates: Record<string, unknown> = {
      whatsappConnected: args.whatsappConnected,
      updatedAt: Date.now(),
    };
    if (args.whatsappNumber !== undefined)
      updates.whatsappNumber = args.whatsappNumber;
    if (args.whatsappConnectedAt !== undefined)
      updates.whatsappConnectedAt = args.whatsappConnectedAt;
    if (args.n8nWebhookUrl !== undefined)
      updates.n8nWebhookUrl = args.n8nWebhookUrl;
    if (args.n8nWorkflowId !== undefined)
      updates.n8nWorkflowId = args.n8nWorkflowId;

    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    await ctx.db.patch(user._id, updates as any);
    return user._id;
  },
});

/**
 * Create a new WhatsApp conversation
 * Phase 6: WhatsApp & Voice Agents
 */
export const createConversation = mutation({
  args: {
    userId: v.string(),
    customerPhone: v.string(),
    customerName: v.optional(v.string()),
    tags: v.optional(v.array(v.string())),
  },
  handler: async (ctx, args) => {
    const now = Date.now();
    const id = await ctx.db.insert("whatsapp_conversations", {
      userId: args.userId,
      customerPhone: args.customerPhone,
      customerName: args.customerName,
      status: "active",
      tags: args.tags ?? [],
      unreadCount: 0,
      createdAt: now,
      updatedAt: now,
    });
    return id;
  },
});

/**
 * Handle an incoming WhatsApp message (create conversation if needed, append message)
 * Phase 6: WhatsApp & Voice Agents
 */
export const handleIncomingMessage = mutation({
  args: {
    userId: v.string(),
    customerPhone: v.string(),
    customerName: v.optional(v.string()),
    message: v.string(),
    metadata: v.optional(v.any()),
  },
  handler: async (ctx, args) => {
    const now = Date.now();

    // Find existing conversation
    const existing = await ctx.db
      .query("whatsapp_conversations")
      .withIndex("by_userId", (q) => q.eq("userId", args.userId))
      .filter((q) => q.eq(q.field("customerPhone"), args.customerPhone))
      .first();

    let conversationId: string;

    if (existing) {
      conversationId = existing._id;
      await ctx.db.patch(existing._id, {
        lastMessage: args.message,
        lastMessageAt: now,
        unreadCount: existing.unreadCount + 1,
        customerName: args.customerName ?? existing.customerName,
        updatedAt: now,
      });
    } else {
      conversationId = await ctx.db.insert("whatsapp_conversations", {
        userId: args.userId,
        customerPhone: args.customerPhone,
        customerName: args.customerName,
        lastMessage: args.message,
        lastMessageAt: now,
        status: "active",
        tags: [],
        unreadCount: 1,
        createdAt: now,
        updatedAt: now,
      });
    }

    // Insert the message
    const messageId = await ctx.db.insert("conversation_messages", {
      conversationId,
      sender: "customer",
      message: args.message,
      timestamp: now,
      metadata: args.metadata,
    });

    return { conversationId, messageId };
  },
});

/**
 * Send a message in a WhatsApp conversation (store locally)
 * Phase 6: WhatsApp & Voice Agents
 */
export const sendMessage = mutation({
  args: {
    conversationId: v.id("whatsapp_conversations"),
    sender: messageSenderValidator,
    message: v.string(),
    metadata: v.optional(v.any()),
  },
  handler: async (ctx, args) => {
    const now = Date.now();

    // Update conversation last message
    const conversation = await ctx.db.get(args.conversationId);
    if (!conversation) {
      throw new Error(`Conversation ${args.conversationId} not found`);
    }
    await ctx.db.patch(args.conversationId, {
      lastMessage: args.message,
      lastMessageAt: now,
      updatedAt: now,
    });

    // Insert the message
    const messageId = await ctx.db.insert("conversation_messages", {
      conversationId: args.conversationId,
      sender: args.sender,
      message: args.message,
      timestamp: now,
      metadata: args.metadata,
    });

    return messageId;
  },
});

/**
 * Mark a conversation as read (reset unread count)
 * Phase 6: WhatsApp & Voice Agents
 */
export const markRead = mutation({
  args: { id: v.id("whatsapp_conversations") },
  handler: async (ctx, args) => {
    const existing = await ctx.db.get(args.id);
    if (!existing) {
      throw new Error(`Conversation ${args.id} not found`);
    }
    await ctx.db.patch(args.id, {
      unreadCount: 0,
      updatedAt: Date.now(),
    });
    return args.id;
  },
});

/**
 * Update conversation status (active, resolved, escalated, abandoned)
 * Phase 6: WhatsApp & Voice Agents
 */
export const updateConversationStatus = mutation({
  args: {
    id: v.id("whatsapp_conversations"),
    status: conversationStatusValidator,
  },
  handler: async (ctx, args) => {
    const existing = await ctx.db.get(args.id);
    if (!existing) {
      throw new Error(`Conversation ${args.id} not found`);
    }
    await ctx.db.patch(args.id, {
      status: args.status,
      updatedAt: Date.now(),
    });
    return args.id;
  },
});

/**
 * Create an org-level WhatsApp conversation
 * Phase 6: WhatsApp & Voice Agents
 */
export const createOrgConversation = mutation({
  args: {
    organizationId: v.string(),
    userPhone: v.string(),
    userName: v.optional(v.string()),
    language: v.string(),
    status: v.optional(v.string()),
    messageCount: v.optional(v.number()),
    humanControlled: v.optional(v.boolean()),
    lastMessageAt: v.optional(v.number()),
    conversationState: v.optional(v.any()),
    createdAt: v.optional(v.number()),
    updatedAt: v.optional(v.number()),
  },
  handler: async (ctx, args) => {
    const now = Date.now();
    const id = await ctx.db.insert("org_whatsapp_conversations", {
      organizationId: args.organizationId,
      userPhone: args.userPhone,
      userName: args.userName,
      language: args.language,
      status: args.status ?? "active",
      messageCount: args.messageCount ?? 0,
      humanControlled: args.humanControlled ?? false,
      lastMessageAt: args.lastMessageAt,
      conversationState: args.conversationState,
      createdAt: args.createdAt ?? now,
      updatedAt: args.updatedAt ?? now,
    });
    return id;
  },
});

/**
 * Send an org-level WhatsApp message
 * Phase 6: WhatsApp & Voice Agents
 */
export const sendOrgMessage = mutation({
  args: {
    conversationId: v.string(),
    role: v.string(),
    content: v.string(),
    language: v.string(),
    intent: v.optional(v.string()),
    toolsUsed: v.optional(v.array(v.string())),
    metadata: v.optional(v.any()),
    timestamp: v.optional(v.number()),
    // KB metadata fields
    kbUsed: v.optional(v.boolean()),
    kbConfidence: v.optional(v.number()),
    questionCategory: v.optional(v.string()),
    escalatedToHuman: v.optional(v.boolean()),
  },
  handler: async (ctx, args) => {
    const now = args.timestamp ?? Date.now();
    const messageId = await ctx.db.insert("org_whatsapp_messages", {
      conversationId: args.conversationId,
      role: args.role,
      content: args.content,
      language: args.language,
      intent: args.intent,
      toolsUsed: args.toolsUsed ?? [],
      metadata: args.metadata,
      timestamp: now,
      kbUsed: args.kbUsed,
      kbConfidence: args.kbConfidence,
      questionCategory: args.questionCategory,
      escalatedToHuman: args.escalatedToHuman,
    });
    return messageId;
  },
});

/**
 * Update an org-level WhatsApp conversation
 * Supports updating status, message count, state, human control, etc.
 */
export const updateOrgConversation = mutation({
  args: {
    id: v.string(),
    status: v.optional(v.string()),
    messageCount: v.optional(v.number()),
    lastMessage: v.optional(v.string()),
    lastMessageAt: v.optional(v.number()),
    conversationState: v.optional(v.any()),
    humanControlled: v.optional(v.boolean()),
    humanControlledAt: v.optional(v.number()),
    language: v.optional(v.string()),
    userName: v.optional(v.string()),
    customerEmail: v.optional(v.string()),
    updatedAt: v.optional(v.number()),
  },
  handler: async (ctx, args) => {
    const { id, ...fields } = args;

    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    let docId: any;
    try {
      const doc = await ctx.db.get(id as any);
      if (doc) docId = doc._id;
    } catch {
      // Not a valid Convex ID
    }

    if (!docId) return null;

    const updates: Record<string, unknown> = { updatedAt: Date.now() };
    for (const [key, value] of Object.entries(fields)) {
      if (value !== undefined) {
        updates[key] = value;
      }
    }

    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    await ctx.db.patch(docId, updates as any);
    return docId;
  },
});

/**
 * Track an unanswered question for the conversation learning system.
 * Deduplicates by normalizedQuestion — increments frequency if it exists.
 */
export const trackUnansweredQuestion = mutation({
  args: {
    organizationId: v.string(),
    question: v.string(),
    normalizedQuestion: v.string(),
    sector: v.optional(v.string()),
    language: v.string(),
  },
  handler: async (ctx, args) => {
    // Check if this normalized question already exists for the org
    const existing = await ctx.db
      .query("unanswered_questions")
      .withIndex("by_organizationId", (q) =>
        q.eq("organizationId", args.organizationId),
      )
      .filter((q) => q.eq(q.field("normalizedQuestion"), args.normalizedQuestion))
      .first();

    if (existing) {
      // Increment frequency, update lastAskedAt
      await ctx.db.patch(existing._id, {
        frequency: existing.frequency + 1,
        lastAskedAt: Date.now(),
      });
      return existing._id;
    }

    // Create new entry
    const now = Date.now();
    return await ctx.db.insert("unanswered_questions", {
      organizationId: args.organizationId,
      question: args.question,
      normalizedQuestion: args.normalizedQuestion,
      frequency: 1,
      sector: args.sector,
      language: args.language,
      firstAskedAt: now,
      lastAskedAt: now,
      status: "open",
    });
  },
});

/**
 * Create a suggested FAQ from an unanswered question.
 * Phase 7: FAQ auto-suggestion system.
 */
export const createSuggestedFaq = mutation({
  args: {
    organizationId: v.string(),
    question: v.string(),
    suggestedAnswer: v.string(),
    language: v.string(),
    frequency: v.number(),
    sourceQuestionIds: v.optional(v.array(v.string())),
  },
  handler: async (ctx, args) => {
    return await ctx.db.insert("suggested_faqs", {
      ...args,
      status: "pending",
      createdAt: Date.now(),
    });
  },
});

/**
 * Update the status of a suggested FAQ (approve / reject).
 * Phase 7: FAQ auto-suggestion system.
 */
export const updateSuggestedFaqStatus = mutation({
  args: {
    id: v.id("suggested_faqs"),
    status: v.string(), // 'approved' | 'rejected'
    approvedBy: v.optional(v.string()),
  },
  handler: async (ctx, args) => {
    const now = Date.now();
    const updates: Record<string, unknown> = { status: args.status };
    if (args.status === "approved") {
      updates.approvedAt = now;
      updates.approvedBy = args.approvedBy;
    } else if (args.status === "rejected") {
      updates.rejectedAt = now;
    }
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    await ctx.db.patch(args.id, updates as any);
    return args.id;
  },
});

/**
 * Track an anonymized question pattern for cross-sector learning.
 * Phase 7: FAQ auto-suggestion system.
 */
export const trackSectorCommonQuestion = mutation({
  args: {
    sector: v.string(),
    questionPattern: v.string(),
    language: v.string(),
  },
  handler: async (ctx, args) => {
    // Check for existing pattern
    const existing = await ctx.db
      .query("sector_common_questions")
      .withIndex("by_sector", (q) => q.eq("sector", args.sector))
      .filter((q) => q.eq(q.field("questionPattern"), args.questionPattern))
      .first();

    if (existing) {
      await ctx.db.patch(existing._id, {
        frequency: existing.frequency + 1,
        lastSeenAt: Date.now(),
      });
      return existing._id;
    }

    const now = Date.now();
    return await ctx.db.insert("sector_common_questions", {
      sector: args.sector,
      questionPattern: args.questionPattern,
      frequency: 1,
      firstSeenAt: now,
      lastSeenAt: now,
      language: args.language,
    });
  },
});

/**
 * GDPR data retention: delete an org-level WhatsApp conversation and all of
 * its messages.
 *
 * Called by lib/services/conversation-cleanup.service.ts to purge
 * conversations older than the org's `dataRetentionDays` setting.
 */
export const deleteOrgConversation = mutation({
  args: { id: v.string() },
  handler: async (ctx, args) => {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const conv = await ctx.db.get(args.id as any);
    if (!conv) return null;

    // Delete all messages for this conversation first to avoid orphans.
    const messages = await ctx.db
      .query("org_whatsapp_messages")
      .withIndex("by_conversationId", (q) =>
        q.eq("conversationId", args.id),
      )
      .collect();

    for (const msg of messages) {
      await ctx.db.delete(msg._id);
    }

    // Then delete the conversation itself.
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    await ctx.db.delete(conv._id as any);
    return conv._id;
  },
});

/**
 * Seed / replace company_knowledge_base entries for an organization.
 *
 * Dev & test helper used to pre-populate a clinic's FAQ/knowledge base so the
 * WhatsApp AI engine has grounded facts to answer from. If `replace` is true,
 * all existing entries for the org are deleted before inserting.
 */
export const seedCompanyKnowledgeBase = mutation({
  args: {
    organizationId: v.string(),
    replace: v.optional(v.boolean()),
    entries: v.array(
      v.object({
        question: v.string(),
        answer: v.string(),
        category: v.optional(v.string()),
        language: v.string(),
        priority: v.optional(v.number()),
      }),
    ),
  },
  handler: async (ctx, args) => {
    const now = Date.now();

    if (args.replace) {
      const existing = await ctx.db
        .query("company_knowledge_base")
        .withIndex("by_organizationId", (q) =>
          q.eq("organizationId", args.organizationId),
        )
        .collect();
      for (const row of existing) {
        await ctx.db.delete(row._id);
      }
    }

    const insertedIds: string[] = [];
    for (const entry of args.entries) {
      const id = await ctx.db.insert("company_knowledge_base", {
        organizationId: args.organizationId,
        question: entry.question,
        answer: entry.answer,
        category: entry.category,
        language: entry.language,
        isActive: true,
        priority: entry.priority ?? 0,
        createdAt: now,
        updatedAt: now,
      });
      insertedIds.push(id);
    }

    return { inserted: insertedIds.length, replaced: args.replace === true };
  },
});

/**
 * Upsert a user language preference.
 */
export const upsertLanguagePreference = mutation({
  args: {
    organizationId: v.string(),
    userPhone: v.string(),
    language: v.string(),
  },
  handler: async (ctx, args) => {
    const now = Date.now();
    const existing = await ctx.db
      .query("user_language_preferences")
      .withIndex("by_organizationId_userPhone", (q) =>
        q.eq("organizationId", args.organizationId).eq("userPhone", args.userPhone),
      )
      .first();
    if (existing) {
      await ctx.db.patch(existing._id, { language: args.language, selectedAt: now, updatedAt: now });
      return existing._id;
    }
    return await ctx.db.insert("user_language_preferences", {
      organizationId: args.organizationId,
      userPhone: args.userPhone,
      language: args.language,
      selectedAt: now,
      createdAt: now,
      updatedAt: now,
    });
  },
});
