const _ = require('lodash');
require('dotenv').config();

module.exports = {
  friendlyName: 'Create Multiple Utilisateurs',
  description: 'Create multiple Utilisateurs records in bulk, with a detailed response format.',

  inputs: {
    listeElementAjout: {
      type: 'ref',
      required: true,
      custom: (value) => Array.isArray(value) && value.length > 0
    },
    logiUsername: {
      type: 'string',
      required: true
    },
    key: {
      type: 'string',
      required: true
    },
    logiPassword: {
      type: 'string',
      required: true
    },
  },

  exits: {
    notFound: {
      description: 'The user or security token was not found or is invalid.',
      statusCode: 404
    },
    invalidInput: {
      description: 'Some provided items are missing required fields or the input is not a valid array.',
      statusCode: 400
    },
    serverError: {
      description: 'An unexpected server error occurred.',
      statusCode: 500
    },
    success: {
      description: 'The batch creation process was completed.',
      statusCode: 200
    }
  },

  fn: async function (inputs, exits) {
    const successes = [];
    const failures = [];
    const existings = [];
    const now = Date.now();

    try {
      // 1. Authentication & Authorization
      const user = await Utilisateurs.findOne({
        login: inputs.logiUsername,
        codeUser: inputs.logiPassword
      });

      if (!user) {
        return exits.notFound({
          message: 'Utilisateur non trouvé ou informations d\'identification non valides.'
        });
      }

      const keyVerify = process.env.KEYVERIFY;
      if (inputs.key !== keyVerify) {
        return exits.notFound({
          message: "Token non valide"
        });
      }

      // 2. Input Validation (ensure listeElementAjout is an array and not empty)
      if (!Array.isArray(inputs.listeElementAjout) || inputs.listeElementAjout.length === 0) {
        return exits.invalidInput({
          message: 'La liste des éléments à ajouter est vide ou invalide.',
        });
      }

      // Define required fields for each item in listeElementAjout
      const requiredFields = ['login', 'codeEcole', 'codeUser', 'nom', 'typeUser'];
      const invalidItems = inputs.listeElementAjout.filter(item =>
        !requiredFields.every(field => field in item)
      );

      if (invalidItems.length > 0) {
        return exits.invalidInput({
          message: 'Certains éléments de la liste manquent de champs requis.',
          invalidItems: invalidItems.map(item => _.pick(item, requiredFields))
        });
      }

      // 3. Deduplication and Existing Records Check
      // We'll use a unique key based on the fields that are likely to have uniqueness constraints.
      // Assuming 'login', 'codeEcole', and 'codeUser' form a unique identifier for an Utilisateur.
      const uniqueItems = [];
      const seenKeys = new Set();

      for (const item of inputs.listeElementAjout) {
        const itemKey = `${item.login}-${item.codeEcole}-${item.codeUser}`;
        if (!seenKeys.has(itemKey)) {
          seenKeys.add(itemKey);
          uniqueItems.push(item);
        }
      }

      // Find existing records in one go based on the unique items identified
      const existingRecordsFromDB = await Utilisateurs.find({
        or: uniqueItems.map(item => ({
          login: item.login,
          codeEcole: item.codeEcole,
          codeUser: item.codeUser
        }))
      });

      const existingRecordsMap = _.keyBy(existingRecordsFromDB, record =>
        `${record.login}-${record.codeEcole}-${record.codeUser}`
      );

      const recordsToCreate = [];
      for (const item of uniqueItems) {
        const itemKey = `${item.login}-${item.codeEcole}-${item.codeUser}`;
        if (existingRecordsMap[itemKey]) {
          existings.push(existingRecordsMap[itemKey]);
        } else {
          recordsToCreate.push(item);
        }
      }

      // 4. Bulk Insert with Transaction and Error Handling for each item
      if (recordsToCreate.length > 0) {
        try {
          await sails.getDatastore().transaction(async (db) => {
            for (const record of recordsToCreate) {
              try {
                const createdRecord = await Utilisateurs.create(record)
                  .usingConnection(db)
                  .fetch();
                successes.push(createdRecord);
              } catch (individualCreateError) {
                // Log the individual error but don't rethrow to allow transaction to continue
                sails.log.warn(`Failed to create Utilisateur for key ${record.login}-${record.codeEcole}-${record.codeUser}: ${individualCreateError.message}`);
                failures.push({
                  item: record, // Include the original item that failed
                  message: individualCreateError.message || 'Erreur inconnue lors de la création.',
                  type: 'creation_failed'
                });
                // If a unique constraint is hit here, it means our pre-check missed something
                // or there's a race condition. Mark as failure.
              }
            }
          });
        } catch (transactionError) {
          // This catch block would only be hit if the transaction itself failed to start/commit,
          // not for individual record insertion failures caught above.
          sails.log.error('Transaction failed for creating Utilisateurs:', transactionError);
          // Add all remaining recordsToCreate to failures if transaction aborted.
          recordsToCreate.forEach(item => {
            if (!successes.some(s => s.login === item.login && s.codeEcole === item.codeEcole && s.codeUser === item.codeUser) &&
                !failures.some(f => f.item.login === item.login && f.item.codeEcole === item.codeEcole && f.item.codeUser === item.codeUser)) {
              failures.push({
                item: item,
                message: `Transaction annulée : ${transactionError.message || 'Erreur inconnue.'}`,
                type: 'transaction_aborted'
              });
            }
          });
        }
      }

      // 5. Determine overall status and prepare response
      let overallStatus = 'success';
      let message = 'Le traitement par lot des utilisateurs est terminé.';

      if (failures.length > 0 && successes.length === 0 && existings.length === 0) {
        overallStatus = 'failure';
        message = 'Le traitement par lot des utilisateurs a échoué pour tous les éléments fournis.';
      } else if (inputs.listeElementAjout.length === 0) {
        message = 'Aucun utilisateur fourni pour le traitement.';
      } else if (successes.length > 0 || existings.length > 0) {
        overallStatus = failures.length > 0 ? 'partial_success' : 'success';
        if (overallStatus === 'success') {
          message = 'Tous les nouveaux utilisateurs ont été ajoutés avec succès.';
        } else {
          message = 'Le traitement est terminé avec des succès, des échecs et/ou des éléments existants.';
        }
      }

      // 6. Return response
      return exits.success({
        status: overallStatus,
        message: message,
        successes: successes.map(s => _.pick(s, ['login', 'codeEcole', 'codeUser', 'nom', 'typeUser', 'id'])),
        failures: failures,
        existings: existings.map(e => _.pick(e, ['login', 'codeEcole', 'codeUser', 'nom', 'typeUser', 'id'])),
        stats: {
          received: inputs.listeElementAjout.length,
          processedUnique: uniqueItems.length,
          alreadyExisting: existings.length,
          inserted: successes.length,
          failedToInsert: failures.length
        },
        createdAt: now,
      });

    } catch (err) {
      sails.log.error('Error processing batch Utilisateur creation:', err);
      return exits.serverError({
        status: 'error',
        message: 'Une erreur interne du serveur est survenue lors du traitement par lot des utilisateurs.',
        error: err.message,
        createdAt: now,
      });
    }
  }
};