const logger = require("../utils/logger");
const queries = require("../graphql-client/queries");
const moment = require("moment");
const { captureFixture } = require("./utils/seralizeHelper");
const { TotalsServerSide: totalsServerSideCA } = require("./job-totals"); // Canadian version (imex)
const { TotalsServerSide: totalsServerSideUS } = require("./job-totals-USA");
const InstanceMgr = require("../utils/instanceMgr").default;
const { uploadFileToS3 } = require("../utils/s3");

// requires two buckets be made per env, job-totals-test, job-totals-production, locally it will
// use `job-totals` in the owncloud stack

/**
 * Returns the environment prefix based on NODE_ENV
 * @returns {string}
 */
const getEnvPrefix = () => {
  switch (process.env?.NODE_ENV) {
    case "test":
      return "test";
    case "production":
      return "production";
    default:
      return "test";
  }
};

const envPrefix = getEnvPrefix();

const S3_BUCKET_NAME =
  process.env?.NODE_ENV === "development"
    ? "imex-job-totals"
    : InstanceMgr({
        imex: `job-totals-${envPrefix}`,
        rome: `job-totals-${envPrefix}-rome`
      });

/**
 * Generates a unique S3 key for the job totals file
 * @param {string} jobId - The job ID
 * @returns {string} - S3 key with timestamp
 */
const generateS3Key = (jobId) => `${jobId}-${moment().toISOString()}.json`;

/**
 * Uploads job totals data to S3
 * @param {object} data - The data to upload
 * @param {string} jobId - The job ID
 * @param {object} userInfo - User information for logging
 * @returns {Promise<string>} - The S3 key
 */
const uploadJobTotalsToS3 = async (data, jobId, userInfo) => {
  const key = generateS3Key(jobId);

  try {
    await uploadFileToS3({
      bucketName: S3_BUCKET_NAME,
      key: key,
      content: JSON.stringify(data, null, 2),
      contentType: "application/json"
    });

    logger.log(`Job totals uploaded successfully to ${key}`, "info", userInfo.email, jobId);
    return key;
  } catch (error) {
    logger.log("Failed to upload job totals to S3", "error", userInfo.email, jobId, {
      error: error?.message,
      stack: error?.stack
    });
    throw error; // Re-throw for the main handler to catch
  }
};

/**
 * Fetches job data using GraphQL
 * @param {object} client - GraphQL client
 * @param {string} token - Bearer token
 * @param {string} jobId - Job ID to fetch
 * @returns {Promise<object>} - Job data
 */
const fetchJobData = async (client, token, jobId) => {
  return client
    .setHeaders({ Authorization: token })
    .request(queries.GET_JOB_BY_PK, { id: jobId })
    .then((response) => response.jobs_by_pk);
};

/**
 * This function is used to capture job totals json files.
 * @param {object} req - Express request
 * @param {object} res - Express response
 * @returns {Promise<void>}
 */
const jobTotalsRecorder = async (req, res) => {
  const { id: jobId } = req.body;
  const bearerToken = req.BearerToken;
  const client = req.userGraphQLClient;
  const userEmail = req?.user?.email;

  logger.log("Starting job totals recording", "debug", userEmail, jobId);

  try {
    // Fetch job data
    const jobData = await fetchJobData(client, bearerToken, jobId);

    // Get the appropriate totals function based on instance
    const totalsFunction = InstanceMgr({
      imex: totalsServerSideCA,
      rome: totalsServerSideUS
    });

    // Calculate the totals
    const calculatedTotals = await totalsFunction({ body: { job: jobData, client }, req }, res, true);

    // Prepare data for storage
    const dataToSave = captureFixture(jobData, calculatedTotals);

    // Upload to S3
    await uploadJobTotalsToS3(dataToSave, jobId, { email: userEmail });

    res.status(200).json({ success: true, message: "Job totals recorded successfully" });
  } catch (error) {
    logger.log("Failed to record job totals", "error", userEmail, jobId, {
      error: error?.message,
      stack: error?.stack
    });

    // Avoid sending response if it's already been sent
    if (!res.headersSent) {
      res.status(503).json({
        success: false,
        message: "Error processing job totals",
        error: error.message
      });
    }
  }
};

module.exports = jobTotalsRecorder;
