/**
 * WhatsApp Domain Adapter
 *
 * Routes WhatsApp-related CRUD to Prisma or Convex based on data-source config.
 * Sub-models:
 *   - whatsapp_conversations (user-level conversations)
 *   - conversation_messages (messages within conversations)
 *   - org_whatsapp_conversations (organization-level AI agent conversations)
 *   - org_whatsapp_messages (messages in org conversations)
 *   - company_knowledge_base (FAQ entries for AI agent)
 *   - user_language_preferences (per-phone language settings)
 */

import { prisma } from "@/lib/db";
import { convexQuery, convexMutation } from "@/lib/convex-client";
import { getDataSource } from "@/lib/data-source";
import {
  convexToPrismaShape,
  convexToPrismaShapeMany,
  applyPagination,
  type ConvexDoc,
  type BatchResult,
} from "./base";

const DOMAIN = "whatsapp" as const;

const CONVERSATION_TS_FIELDS = ["createdAt", "updatedAt", "lastMessageAt"];
const MESSAGE_TS_FIELDS = ["timestamp"];
const ORG_CONVERSATION_TS_FIELDS = [
  "createdAt",
  "updatedAt",
  "lastMessageAt",
  "humanControlledAt",
];
const ORG_MESSAGE_TS_FIELDS = ["timestamp"];
const KB_TS_FIELDS = ["createdAt", "updatedAt"];
const LANG_PREF_TS_FIELDS = ["createdAt", "updatedAt", "selectedAt"];

// Suppress unused-variable warnings for fields reserved for future Convex migration
void MESSAGE_TS_FIELDS;
void ORG_MESSAGE_TS_FIELDS;
void KB_TS_FIELDS;
void LANG_PREF_TS_FIELDS;

function isConvex(): boolean {
  return getDataSource(DOMAIN) === "convex";
}

// =============================================================================
// WhatsApp Conversations (user-level)
// =============================================================================

const conversations = {
  async findMany(args: {
    where?: Record<string, unknown>;
    include?: Record<string, unknown>;
    orderBy?: Record<string, string> | Record<string, string>[];
    take?: number;
    skip?: number;
    select?: Record<string, boolean>;
  }) {
    if (!isConvex()) {
      return prisma.whatsapp_conversations.findMany(args as any);
    }

    const where = (args.where || {}) as Record<string, unknown>;
    const userId = where.userId as string | undefined;
    const status = where.status as string | undefined;
    const limit = (args.take || 100) + (args.skip || 0);

    const docs =
      (await convexQuery<ConvexDoc[]>("whatsapp/queries:getConversations", {
        userId: userId || "",
        ...(status ? { status } : {}),
        limit,
      })) || [];

    // Apply additional where filters not handled by Convex query
    let filtered = docs;
    if (where.customerPhone) {
      filtered = filtered.filter(
        (d) => d.customerPhone === where.customerPhone,
      );
    }

    const paginated = applyPagination(filtered, args.skip, args.take);
    return convexToPrismaShapeMany(paginated, CONVERSATION_TS_FIELDS);
  },

  async findFirst(args: {
    where?: Record<string, unknown>;
    include?: Record<string, unknown>;
    select?: Record<string, boolean>;
  }) {
    if (!isConvex()) {
      return prisma.whatsapp_conversations.findFirst(args as any);
    }

    const where = (args.where || {}) as Record<string, unknown>;
    const userId = where.userId as string | undefined;

    const docs =
      (await convexQuery<ConvexDoc[]>("whatsapp/queries:getConversations", {
        userId: userId || "",
        limit: 1000,
      })) || [];

    const match = docs.find((doc) => {
      for (const [key, value] of Object.entries(where)) {
        if (key === "id") {
          if ((doc.prismaId || doc._id) !== value) return false;
        } else if (doc[key] !== value) {
          return false;
        }
      }
      return true;
    });

    return match ? convexToPrismaShape(match, CONVERSATION_TS_FIELDS) : null;
  },

  async findUnique(args: {
    where: { id: string };
    include?: Record<string, unknown>;
    select?: Record<string, boolean>;
  }) {
    if (!isConvex()) {
      return prisma.whatsapp_conversations.findUnique(args as any);
    }

    return conversations.findFirst({ where: args.where });
  },

  async count(args?: { where?: Record<string, unknown> }) {
    if (!isConvex()) {
      return prisma.whatsapp_conversations.count(args as any);
    }

    const where = (args?.where || {}) as Record<string, unknown>;
    const userId = where.userId as string | undefined;
    const status = where.status as string | undefined;

    const docs =
      (await convexQuery<ConvexDoc[]>("whatsapp/queries:getConversations", {
        userId: userId || "",
        ...(status ? { status } : {}),
        limit: 10000,
      })) || [];

    // Apply additional filters
    let filtered = docs;
    if (where.customerPhone) {
      filtered = filtered.filter(
        (d) => d.customerPhone === where.customerPhone,
      );
    }
    if (
      where.status &&
      typeof where.status === "object" &&
      "in" in (where.status as object)
    ) {
      const inValues = (where.status as { in: string[] }).in;
      filtered = filtered.filter((d) => inValues.includes(d.status as string));
    }
    if (where.createdAt && typeof where.createdAt === "object") {
      const gte = (where.createdAt as { gte?: Date }).gte;
      const lte = (where.createdAt as { lte?: Date }).lte;
      if (gte) {
        const gteMs = gte.getTime();
        filtered = filtered.filter((d) => (d.createdAt as number) >= gteMs);
      }
      if (lte) {
        const lteMs = lte.getTime();
        filtered = filtered.filter((d) => (d.createdAt as number) <= lteMs);
      }
    }

    return filtered.length;
  },

  async create(args: { data: Record<string, unknown> }) {
    if (!isConvex()) {
      return prisma.whatsapp_conversations.create(args as any);
    }

    const d = args.data;
    const convexId = await convexMutation<string>(
      "whatsapp/mutations:createConversation",
      {
        userId: d.userId as string,
        customerPhone: d.customerPhone as string,
        ...(d.customerName ? { customerName: d.customerName as string } : {}),
        ...(d.tags && Array.isArray(d.tags)
          ? { tags: d.tags as string[] }
          : {}),
      },
    );

    return {
      id: (d.id as string) || convexId || "",
      userId: d.userId,
      customerPhone: d.customerPhone,
      customerName: d.customerName ?? null,
      lastMessage: d.lastMessage ?? null,
      lastMessageAt: d.lastMessageAt ?? null,
      status: d.status || "active",
      tags: d.tags ?? [],
      aiActions: d.aiActions ?? null,
      summary: d.summary ?? null,
      bookingId: d.bookingId ?? null,
      unreadCount: d.unreadCount ?? 0,
      createdAt: new Date(),
      updatedAt: new Date(),
    };
  },

  async update(args: {
    where: { id: string };
    data: Record<string, unknown>;
    include?: Record<string, unknown>;
    select?: Record<string, boolean>;
  }) {
    if (!isConvex()) {
      return prisma.whatsapp_conversations.update(args as any);
    }

    const d = args.data;

    // Status update
    if (d.status) {
      await convexMutation("whatsapp/mutations:updateConversationStatus", {
        id: args.where.id,
        status: d.status as string,
      });
    }

    // Mark read (reset unread count)
    if (d.unreadCount === 0) {
      await convexMutation("whatsapp/mutations:markRead", {
        id: args.where.id,
      });
    }

    const existing = await conversations.findFirst({
      where: { id: args.where.id },
    });
    return existing ? { ...existing, ...d } : null;
  },

  async groupBy(args: {
    by: string[];
    _count: Record<string, boolean>;
    where?: Record<string, unknown>;
  }) {
    if (!isConvex()) {
      return prisma.whatsapp_conversations.groupBy(args as any);
    }

    const where = (args.where || {}) as Record<string, unknown>;
    const userId = where.userId as string | undefined;

    const docs =
      (await convexQuery<ConvexDoc[]>("whatsapp/queries:getConversations", {
        userId: userId || "",
        limit: 10000,
      })) || [];

    const field = args.by[0];
    const groups: Record<string, number> = {};
    for (const doc of docs) {
      const val = doc[field] as string;
      groups[val] = (groups[val] || 0) + 1;
    }

    return Object.entries(groups).map(([value, cnt]) => ({
      [field]: value,
      _count: { id: cnt },
    }));
  },
};

// =============================================================================
// Conversation Messages
// =============================================================================

const conversationMessages = {
  async findMany(args: {
    where?: Record<string, unknown>;
    orderBy?: Record<string, string> | Record<string, string>[];
    take?: number;
    skip?: number;
    select?: Record<string, boolean>;
  }) {
    if (!isConvex()) {
      return prisma.conversation_messages.findMany(args as any);
    }

    const where = (args.where || {}) as Record<string, unknown>;
    const conversationId = where.conversationId as string | undefined;

    if (!conversationId) {
      return [];
    }

    const limit = (args.take || 100) + (args.skip || 0);
    const docs =
      (await convexQuery<ConvexDoc[]>("whatsapp/queries:getMessages", {
        conversationId,
        limit,
      })) || [];

    // Apply additional filters
    let filtered = docs;
    if (where.sender) {
      filtered = filtered.filter((d) => d.sender === where.sender);
    }

    const paginated = applyPagination(filtered, args.skip, args.take);
    return convexToPrismaShapeMany(paginated, ["timestamp"]);
  },

  async count(args?: { where?: Record<string, unknown> }) {
    if (!isConvex()) {
      return prisma.conversation_messages.count(args as any);
    }

    const where = (args?.where || {}) as Record<string, unknown>;
    const conversationId = where.conversationId as string | undefined;
    if (!conversationId) return 0;

    const docs =
      (await convexQuery<ConvexDoc[]>("whatsapp/queries:getMessages", {
        conversationId,
        limit: 10000,
      })) || [];

    let filtered = docs;
    if (where.sender) {
      filtered = filtered.filter((d) => d.sender === where.sender);
    }

    return filtered.length;
  },

  async create(args: { data: Record<string, unknown> }) {
    if (!isConvex()) {
      return prisma.conversation_messages.create(args as any);
    }

    const d = args.data;
    const convexId = await convexMutation<string>(
      "whatsapp/mutations:sendMessage",
      {
        conversationId: d.conversationId as string,
        sender: d.sender as string,
        message: d.message as string,
        ...(d.metadata !== undefined ? { metadata: d.metadata } : {}),
      },
    );

    return {
      id: (d.id as string) || convexId || "",
      conversationId: d.conversationId,
      sender: d.sender,
      message: d.message,
      timestamp: new Date(),
      metadata: d.metadata ?? null,
    };
  },
};

// =============================================================================
// Org WhatsApp Conversations (multi-tenant AI agent)
// =============================================================================

const orgConversations = {
  async findMany(args: {
    where?: Record<string, unknown>;
    include?: Record<string, unknown>;
    orderBy?: Record<string, string> | Record<string, string>[];
    take?: number;
    skip?: number;
    select?: Record<string, boolean>;
  }) {
    if (!isConvex()) {
      return prisma.org_whatsapp_conversations.findMany(args as any);
    }

    const where = (args.where || {}) as Record<string, unknown>;
    const organizationId = where.organizationId as string | undefined;
    const status = where.status as string | undefined;
    const limit = (args.take || 100) + (args.skip || 0);

    const docs =
      (await convexQuery<ConvexDoc[]>("whatsapp/queries:getOrgConversations", {
        organizationId: organizationId || "",
        ...(status ? { status } : {}),
        limit,
      })) || [];

    // Apply additional where filters
    let filtered = docs;
    if (where.userPhone) {
      filtered = filtered.filter((d) => d.userPhone === where.userPhone);
    }
    if (where.humanControlled !== undefined) {
      filtered = filtered.filter(
        (d) => d.humanControlled === where.humanControlled,
      );
    }

    const paginated = applyPagination(filtered, args.skip, args.take);
    return convexToPrismaShapeMany(paginated, ORG_CONVERSATION_TS_FIELDS);
  },

  async findFirst(args: {
    where?: Record<string, unknown>;
    include?: Record<string, unknown>;
    select?: Record<string, boolean>;
  }) {
    if (!isConvex()) {
      return prisma.org_whatsapp_conversations.findFirst(args as any);
    }

    const where = (args.where || {}) as Record<string, unknown>;
    const organizationId = where.organizationId as string | undefined;

    const docs =
      (await convexQuery<ConvexDoc[]>("whatsapp/queries:getOrgConversations", {
        organizationId: organizationId || "",
        limit: 1000,
      })) || [];

    const match = docs.find((doc) => {
      for (const [key, value] of Object.entries(where)) {
        if (key === "id") {
          if ((doc.prismaId || doc._id) !== value) return false;
        } else if (doc[key] !== value) {
          return false;
        }
      }
      return true;
    });

    return match
      ? convexToPrismaShape(match, ORG_CONVERSATION_TS_FIELDS)
      : null;
  },

  async findUnique(args: {
    where: { id: string } | Record<string, unknown>;
    include?: Record<string, unknown>;
    select?: Record<string, boolean>;
  }) {
    if (!isConvex()) {
      return prisma.org_whatsapp_conversations.findUnique(args as any);
    }

    return orgConversations.findFirst({
      where: args.where as Record<string, unknown>,
    });
  },

  async count(args?: { where?: Record<string, unknown> }) {
    if (!isConvex()) {
      return prisma.org_whatsapp_conversations.count(args as any);
    }

    const where = (args?.where || {}) as Record<string, unknown>;
    const organizationId = where.organizationId as string | undefined;

    const docs =
      (await convexQuery<ConvexDoc[]>("whatsapp/queries:getOrgConversations", {
        organizationId: organizationId || "",
        limit: 10000,
      })) || [];

    return docs.length;
  },

  async create(args: { data: Record<string, unknown> }) {
    if (!isConvex()) {
      return prisma.org_whatsapp_conversations.create(args as any);
    }

    const d = args.data;
    const convexId = await convexMutation<string>(
      "whatsapp/mutations:createOrgConversation",
      {
        organizationId: d.organizationId as string,
        userPhone: d.userPhone as string,
        ...(d.userName ? { userName: d.userName as string } : {}),
        language: (d.language as string) || "en",
      },
    );

    return {
      id: (d.id as string) || convexId || "",
      organizationId: d.organizationId,
      userPhone: d.userPhone,
      userName: d.userName ?? null,
      language: d.language || "en",
      status: d.status || "active",
      lastMessageAt: d.lastMessageAt ?? null,
      messageCount: d.messageCount ?? 0,
      conversationState: d.conversationState ?? null,
      customerEmail: d.customerEmail ?? null,
      humanControlled: d.humanControlled ?? false,
      humanControlledAt: d.humanControlledAt ?? null,
      humanControlledBy: d.humanControlledBy ?? null,
      createdAt: new Date(),
      updatedAt: new Date(),
    };
  },

  async update(args: { where: { id: string }; data: Record<string, unknown> }) {
    if (!isConvex()) {
      return prisma.org_whatsapp_conversations.update(args as any);
    }

    // Convex doesn't have a generic update for org conversations yet.
    // Return best-effort merged shape.
    const existing = await orgConversations.findFirst({
      where: { id: args.where.id },
    });
    return existing
      ? { ...existing, ...args.data, updatedAt: new Date() }
      : null;
  },
};

// =============================================================================
// Org WhatsApp Messages
// =============================================================================

const orgMessages = {
  async findMany(args: {
    where?: Record<string, unknown>;
    orderBy?: Record<string, string> | Record<string, string>[];
    take?: number;
    skip?: number;
    select?: Record<string, boolean>;
  }) {
    if (!isConvex()) {
      return prisma.org_whatsapp_messages.findMany(args as any);
    }

    // Convex doesn't have a dedicated query for org messages yet.
    // Fall back to prisma for now.
    // TODO: Add getOrgMessages query to Convex whatsapp domain
    return prisma.org_whatsapp_messages.findMany(args as any);
  },

  async create(args: { data: Record<string, unknown> }) {
    if (!isConvex()) {
      return prisma.org_whatsapp_messages.create(args as any);
    }

    const d = args.data;
    const convexId = await convexMutation<string>(
      "whatsapp/mutations:sendOrgMessage",
      {
        conversationId: d.conversationId as string,
        role: d.role as string,
        content: d.content as string,
        language: (d.language as string) || "en",
        ...(d.intent ? { intent: d.intent as string } : {}),
        ...(d.toolsUsed && Array.isArray(d.toolsUsed)
          ? { toolsUsed: d.toolsUsed as string[] }
          : {}),
        ...(d.metadata !== undefined ? { metadata: d.metadata } : {}),
      },
    );

    return {
      id: (d.id as string) || convexId || "",
      conversationId: d.conversationId,
      role: d.role,
      content: d.content,
      language: d.language || "en",
      intent: d.intent ?? null,
      toolsUsed: d.toolsUsed ?? [],
      metadata: d.metadata ?? null,
      timestamp: new Date(),
    };
  },

  async count(args?: { where?: Record<string, unknown> }) {
    if (!isConvex()) {
      return prisma.org_whatsapp_messages.count(args as any);
    }

    // No dedicated Convex query for org message count yet
    return prisma.org_whatsapp_messages.count(args as any);
  },
};

// =============================================================================
// Company Knowledge Base
// =============================================================================

const knowledgeBase = {
  async findMany(args: {
    where?: Record<string, unknown>;
    orderBy?: Record<string, string> | Record<string, string>[];
    take?: number;
    skip?: number;
    select?: Record<string, boolean>;
  }) {
    if (!isConvex()) {
      return prisma.company_knowledge_base.findMany(args as any);
    }

    // Knowledge base queries with OR conditions and insensitive search
    // are complex for Convex -- fall back to prisma for full-text search
    // TODO: Add Convex full-text search when migrating knowledge base
    return prisma.company_knowledge_base.findMany(args as any);
  },

  async findFirst(args: { where?: Record<string, unknown> }) {
    if (!isConvex()) {
      return prisma.company_knowledge_base.findFirst(args as any);
    }

    return prisma.company_knowledge_base.findFirst(args as any);
  },

  async findUnique(args: { where: { id: string } | Record<string, unknown> }) {
    if (!isConvex()) {
      return prisma.company_knowledge_base.findUnique(args as any);
    }

    return prisma.company_knowledge_base.findUnique(args as any);
  },

  async create(args: { data: Record<string, unknown> }) {
    if (!isConvex()) {
      return prisma.company_knowledge_base.create(args as any);
    }

    return prisma.company_knowledge_base.create(args as any);
  },

  async update(args: { where: { id: string }; data: Record<string, unknown> }) {
    if (!isConvex()) {
      return prisma.company_knowledge_base.update(args as any);
    }

    return prisma.company_knowledge_base.update(args as any);
  },

  async deleteOne(args: { where: { id: string } }) {
    if (!isConvex()) {
      return prisma.company_knowledge_base.delete(args as any);
    }

    return prisma.company_knowledge_base.delete(args as any);
  },

  async count(args?: { where?: Record<string, unknown> }) {
    if (!isConvex()) {
      return prisma.company_knowledge_base.count(args as any);
    }

    return prisma.company_knowledge_base.count(args as any);
  },
};

// =============================================================================
// User Language Preferences
// =============================================================================

const languagePreferences = {
  async findUnique(args: { where: Record<string, unknown> }) {
    if (!isConvex()) {
      return prisma.user_language_preferences.findUnique(args as any);
    }

    // No dedicated Convex query yet
    return prisma.user_language_preferences.findUnique(args as any);
  },

  async findFirst(args: { where?: Record<string, unknown> }) {
    if (!isConvex()) {
      return prisma.user_language_preferences.findFirst(args as any);
    }

    return prisma.user_language_preferences.findFirst(args as any);
  },

  async upsert(args: {
    where: Record<string, unknown>;
    create: Record<string, unknown>;
    update: Record<string, unknown>;
  }) {
    if (!isConvex()) {
      return prisma.user_language_preferences.upsert(args as any);
    }

    return prisma.user_language_preferences.upsert(args as any);
  },
};

// =============================================================================
// Namespace Exports
// =============================================================================

export const whatsappConversationsAdapter = conversations;
export const conversationMessagesAdapter = conversationMessages;
export const orgWhatsappConversationsAdapter = orgConversations;
export const orgWhatsappMessagesAdapter = orgMessages;
export const companyKnowledgeBaseAdapter = knowledgeBase;
export const userLanguagePreferencesAdapter = languagePreferences;
