const db = require('../db/models');
const LeadsDBApi = require('../db/api/leads');
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 LeadsService {
  static async create(data, currentUser) {
    const transaction = await db.sequelize.transaction();
    try {
      const lead = await LeadsDBApi.create(
        data,
        {
          currentUser,
          transaction,
        },
      );

      // If businessId is provided, create a LeadMatch immediately
      if (data.businessId) {
        await db.lead_matches.create({
            leadId: lead.id,
            businessId: data.businessId,
            match_score: 100, // Direct request is 100% match
            status: 'SENT',
            sent_at: new Date()
        }, { transaction });
      }

      await transaction.commit();
      return lead;
    } 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 LeadsDBApi.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 leads = await LeadsDBApi.findBy({id}, {transaction});
      if (!leads) { throw new ValidationError('leadsNotFound'); }

      // Ownership check for Verified Business Owner
      if (currentUser.app_role?.name === 'Verified Business Owner') {
          const match = await db.lead_matches.findOne({ 
              where: { leadId: id, businessId: currentUser.businessId },
              transaction 
          });
          if (!match) {
              throw new ForbiddenError('forbidden');
          }
      }

      const updatedLeads = await LeadsDBApi.update(id, data, { currentUser, transaction });
      await transaction.commit();
      return updatedLeads;
    } 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 count = await db.lead_matches.count({ 
              where: { 
                  leadId: { [db.Sequelize.Op.in]: ids }, 
                  businessId: currentUser.businessId 
              },
              transaction 
          });
          if (count !== ids.length) {
              throw new ForbiddenError('forbidden');
          }
      }

      await LeadsDBApi.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 {
      // Ownership check for Verified Business Owner
      if (currentUser.app_role?.name === 'Verified Business Owner') {
          const match = await db.lead_matches.findOne({ 
              where: { leadId: id, businessId: currentUser.businessId },
              transaction 
          });
          if (!match) {
              throw new ForbiddenError('forbidden');
          }
      }

      await LeadsDBApi.remove(id, { currentUser, transaction });
      await transaction.commit();
    } catch (error) {
      await transaction.rollback();
      throw error;
    }
  }
};
