import { prisma } from "~/db.server";
import { getEpisode } from "./graphModels/episode";
import { getSpacesForEpisodes } from "./graphModels/space";

export async function getIngestionLogs(
  userId: string,
  page: number = 1,
  limit: number = 10,
) {
  const user = await prisma.user.findUnique({
    where: {
      id: userId,
    },
    include: {
      Workspace: true,
    },
  });

  const skip = (page - 1) * limit;

  const [ingestionLogs, total] = await Promise.all([
    prisma.ingestionQueue.findMany({
      where: {
        workspaceId: user?.Workspace?.id,
      },
      skip,
      take: limit,
      orderBy: {
        createdAt: "desc",
      },
    }),
    prisma.ingestionQueue.count({
      where: {
        workspaceId: user?.Workspace?.id,
      },
    }),
  ]);

  return {
    ingestionLogs,
    pagination: {
      total,
      pages: Math.ceil(total / limit),
      currentPage: page,
      limit,
    },
  };
}

export const getIngestionQueue = async (id: string) => {
  return await prisma.ingestionQueue.findUnique({
    where: {
      id,
    },
  });
};

export const getIngestionQueueForFrontend = async (
  id: string,
  userId: string,
) => {
  // Fetch the specific log by logId
  const log = await prisma.ingestionQueue.findUnique({
    where: { id: id },
    select: {
      id: true,
      createdAt: true,
      processedAt: true,
      status: true,
      error: true,
      type: true,
      output: true,
      data: true,
      workspaceId: true,
      activity: {
        select: {
          text: true,
          sourceURL: true,
          integrationAccount: {
            select: {
              integrationDefinition: {
                select: {
                  name: true,
                  slug: true,
                },
              },
            },
          },
        },
      },
    },
  });

  if (!log) {
    throw new Response("Log not found", { status: 404 });
  }

  // Format the response
  const integrationDef =
    log.activity?.integrationAccount?.integrationDefinition;
  const logData = log.data as any;

  const formattedLog: any = {
    id: log.id,
    source: integrationDef?.name || logData?.source || "Unknown",
    ingestText:
      log.activity?.text ||
      logData?.episodeBody ||
      logData?.text ||
      "No content",
    time: log.createdAt,
    processedAt: log.processedAt,
    episodeUUID: (log.output as any)?.episodeUuid,
    status: log.status,
    error: log.error,
    sourceURL: log.activity?.sourceURL,
    integrationSlug: integrationDef?.slug,
    data: log.data,
  };

  // Fetch space data based on log type
  if (logData?.type === "CONVERSATION" && formattedLog?.episodeUUID) {
    // For CONVERSATION type: get spaceIds for the single episode
    const spacesMap = await getSpacesForEpisodes(
      [formattedLog.episodeUUID],
      userId,
    );
    formattedLog.spaceIds = spacesMap[formattedLog.episodeUUID] || [];
  } else if (
    logData?.type === "DOCUMENT" &&
    (log.output as any)?.episodes?.length > 0
  ) {
    // For DOCUMENT type: get episode details and space information for all episodes
    const episodeIds = (log.output as any)?.episodes.map(
      (e: any) => e.episodeUuid,
    );

    // Fetch all episode details in parallel
    const episodeDetailsPromises = episodeIds.map((episodeId: string) =>
      getEpisode(episodeId).catch(() => null),
    );
    const episodeDetails = await Promise.all(episodeDetailsPromises);

    // Get spaceIds for all episodes
    const spacesMap = await getSpacesForEpisodes(episodeIds, userId);

    // Combine episode details with space information
    formattedLog.episodeDetails = episodeIds.map(
      (episodeId: string, index: number) => {
        const episode = episodeDetails[index];
        return {
          uuid: episodeId,
          content: episode?.content || episode?.originalContent || "No content",
          spaceIds: spacesMap[episodeId] || [],
        };
      },
    );
  }

  return formattedLog;
};

export const getLogByEpisode = async (episodeUuid: string) => {
  // Find logs where the episode UUID matches either:
  // 1. log.output.episodeUuid (single episode - CONVERSATION type)
  // 2. log.output.episodes array (multiple episodes - DOCUMENT type)
  const logs = await prisma.ingestionQueue.findMany({
    where: {
      OR: [
        {
          output: {
            path: ["episodeUuid"],
            equals: episodeUuid,
          },
        },
        {
          output: {
            path: ["episodes"],
            array_contains: episodeUuid,
          },
        },
      ],
    },
    orderBy: {
      createdAt: "desc",
    },
    take: 1,
  });

  return logs[0] || null;
};

export const deleteIngestionQueue = async (id: string) => {
  return await prisma.ingestionQueue.delete({
    where: {
      id,
    },
  });
};
