import dotenv from 'dotenv';
import { materialModel } from '../../database/schemas/management/material.schema.js';
import log4js from 'log4js';
import mongoose from 'mongoose';
import { getModelStats, getModelHistory } from '../../database/database.js';
dotenv.config();

const logger = log4js.getLogger('Materials');
logger.level = process.env.LOG_LEVEL;

export const listMaterialsRouteHandler = async (
  req,
  res,
  page = 1,
  limit = 25,
  property = '',
  filter = {}
) => {
  try {
    // Calculate the skip value based on the page number and limit
    const skip = (page - 1) * limit;

    let material;
    let aggregateCommand = [];

    if (filter != {}) {
      // use filtering if present
      aggregateCommand.push({ $match: filter });
    }

    if (property != '') {
      aggregateCommand.push({ $group: { _id: `$${property}` } }); // group all same properties
      aggregateCommand.push({ $project: { _id: 0, [property]: '$_id' } }); // rename _id to the property name
    } else {
      aggregateCommand.push({ $project: { image: 0, url: 0 } });
    }

    aggregateCommand.push({ $skip: skip });
    aggregateCommand.push({ $limit: Number(limit) });

    console.log(aggregateCommand);

    material = await materialModel.aggregate(aggregateCommand);

    logger.trace(
      `List of materials (Page ${page}, Limit ${limit}, Property ${property}):`,
      material
    );
    res.send(material);
  } catch (error) {
    logger.error('Error listing materials:', error);
    res.status(500).send({ error: error });
  }
};

export const getMaterialRouteHandler = async (req, res) => {
  try {
    // Get ID from params
    const id = new mongoose.Types.ObjectId(req.params.id);
    // Fetch the material with the given remote address
    const material = await materialModel.findOne({
      _id: id,
    });

    if (!material) {
      logger.warn(`Material not found with supplied id.`);
      return res.status(404).send({ error: 'Print job not found.' });
    }

    logger.trace(`Material with ID: ${id}:`, material);
    res.send(material);
  } catch (error) {
    logger.error('Error fetching Material:', error);
    res.status(500).send({ error: error.message });
  }
};

export const editMaterialRouteHandler = async (req, res) => {
  try {
    // Get ID from params
    const id = new mongoose.Types.ObjectId(req.params.id);
    // Fetch the material with the given remote address
    const material = await materialModel.findOne({ _id: id });

    if (!material) {
      // Error handling
      logger.warn(`Material not found with supplied id.`);
      return res.status(404).send({ error: 'Print job not found.' });
    }

    logger.trace(`Material with ID: ${id}:`, material);

    try {
      const updateData = req.body;

      const result = await materialModel.updateOne({ _id: id }, { $set: updateData });
      if (result.nModified === 0) {
        logger.error('No Material updated.');
        res.status(500).send({ error: 'No materials updated.' });
      }
    } catch (updateError) {
      logger.error('Error updating material:', updateError);
      res.status(500).send({ error: updateError.message });
    }
    res.send('OK');
  } catch (fetchError) {
    logger.error('Error fetching material:', fetchError);
    res.status(500).send({ error: fetchError.message });
  }
};

export const newMaterialRouteHandler = async (req, res) => {
  try {
    let { ...newMaterial } = req.body;
    newMaterial = {
      ...newMaterial,
      createdAt: new Date(),
      updatedAt: new Date(),
    };

    const result = await materialModel.create(newMaterial);
    if (result.nCreated === 0) {
      logger.error('No material created.');
      res.status(500).send({ error: 'No material created.' });
    }
    res.status(200).send({ status: 'ok' });
  } catch (updateError) {
    logger.error('Error updating material:', updateError);
    res.status(500).send({ error: updateError.message });
  }
};

export const getMaterialStatsRouteHandler = async (req, res) => {
  const result = await getModelStats({ model: materialModel });
  if (result?.error) {
    logger.error('Error fetching material stats:', result.error);
    return res.status(result.code).send(result);
  }
  logger.trace('Material stats:', result);
  res.send(result);
};

export const getMaterialHistoryRouteHandler = async (req, res) => {
  const from = req.query.from;
  const to = req.query.to;
  const result = await getModelHistory({ model: materialModel, from, to });
  if (result?.error) {
    logger.error('Error fetching material history:', result.error);
    return res.status(result.code).send(result);
  }
  logger.trace('Material history:', result);
  res.send(result);
};
