/**
 * Support Domain Adapter
 *
 * Routes support_tickets and ticket_messages CRUD to Prisma or Convex.
 * Note: Convex path does NOT resolve user joins — the service layer handles that separately.
 */

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 = "support" as const;
const TICKET_TS_FIELDS = ["createdAt", "updatedAt", "resolvedAt"];
const MESSAGE_TS_FIELDS = ["createdAt", "readAt"];

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

// ═══════════════════════════════════════════════════════════════════════════
// Support Tickets
// ═══════════════════════════════════════════════════════════════════════════

const tickets = {
  async findMany(args: {
    where?: Record<string, unknown>;
    include?: Record<string, unknown>;
    orderBy?: Record<string, string> | Record<string, string>[];
    take?: number;
    skip?: number;
  }) {
    if (!isConvex()) {
      return prisma.support_tickets.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[]>("support/queries:getTickets", {
        ...(userId ? { userId } : { userId: "" }),
        ...(status ? { status } : {}),
        limit,
      })) || [];

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

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

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

    const where = (args.where || {}) as Record<string, unknown>;
    const id = where.id as string;
    if (id) {
      const doc = await convexQuery<ConvexDoc | null>(
        "support/queries:getTicketById",
        { id },
      );
      return doc ? convexToPrismaShape(doc, TICKET_TS_FIELDS) : null;
    }

    // Fallback: fetch by userId and filter
    const userId = where.userId as string;
    const docs =
      (await convexQuery<ConvexDoc[]>("support/queries:getTickets", {
        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, TICKET_TS_FIELDS) : null;
  },

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

    const doc = await convexQuery<ConvexDoc | null>(
      "support/queries:getTicketById",
      { id: args.where.id },
    );
    return doc ? convexToPrismaShape(doc, TICKET_TS_FIELDS) : null;
  },

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

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

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

    // Apply additional filters
    let filtered = docs;
    if (where.priority) {
      const p = where.priority;
      if (typeof p === "object" && p !== null && "in" in (p as object)) {
        const inValues = (p as { in: string[] }).in;
        filtered = filtered.filter((d) =>
          inValues.includes(d.priority as string),
        );
      } else {
        filtered = filtered.filter((d) => d.priority === p);
      }
    }
    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));
    }

    return filtered.length;
  },

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

    const d = args.data;
    const convexId = await convexMutation<string>(
      "support/mutations:createTicket",
      {
        userId: d.userId as string,
        subject: d.subject as string,
        message: d.message as string,
        category: d.category as string,
        ...(d.priority ? { priority: d.priority as string } : {}),
        ...(d.attachments ? { attachments: d.attachments } : {}),
      },
    );

    return {
      id: (d.id as string) || convexId || "",
      userId: d.userId,
      subject: d.subject,
      category: d.category,
      priority: d.priority || "NORMAL",
      message: d.message,
      status: d.status || "OPEN",
      attachments: d.attachments ?? null,
      resolvedAt: null,
      resolvedBy: null,
      resolution: null,
      createdAt: new Date(),
      updatedAt: new Date(),
    };
  },

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

    const d = args.data;
    // Check if this is a status update
    if (d.status) {
      await convexMutation("support/mutations:updateStatus", {
        id: args.where.id,
        status: d.status as string,
        ...(d.resolvedBy ? { resolvedBy: d.resolvedBy as string } : {}),
        ...(d.resolution ? { resolution: d.resolution as string } : {}),
      });
    } else {
      // General field update
      await convexMutation("support/mutations:updateTicket", {
        id: args.where.id,
        ...(d.subject ? { subject: d.subject as string } : {}),
        ...(d.message ? { message: d.message as string } : {}),
        ...(d.category ? { category: d.category as string } : {}),
        ...(d.priority ? { priority: d.priority as string } : {}),
      });
    }

    // Return best-effort shape
    const existing = await tickets.findUnique({ where: { id: args.where.id } });
    return existing ? { ...existing, ...d } : null;
  },

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

    // Fetch all tickets and group manually
    const docs =
      (await convexQuery<ConvexDoc[]>("support/queries:getTickets", {
        userId: "",
        limit: 10000,
      })) || [];

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

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

// ═══════════════════════════════════════════════════════════════════════════
// Ticket Messages
// ═══════════════════════════════════════════════════════════════════════════

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

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

    if (!ticketId) {
      // Need ticketId for Convex query — can't fetch all messages globally
      return [];
    }

    const docs =
      (await convexQuery<ConvexDoc[]>("support/queries:getMessages", {
        ticketId,
      })) || [];

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

    return convexToPrismaShapeMany(filtered, MESSAGE_TS_FIELDS);
  },

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

    const d = args.data;
    const convexId = await convexMutation<string>(
      "support/mutations:addMessage",
      {
        ticketId: d.ticketId as string,
        senderId: d.senderId as string,
        senderType: d.senderType as string,
        message: d.message as string,
        ...(d.attachments ? { attachments: d.attachments } : {}),
      },
    );

    return {
      id: (d.id as string) || convexId || "",
      ticketId: d.ticketId,
      senderId: d.senderId,
      senderType: d.senderType,
      message: d.message,
      attachments: d.attachments ?? null,
      isRead: false,
      readAt: null,
      createdAt: new Date(),
    };
  },

  async updateMany(args: {
    where: Record<string, unknown>;
    data: Record<string, unknown>;
  }): Promise<BatchResult> {
    if (!isConvex()) {
      return prisma.ticket_messages.updateMany(args as any);
    }

    // Fetch messages for the ticket and update matching ones
    const where = args.where;
    const ticketId = where.ticketId as string;
    if (!ticketId) return { count: 0 };

    const docs =
      (await convexQuery<ConvexDoc[]>("support/queries:getMessages", {
        ticketId,
      })) || [];

    let matching = docs;
    if (where.senderType) {
      matching = matching.filter((d) => d.senderType === where.senderType);
    }
    if (where.isRead !== undefined) {
      matching = matching.filter((d) => d.isRead === where.isRead);
    }

    // Convex doesn't have a bulk update for messages — would need a new mutation
    // For now, return count without actual update (Convex mutations need to be added)
    // TODO: Add markMessagesRead mutation to Convex support domain
    return { count: matching.length };
  },

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

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

    // Need support_tickets relation for userId-based queries
    if (where.support_tickets) {
      // Complex relation query — fall back to prisma for now
      // TODO: Implement when support domain fully migrates
      return prisma.ticket_messages.count(args as any);
    }

    if (!ticketId) return 0;

    const docs =
      (await convexQuery<ConvexDoc[]>("support/queries:getMessages", {
        ticketId,
      })) || [];

    let filtered = docs;
    if (where.senderType) {
      filtered = filtered.filter((d) => d.senderType === where.senderType);
    }
    if (where.isRead !== undefined) {
      filtered = filtered.filter((d) => d.isRead === where.isRead);
    }

    return filtered.length;
  },
};

// --- Namespace exports ---------------------------------------------------

export const supportTicketsAdapter = tickets;
export const ticketMessagesAdapter = messages;
