/**
 * Analytics Domain Adapter
 *
 * Routes conversationLog CRUD to Prisma or Convex based on data-source config.
 * Maintains Prisma-compatible method signatures so service layer changes are minimal.
 *
 * Prisma model: ConversationLog (prisma.conversationLog)
 * Convex table: conversation_logs (voice_agents/mutations, voice_agents/queries)
 */

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

const DOMAIN = "analytics" as const;
const TIMESTAMP_FIELDS = ["createdAt", "updatedAt", "lastMessageAt"];

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

// ─── conversationLog.create ─────────────────────────────────────────────

async function conversationLogCreate(args: {
  data: {
    id: string;
    userId: string;
    platform: string;
    customerPhone?: string | null;
    customerName?: string | null;
    messages: string | unknown;
    metadata?: string | unknown | null;
    status?: string;
    createdAt?: Date;
    updatedAt?: Date;
  };
}) {
  if (!isConvex()) {
    return prisma.conversationLog.create(args as any);
  }

  const d = args.data;
  const convexId = await convexMutation<string>(
    "voice_agents/mutations:createConversationLog",
    {
      userId: d.userId,
      platform: d.platform,
      ...(d.customerPhone ? { customerPhone: d.customerPhone } : {}),
      ...(d.customerName ? { customerName: d.customerName } : {}),
      ...(d.metadata !== undefined && d.metadata !== null
        ? {
            metadata:
              typeof d.metadata === "string"
                ? JSON.parse(d.metadata)
                : d.metadata,
          }
        : {}),
    },
  );

  // Return Prisma-compatible shape
  return {
    id: d.id || convexId || "",
    userId: d.userId,
    platform: d.platform,
    customerPhone: d.customerPhone ?? null,
    customerName: d.customerName ?? null,
    messages: d.messages,
    metadata: d.metadata ?? null,
    status: d.status ?? "open",
    lastMessageAt: null,
    lastMessagePreview: null,
    unreadCount: 0,
    messageCount: 0,
    createdAt: d.createdAt ?? new Date(),
    updatedAt: d.updatedAt ?? new Date(),
  };
}

// ─── conversationLog.findUnique ─────────────────────────────────────────

async function conversationLogFindUnique(args: { where: { id: string } }) {
  if (!isConvex()) {
    return prisma.conversationLog.findUnique(args as any);
  }

  // Convex doesn't have a getById for conversation_logs, so fetch by userId and filter
  // We need to do a broad query. Since we don't know userId, use findFirst pattern.
  return conversationLogFindFirst({ where: { id: args.where.id } });
}

// ─── conversationLog.findFirst ──────────────────────────────────────────

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

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

  if (!userId) {
    // Without userId, we can't efficiently query Convex (no global index).
    // Fall back to Prisma for this edge case.
    return prisma.conversationLog.findFirst(args as any);
  }

  const docs =
    (await convexQuery<ConvexDoc[]>(
      "voice_agents/queries:getConversationLogs",
      { userId, limit: 200 },
    )) || [];

  // Filter by all where conditions
  const match = docs.find((doc) => {
    for (const [key, value] of Object.entries(where)) {
      if (key === "userId") continue; // Already filtered by index
      const docVal = key === "id" ? doc.prismaId || doc._id : doc[key];
      if (docVal !== value) return false;
    }
    return true;
  });

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

// ─── conversationLog.findMany ───────────────────────────────────────────

async function conversationLogFindMany(args: {
  where?: Record<string, unknown>;
  orderBy?: Record<string, string> | Record<string, string>[];
  take?: number;
  skip?: number;
}) {
  if (!isConvex()) {
    return prisma.conversationLog.findMany(args as any);
  }

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

  if (!userId) {
    // Without userId, fall back to Prisma
    return prisma.conversationLog.findMany(args as any);
  }

  const platform = where.platform as string | undefined;
  const status = where.status as string | undefined;

  // Over-fetch to handle skip
  const fetchLimit = (args.take || 100) + (args.skip || 0);

  let docs =
    (await convexQuery<ConvexDoc[]>(
      "voice_agents/queries:getConversationLogs",
      {
        userId,
        ...(platform ? { platform } : {}),
        ...(status ? { status } : {}),
        limit: fetchLimit,
      },
    )) || [];

  // Apply additional where filters (e.g., date ranges)
  const createdAt = where.createdAt as { gte?: Date; lte?: Date } | undefined;
  if (createdAt) {
    if (createdAt.gte) {
      const gteMs = createdAt.gte.getTime();
      docs = docs.filter((d) => (d.createdAt as number) >= gteMs);
    }
    if (createdAt.lte) {
      const lteMs = createdAt.lte.getTime();
      docs = docs.filter((d) => (d.createdAt as number) <= lteMs);
    }
  }

  // Apply skip/take pagination
  const paginated = applyPagination(docs, args.skip, args.take);

  return convexToPrismaShapeMany(paginated, TIMESTAMP_FIELDS);
}

// ─── conversationLog.update ─────────────────────────────────────────────

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

  // Convex voice_agents don't have a generic update for conversation_logs.
  // For status updates and message appends, we handle the common cases.
  // Since there's no dedicated Convex mutation for updating conversation_log fields,
  // fall back to Prisma for the update but return the merged shape.
  // This is safe because analytics domain defaults to prisma until fully migrated.
  return prisma.conversationLog.update(args as any);
}

// ─── Namespace export (mirrors prisma.conversationLog) ──────────────────

export const conversationLog = {
  create: conversationLogCreate,
  findUnique: conversationLogFindUnique,
  findFirst: conversationLogFindFirst,
  findMany: conversationLogFindMany,
  update: conversationLogUpdate,
};

export const analyticsAdapter = {
  conversationLog,
};
