//This is a service which will download data for the latest updated Mantis tickets and store them in the database.
//It will also download all the notes and attachments for each ticket.

import axios from 'axios';

import { getSetting } from '../utils/settings.js';

import prisma from '../database.js';

import { logger } from '../utils/logging.js';

export async function getMantisSettings()
{
  const MANTIS_API_KEY = await getSetting('MANTIS_API_KEY');
  const MANTIS_API_ENDPOINT = await getSetting('MANTIS_API_ENDPOINT');

  if (!MANTIS_API_ENDPOINT || !MANTIS_API_KEY)
  {
    return {
      url: null,
      headers: null,
    };
  }
  const headers = {
    Authorization: `${MANTIS_API_KEY}`,
    Accept: 'application/json',
    'Content-Type': 'application/json',
  };

  return { url: MANTIS_API_ENDPOINT, headers };
}

export async function getLatestMantisTickets()
{
  const { url, headers } = await getMantisSettings();
  const ticketUrl = `${url}/issues?project_id=1&page_size=50&select=id,updated_at`;
  try
  {
    const response = await axios.get(ticketUrl, { headers });
    return response.data.issues;
  }
  catch (error)
  {
    logger.error('Error fetching tickets data:', error);
    return [];
  }
}

export async function getDataForMantisTicket(ticketId)
{
  const { url, headers } = await getMantisSettings();
  // Removed notes from select, as they are fetched separately with attachments
  const ticketUrl = `${url}/issues/${ticketId}?select=id,summary,description,created_at,updated_at,reporter,status,severity,priority,notes`;
  try
  {
    const response = await axios.get(ticketUrl, { headers });
    // Assuming response.data contains the issue object directly
    return response.data.issues && response.data.issues.length > 0 ? response.data.issues[0] : null;
  }
  catch (error)
  {
    logger.error(`Error fetching ticket data for ID ${ticketId}:`, error);
    throw new Error(`Failed to fetch ticket data for ID ${ticketId} from Mantis.`);
  }
}

export async function saveTicketToDatabase(ticketId)
{
  const ticketData = await getDataForMantisTicket(ticketId);

  if (!ticketData)
  {
    logger.warn(`No ticket data found for ID ${ticketId}. Skipping save.`);
    return null;
  }

  const ticketInDb = await prisma.$transaction(async(tx) =>
  {
    const reporterUsername = ticketData.reporter?.name;

    const ticket = await tx.mantisIssue.upsert({
      where: { id: ticketId },
      update: {
        title: ticketData.summary,
        description: ticketData.description,
        reporterUsername,
        status: ticketData.status.name,
        priority: ticketData.priority.name,
        severity: ticketData.severity.name,
        updatedAt: new Date(ticketData.updated_at),
      },
      create: {
        id: ticketId,
        title: ticketData.summary,
        description: ticketData.description,
        reporterUsername,
        status: ticketData.status.name,
        priority: ticketData.priority.name,
        severity: ticketData.severity.name,
        createdAt: new Date(ticketData.created_at),
        updatedAt: new Date(ticketData.updated_at),
      },
    });
    logger.info(`Ticket ${ticketId} saved to database.`);

    // Process notes
    if (ticketData.notes && ticketData.notes.length > 0)
    {
      for (const note of ticketData.notes)
      {
        const noteReporter = note.reporter?.name || 'Unknown Reporter';

        const comment = await tx.mantisComment.create({
          data: {
            mantisIssueId: ticketId,
            senderUsername: noteReporter,
            comment: note.text,
            createdAt: new Date(note.created_at),
          },
        });

        // Process attachments for the note
        if (note.attachments && note.attachments.length > 0)
        {
          for (const attachment of note.attachments)
          {
            const attachmentData = {
              commentId: comment.id,
              filename: attachment.filename,
              url: '/mantis/attachment/' + ticketId + '/' + attachment.id,
              mimeType: attachment.content_type,
              size: attachment.size,
              uploadedAt: new Date(attachment.created_at),
            };

            await tx.mantisAttachment.create({
              data: attachmentData,
            });
            logger.info(`Attachment ${attachment.filename} for ticket ${ticketId} saved to database.`);
          }
        }
      }
    }

    return ticket;
  });

  return ticketInDb;
}

async function processNewMantisTickets()
{
  logger.info('Checking for new Mantis tickets...');
  const issues = await getLatestMantisTickets();

  if (!issues)
  {
    logger.warn('No issues returned from getLatestMantisTickets.');
    return;
  }

  //Check if the tickets exist, and if not, or if they have a newer updated_at date, add them to the download queue
  for (const issue of issues)
  {
    const ticketId = issue.id;
    const existingTicket = await prisma.mantisIssue.findUnique({ // Changed from prisma.ticket to prisma.mantisIssue
      where: { id: ticketId },
      select: { updatedAt: true } // Only select needed field
    });

    if (!existingTicket || new Date(issue.updated_at) > new Date(existingTicket.updatedAt)) // Changed existingTicket.updated_at to existingTicket.updatedAt
    {
      // Avoid adding duplicates to the queue
      if (!downloadQueue.includes(ticketId))
      {
        downloadQueue.push(ticketId);
        logger.info(`Queueing ticket ${ticketId} for processing.`);
      }
    }
  }
}

async function processTicketsInQueue()
{
  if (downloadQueue.length === 0)
  {
    return;
  }
  logger.info(`Processing tickets in queue: ${downloadQueue.length} tickets remaining.`);

  // const ticketId = downloadQueue.shift();
  //Pick a random ticket from the queue
  const randomIndex = Math.floor(Math.random() * downloadQueue.length);
  const ticketId = downloadQueue[randomIndex];
  downloadQueue.splice(randomIndex, 1);
  try
  {
    logger.info(`Processing ticket ${ticketId}...`);
    await saveTicketToDatabase(ticketId);
    logger.info(`Ticket ${ticketId} processed and saved to database.`);
  }
  catch (error)
  {
    console.log(error);
    logger.error(`Error processing ticket ${ticketId}:`, error);
    // Optionally, you can re-add the ticket to the queue for retrying later
    downloadQueue.push(ticketId);
  }
}

const downloadQueue = [];

export async function setup()
{
  try
  {
    // Initialize the download queue
    downloadQueue.length = 0;

    // Start the process of checking for new tickets
    processNewMantisTickets();
    setInterval(processNewMantisTickets, 5 * 60 * 1000); // Check for new tickets every 5 minutes
    setInterval(processTicketsInQueue, 1 * 1000); // Process the queue every 10 seconds

    if(process.env.LOAD_ALL_MANTISES == 'true')
    {
      for (let i = 3000; i <= 5100; i++)
      {
        //Check if the ticket already exists in the database
        const existingTicket = await prisma.mantisIssue.findUnique({
          where: { id: i },
          select: { updatedAt: true } // Only select needed field
        });

        if (!existingTicket)
        {
          downloadQueue.push(i);
        }
      }
    }
  }
  catch(error)
  {
    logger.error('Error setting up Mantis downloader:', error);
  }
}