const db = require('../db/models');
const MessagesDBApi = require('../db/api/messages');
const processFile = require("../middlewares/upload");
const ValidationError = require('./notifications/errors/validation');
const ForbiddenError = require('./notifications/errors/forbidden');
const csv = require('csv-parser');
const axios = require('axios');
const config = require('../config');
const stream = require('stream');

module.exports = class MessagesService {
  static async create(data, currentUser) {
    const transaction = await db.sequelize.transaction();
    try {
      // For VBOs, ensure they can only message about their leads/businesses
      if (currentUser.app_role?.name === 'Verified Business Owner') {
          // If leadId is provided, check if business is matched to that lead
          if (data.lead) {
              const match = await db.lead_matches.findOne({
                  where: { 
                      leadId: data.lead,
                      [db.Sequelize.Op.or]: [
                          { businessId: currentUser.businessId || null },
                          { '$business.owner_userId$': currentUser.id }
                      ]
                  },
                  include: [{ model: db.businesses, as: 'business' }],
                  transaction
              });
              if (!match) {
                  throw new ForbiddenError('forbidden');
              }
          }
      }

      const message = await MessagesDBApi.create(
        data,
        {
          currentUser,
          transaction,
        },
      );

      await transaction.commit();
      return message;
    } catch (error) {
      await transaction.rollback();
      throw error;
    }
  };

  static async bulkImport(req, res, sendInvitationEmails = true, host) {
    const transaction = await db.sequelize.transaction();

    try {
      await processFile(req, res);
      const bufferStream = new stream.PassThrough();
      const results = [];

      await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); 

      await new Promise((resolve, reject) => {
        bufferStream
          .pipe(csv())
          .on('data', (data) => results.push(data))
          .on('end', async () => {
            resolve();
          })
          .on('error', (error) => reject(error));
      })

      await MessagesDBApi.bulkImport(results, {
          transaction,
          ignoreDuplicates: true,
          validate: true,
          currentUser: req.currentUser
      });

      await transaction.commit();
    } catch (error) {
      await transaction.rollback();
      throw error;
    }
  }

  static async update(data, id, currentUser) {
    const transaction = await db.sequelize.transaction();
    try {
      let message = await MessagesDBApi.findBy(
        {id},
        {transaction},
      );

      if (!message) {
        throw new ValidationError(
          'messagesNotFound',
        );
      }

      // Ownership check for Verified Business Owner
      if (currentUser.app_role?.name === 'Verified Business Owner') {
          if (message.sender_userId !== currentUser.id && message.receiver_userId !== currentUser.id) {
              // Also check if it's about their lead
              const match = await db.lead_matches.findOne({
                  where: { 
                      leadId: message.lead?.id,
                      [db.Sequelize.Op.or]: [
                          { businessId: currentUser.businessId || null },
                          { '$business.owner_userId$': currentUser.id }
                      ]
                  },
                  include: [{ model: db.businesses, as: 'business' }],
                  transaction
              });
              if (!match) {
                  throw new ForbiddenError('forbidden');
              }
          }
      }

      const updatedMessages = await MessagesDBApi.update(
        id,
        data,
        {
          currentUser,
          transaction,
        },
      );

      await transaction.commit();
      return updatedMessages;

    } catch (error) {
      await transaction.rollback();
      throw error;
    }
  };

  static async deleteByIds(ids, currentUser) {
    const transaction = await db.sequelize.transaction();

    try {
        // Ownership check for Verified Business Owner
        if (currentUser.app_role?.name === 'Verified Business Owner') {
            const records = await db.messages.findAll({ 
                where: { id: { [db.Sequelize.Op.in]: ids } },
                transaction 
            });
            for (const record of records) {
                if (record.sender_userId !== currentUser.id && record.receiver_userId !== currentUser.id) {
                    throw new ForbiddenError('forbidden');
                }
            }
        }

      await MessagesDBApi.deleteByIds(ids, {
        currentUser,
        transaction,
      });

      await transaction.commit();
    } catch (error) {
      await transaction.rollback();
      throw error;
    }
  }

  static async remove(id, currentUser) {
    const transaction = await db.sequelize.transaction();

    try {
      const record = await db.messages.findByPk(id, { transaction });
      if (!record) throw new ValidationError('messagesNotFound');

      if (currentUser.app_role?.name === 'Verified Business Owner') {
          if (record.sender_userId !== currentUser.id && record.receiver_userId !== currentUser.id) {
              throw new ForbiddenError('forbidden');
          }
      }

      await MessagesDBApi.remove(
        id,
        {
          currentUser,
          transaction,
        },
      );

      await transaction.commit();
    } catch (error) {
      await transaction.rollback();
      throw error;
    }
  }

  
};